/**
  * Creates the initial multisig contract and incomplete refund transaction which can be requested
  * at the appropriate time using {@link PaymentChannelClientState#getIncompleteRefundTransaction}
  * and {@link PaymentChannelClientState#getMultisigContract()}. The way the contract is crafted
  * can be adjusted by overriding {@link
  * PaymentChannelClientState#editContractSendRequest(com.google.bitcoin.core.Wallet.SendRequest)}.
  * By default unconfirmed coins are allowed to be used, as for micropayments the risk should be
  * relatively low.
  *
  * @throws ValueOutOfRangeException if the value being used is too small to be accepted by the
  *     network
  * @throws InsufficientMoneyException if the wallet doesn't contain enough balance to initiate
  */
 public synchronized void initiate() throws ValueOutOfRangeException, InsufficientMoneyException {
   final NetworkParameters params = wallet.getParams();
   Transaction template = new Transaction(params);
   // We always place the client key before the server key because, if either side wants some
   // privacy, they can
   // use a fresh key for the the multisig contract and nowhere else
   List<ECKey> keys = Lists.newArrayList(myKey, serverMultisigKey);
   // There is also probably a change output, but we don't bother shuffling them as it's obvious
   // from the
   // format which one is the change. If we start obfuscating the change output better in future
   // this may
   // be worth revisiting.
   TransactionOutput multisigOutput =
       template.addOutput(totalValue, ScriptBuilder.createMultiSigOutputScript(2, keys));
   if (multisigOutput.getMinNonDustValue().compareTo(totalValue) > 0)
     throw new ValueOutOfRangeException("totalValue too small to use");
   Wallet.SendRequest req = Wallet.SendRequest.forTx(template);
   req.coinSelector = AllowUnconfirmedCoinSelector.get();
   editContractSendRequest(req);
   req.shuffleOutputs = false; // TODO: Fix things so shuffling is usable.
   wallet.completeTx(req);
   Coin multisigFee = req.tx.getFee();
   multisigContract = req.tx;
   // Build a refund transaction that protects us in the case of a bad server that's just trying to
   // cause havoc
   // by locking up peoples money (perhaps as a precursor to a ransom attempt). We time lock it so
   // the server
   // has an assurance that we cannot take back our money by claiming a refund before the channel
   // closes - this
   // relies on the fact that since Bitcoin 0.8 time locked transactions are non-final. This will
   // need to change
   // in future as it breaks the intended design of timelocking/tx replacement, but for now it
   // simplifies this
   // specific protocol somewhat.
   refundTx = new Transaction(params);
   refundTx
       .addInput(multisigOutput)
       .setSequenceNumber(0); // Allow replacement when it's eventually reactivated.
   refundTx.setLockTime(expiryTime);
   if (totalValue.compareTo(Coin.CENT) < 0) {
     // Must pay min fee.
     final Coin valueAfterFee = totalValue.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
     if (Transaction.MIN_NONDUST_OUTPUT.compareTo(valueAfterFee) > 0)
       throw new ValueOutOfRangeException("totalValue too small to use");
     refundTx.addOutput(valueAfterFee, myKey.toAddress(params));
     refundFees = multisigFee.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
   } else {
     refundTx.addOutput(totalValue, myKey.toAddress(params));
     refundFees = multisigFee;
   }
   refundTx.getConfidence().setSource(TransactionConfidence.Source.SELF);
   log.info(
       "initiated channel with multi-sig contract {}, refund {}",
       multisigContract.getHashAsString(),
       refundTx.getHashAsString());
   state = State.INITIATED;
   // Client should now call getIncompleteRefundTransaction() and send it to the server.
 }
예제 #2
0
 public static List<String> getAddresses() {
   Blocks blocks = Blocks.getInstance();
   List<ECKey> keys = blocks.wallet.getKeys();
   List<String> addresses = new ArrayList<String>();
   for (ECKey key : keys) {
     addresses.add(key.toAddress(blocks.params).toString());
   }
   return addresses;
 }
 private synchronized Transaction makeUnsignedChannelContract(Coin valueToMe)
     throws ValueOutOfRangeException {
   Transaction tx = new Transaction(wallet.getParams());
   tx.addInput(multisigContract.getOutput(0));
   // Our output always comes first.
   // TODO: We should drop myKey in favor of output key + multisig key separation
   // (as its always obvious who the client is based on T2 output order)
   tx.addOutput(valueToMe, myKey.toAddress(wallet.getParams()));
   return tx;
 }
 @Override
 public void showKey(ECKey key, String dir, boolean testnet) throws IOException {
   NetworkParameters params = LotteryTx.getNetworkParameters(testnet);
   writeln("Generated new <public key, secret key> pair" + (testnet ? " (for the testnet)" : ""));
   writeln("They were saved under the " + dir + " directory");
   writeln("The address, public key and the private key are:");
   writeln(key.toAddress(params).toString());
   writeln(Utils.bytesToHexString(key.getPubKey()));
   writeln(key.getPrivateKeyEncoded(params).toString());
 }
  private byte[] determinePaymentRequest(final boolean includeBluetoothMac) {
    final ECKey key = (ECKey) addressView.getSelectedItem();
    final Address address = key.toAddress(Constants.NETWORK_PARAMETERS);

    return PaymentProtocol.createPaymentRequest(
            amountCalculatorLink.getAmount(),
            address,
            null,
            includeBluetoothMac && bluetoothMac != null ? "bt:" + bluetoothMac : null)
        .toByteArray();
  }
예제 #6
0
  public void sweepKey(ECKey key, long fee, int accountId, JSONArray outputs) {
    mLogger.info("sweepKey starting");

    mLogger.info("key addr " + key.toAddress(mParams).toString());

    Transaction tx = new Transaction(mParams);

    long balance = 0;
    ArrayList<Script> scripts = new ArrayList<Script>();
    try {
      for (int ii = 0; ii < outputs.length(); ++ii) {
        JSONObject output;
        output = outputs.getJSONObject(ii);

        String tx_hash = output.getString("tx_hash");
        int tx_output_n = output.getInt("tx_output_n");
        String script = output.getString("script");

        // Reverse byte order, create hash.
        Sha256Hash hash = new Sha256Hash(WalletUtil.msgHexToBytes(tx_hash));

        tx.addInput(
            new TransactionInput(
                mParams, tx, new byte[] {}, new TransactionOutPoint(mParams, tx_output_n, hash)));

        scripts.add(new Script(Hex.decode(script)));

        balance += output.getLong("value");
      }
    } catch (JSONException e) {
      e.printStackTrace();
      throw new RuntimeException("trouble parsing unspent outputs");
    }

    // Compute balance - fee.
    long amount = balance - fee;
    mLogger.info(String.format("sweeping %d", amount));

    // Figure out the destination address.
    Address to = mHDWallet.nextReceiveAddress(accountId);
    mLogger.info("sweeping to " + to.toString());

    // Add output.
    tx.addOutput(BigInteger.valueOf(amount), to);

    WalletUtil.signTransactionInputs(tx, Transaction.SigHash.ALL, key, scripts);

    mLogger.info("tx bytes: " + new String(Hex.encode(tx.bitcoinSerialize())));
    // mKit.peerGroup().broadcastTransaction(tx);
    broadcastTransaction(mKit.peerGroup(), tx);

    mLogger.info("sweepKey finished");
  }
  private String determineBitcoinRequestStr(final boolean includeBluetoothMac) {
    final ECKey key = (ECKey) addressView.getSelectedItem();
    final Address address = key.toAddress(Constants.NETWORK_PARAMETERS);
    final BigInteger amount = amountCalculatorLink.getAmount();

    final StringBuilder uri =
        new StringBuilder(BitcoinURI.convertToBitcoinURI(address, amount, null, null));
    if (includeBluetoothMac && bluetoothMac != null) {
      uri.append(amount == null ? '?' : '&');
      uri.append(Bluetooth.MAC_URI_PARAM).append('=').append(bluetoothMac);
    }
    return uri.toString();
  }
예제 #8
0
  public Address determineSelectedAddress() {
    final String selectedAddress = prefs.getString(Constants.PREFS_KEY_SELECTED_ADDRESS, null);

    Address firstAddress = null;
    for (final ECKey key : wallet.getKeys()) {
      if (!wallet.isKeyRotating(key)) {
        final Address address = key.toAddress(Constants.NETWORK_PARAMETERS);

        if (address.toString().equals(selectedAddress)) return address;

        if (firstAddress == null) firstAddress = address;
      }
    }

    return firstAddress;
  }
  public void setUp(BlockStore blockStore) throws Exception {
    BriefLogFormatter.init();

    unitTestParams = UnitTestParams.get();
    Wallet.SendRequest.DEFAULT_FEE_PER_KB = BigInteger.ZERO;
    this.blockStore = blockStore;
    wallet = new Wallet(unitTestParams);
    key = new ECKey();
    address = key.toAddress(unitTestParams);
    wallet.addKey(key);
    blockChain = new BlockChain(unitTestParams, wallet, blockStore);

    startPeerServers();
    if (clientType == ClientType.NIO_CLIENT_MANAGER
        || clientType == ClientType.BLOCKING_CLIENT_MANAGER) {
      channels.startAsync();
      channels.awaitRunning();
    }

    socketAddress = new InetSocketAddress("127.0.0.1", 1111);
  }