Java Code Examples for org.bitcoinj.protocols.channels.IPaymentChannelClient.ClientChannelProperties#modifyContractSendRequest()

The following examples show how to use org.bitcoinj.protocols.channels.IPaymentChannelClient.ClientChannelProperties#modifyContractSendRequest() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: PaymentChannelV2ClientState.java    From bcm-android with GNU General Public License v3.0 4 votes vote down vote up
@Override
public synchronized void initiate(@Nullable KeyParameter userKey, ClientChannelProperties clientChannelProperties) throws ValueOutOfRangeException, InsufficientMoneyException {
    final NetworkParameters params = wallet.getParams();
    Transaction template = new Transaction(params);
    // 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.
    Script redeemScript =
            ScriptBuilder.createCLTVPaymentChannelOutput(BigInteger.valueOf(expiryTime), myKey, serverKey);
    TransactionOutput transactionOutput = template.addOutput(totalValue,
            ScriptBuilder.createP2SHOutputScript(redeemScript));
    if (transactionOutput.isDust())
        throw new ValueOutOfRangeException("totalValue too small to use");
    SendRequest req = SendRequest.forTx(template);
    req.coinSelector = AllowUnconfirmedCoinSelector.get();
    req.shuffleOutputs = false;   // TODO: Fix things so shuffling is usable.
    req = clientChannelProperties.modifyContractSendRequest(req);
    if (userKey != null)
        req.aesKey = userKey;
    wallet.completeTx(req);
    Coin multisigFee = req.tx.getFee();
    contract = 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 because the
    // CheckLockTimeVerify opcode requires a lock time to be specified and the input to have a non-final sequence
    // number (so that the lock time is not disabled).
    refundTx = new Transaction(params);
    // by using this sequence value, we avoid extra full replace-by-fee and relative lock time processing.
    refundTx.addInput(contract.getOutput(0)).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L);
    refundTx.setLockTime(expiryTime);
    if (Context.get().isEnsureMinRequiredFee()) {
        // 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, LegacyAddress.fromKey(params, myKey));
        refundFees = multisigFee.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
    } else {
        refundTx.addOutput(totalValue, LegacyAddress.fromKey(params, myKey));
        refundFees = multisigFee;
    }

    TransactionSignature refundSignature =
            refundTx.calculateSignature(0, myKey.maybeDecrypt(userKey),
                    getSignedScript(), Transaction.SigHash.ALL, false);
    refundTx.getInput(0).setScriptSig(ScriptBuilder.createCLTVPaymentChannelP2SHRefund(refundSignature, redeemScript));

    refundTx.getConfidence().setSource(TransactionConfidence.Source.SELF);
    log.info("initiated channel with contract {}", contract.getHashAsString());
    stateMachine.transition(State.SAVE_STATE_IN_WALLET);
    // Client should now call getIncompleteRefundTransaction() and send it to the server.
}
 
Example 2
Source File: PaymentChannelV1ClientState.java    From bcm-android with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Creates the initial multisig contract and incomplete refund transaction which can be requested at the appropriate
 * time using {@link PaymentChannelV1ClientState#getIncompleteRefundTransaction} and
 * {@link PaymentChannelV1ClientState#getContract()}.
 * By default unconfirmed coins are allowed to be used, as for micropayments the risk should be relatively low.
 *
 * @param userKey                 Key derived from a user password, needed for any signing when the wallet is encrypted.
 *                                The wallet KeyCrypter is assumed.
 * @param clientChannelProperties Modify the channel's configuration.
 * @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
 */
@Override
public synchronized void initiate(@Nullable KeyParameter userKey, ClientChannelProperties clientChannelProperties) 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, serverKey);
    // 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.isDust())
        throw new ValueOutOfRangeException("totalValue too small to use");
    SendRequest req = SendRequest.forTx(template);
    req.coinSelector = AllowUnconfirmedCoinSelector.get();
    req.shuffleOutputs = false;   // TODO: Fix things so shuffling is usable.
    req = clientChannelProperties.modifyContractSendRequest(req);
    if (userKey != null)
        req.aesKey = userKey;
    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);
    // don't disable lock time. the sequence will be included in the server's signature and thus won't be changeable.
    // by using this sequence value, we avoid extra full replace-by-fee and relative lock time processing.
    refundTx.addInput(multisigOutput).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L);
    refundTx.setLockTime(expiryTime);
    if (Context.get().isEnsureMinRequiredFee()) {
        // 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, LegacyAddress.fromKey(params, myKey));
        refundFees = multisigFee.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
    } else {
        refundTx.addOutput(totalValue, LegacyAddress.fromKey(params, myKey));
        refundFees = multisigFee;
    }
    refundTx.getConfidence().setSource(TransactionConfidence.Source.SELF);
    log.info("initiated channel with multi-sig contract {}, refund {}", multisigContract.getHashAsString(),
            refundTx.getHashAsString());
    stateMachine.transition(State.INITIATED);
    // Client should now call getIncompleteRefundTransaction() and send it to the server.
}
 
Example 3
Source File: PaymentChannelV2ClientState.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
@Override
public synchronized void initiate(@Nullable KeyParameter userKey, ClientChannelProperties clientChannelProperties) throws ValueOutOfRangeException, InsufficientMoneyException {
    final NetworkParameters params = wallet.getParams();
    Transaction template = new Transaction(params);
    // 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.
    Script redeemScript =
            ScriptBuilder.createCLTVPaymentChannelOutput(BigInteger.valueOf(expiryTime), myKey, serverKey);
    TransactionOutput transactionOutput = template.addOutput(totalValue,
            ScriptBuilder.createP2SHOutputScript(redeemScript));
    if (transactionOutput.isDust())
        throw new ValueOutOfRangeException("totalValue too small to use");
    SendRequest req = SendRequest.forTx(template);
    req.coinSelector = AllowUnconfirmedCoinSelector.get();
    req.shuffleOutputs = false;   // TODO: Fix things so shuffling is usable.
    req = clientChannelProperties.modifyContractSendRequest(req);
    if (userKey != null) req.aesKey = userKey;
    wallet.completeTx(req);
    Coin multisigFee = req.tx.getFee();
    contract = 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 because the
    // CheckLockTimeVerify opcode requires a lock time to be specified and the input to have a non-final sequence
    // number (so that the lock time is not disabled).
    refundTx = new Transaction(params);
    // by using this sequence value, we avoid extra full replace-by-fee and relative lock time processing.
    refundTx.addInput(contract.getOutput(0)).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L);
    refundTx.setLockTime(expiryTime);
    if (Context.get().isEnsureMinRequiredFee()) {
        // 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;
    }

    TransactionSignature refundSignature =
            refundTx.calculateSignature(0, myKey.maybeDecrypt(userKey),
                    getSignedScript(), Transaction.SigHash.ALL, false);
    refundTx.getInput(0).setScriptSig(ScriptBuilder.createCLTVPaymentChannelP2SHRefund(refundSignature, redeemScript));

    refundTx.getConfidence().setSource(TransactionConfidence.Source.SELF);
    log.info("initiated channel with contract {}", contract.getHashAsString());
    stateMachine.transition(State.SAVE_STATE_IN_WALLET);
    // Client should now call getIncompleteRefundTransaction() and send it to the server.
}
 
Example 4
Source File: PaymentChannelV1ClientState.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Creates the initial multisig contract and incomplete refund transaction which can be requested at the appropriate
 * time using {@link PaymentChannelV1ClientState#getIncompleteRefundTransaction} and
 * {@link PaymentChannelV1ClientState#getContract()}.
 * By default unconfirmed coins are allowed to be used, as for micropayments the risk should be relatively low.
 * @param userKey Key derived from a user password, needed for any signing when the wallet is encrypted.
 *                The wallet KeyCrypter is assumed.
 * @param clientChannelProperties Modify the channel's configuration.
 *
 * @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
 */
@Override
public synchronized void initiate(@Nullable KeyParameter userKey, ClientChannelProperties clientChannelProperties) 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, serverKey);
    // 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.isDust())
        throw new ValueOutOfRangeException("totalValue too small to use");
    SendRequest req = SendRequest.forTx(template);
    req.coinSelector = AllowUnconfirmedCoinSelector.get();
    req.shuffleOutputs = false;   // TODO: Fix things so shuffling is usable.
    req = clientChannelProperties.modifyContractSendRequest(req);
    if (userKey != null) req.aesKey = userKey;
    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);
    // don't disable lock time. the sequence will be included in the server's signature and thus won't be changeable.
    // by using this sequence value, we avoid extra full replace-by-fee and relative lock time processing.
    refundTx.addInput(multisigOutput).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L);
    refundTx.setLockTime(expiryTime);
    if (Context.get().isEnsureMinRequiredFee()) {
        // 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());
    stateMachine.transition(State.INITIATED);
    // Client should now call getIncompleteRefundTransaction() and send it to the server.
}
 
Example 5
Source File: PaymentChannelV2ClientState.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
@Override
public synchronized void initiate(@Nullable KeyParameter userKey, ClientChannelProperties clientChannelProperties) throws ValueOutOfRangeException, InsufficientMoneyException {
    final NetworkParameters params = wallet.getParams();
    Transaction template = new Transaction(params);
    // 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.
    Script redeemScript =
            ScriptBuilder.createCLTVPaymentChannelOutput(BigInteger.valueOf(expiryTime), myKey, serverKey);
    TransactionOutput transactionOutput = template.addOutput(totalValue,
            ScriptBuilder.createP2SHOutputScript(redeemScript));
    if (transactionOutput.isDust())
        throw new ValueOutOfRangeException("totalValue too small to use");
    SendRequest req = SendRequest.forTx(template);
    req.coinSelector = AllowUnconfirmedCoinSelector.get();
    req.shuffleOutputs = false;   // TODO: Fix things so shuffling is usable.
    req = clientChannelProperties.modifyContractSendRequest(req);
    if (userKey != null) req.aesKey = userKey;
    wallet.completeTx(req);
    Coin multisigFee = req.tx.getFee();
    contract = 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 because the
    // CheckLockTimeVerify opcode requires a lock time to be specified and the input to have a non-final sequence
    // number (so that the lock time is not disabled).
    refundTx = new Transaction(params);
    // by using this sequence value, we avoid extra full replace-by-fee and relative lock time processing.
    refundTx.addInput(contract.getOutput(0)).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L);
    refundTx.setLockTime(expiryTime);
    if (Context.get().isEnsureMinRequiredFee()) {
        // 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;
    }

    TransactionSignature refundSignature =
            refundTx.calculateSignature(0, myKey.maybeDecrypt(userKey),
                    getSignedScript(), Transaction.SigHash.ALL, false);
    refundTx.getInput(0).setScriptSig(ScriptBuilder.createCLTVPaymentChannelP2SHRefund(refundSignature, redeemScript));

    refundTx.getConfidence().setSource(TransactionConfidence.Source.SELF);
    log.info("initiated channel with contract {}", contract.getHashAsString());
    stateMachine.transition(State.SAVE_STATE_IN_WALLET);
    // Client should now call getIncompleteRefundTransaction() and send it to the server.
}
 
Example 6
Source File: PaymentChannelV1ClientState.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Creates the initial multisig contract and incomplete refund transaction which can be requested at the appropriate
 * time using {@link PaymentChannelV1ClientState#getIncompleteRefundTransaction} and
 * {@link PaymentChannelV1ClientState#getContract()}.
 * By default unconfirmed coins are allowed to be used, as for micropayments the risk should be relatively low.
 * @param userKey Key derived from a user password, needed for any signing when the wallet is encrypted.
 *                The wallet KeyCrypter is assumed.
 * @param clientChannelProperties Modify the channel's configuration.
 *
 * @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
 */
@Override
public synchronized void initiate(@Nullable KeyParameter userKey, ClientChannelProperties clientChannelProperties) 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, serverKey);
    // 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.isDust())
        throw new ValueOutOfRangeException("totalValue too small to use");
    SendRequest req = SendRequest.forTx(template);
    req.coinSelector = AllowUnconfirmedCoinSelector.get();
    req.shuffleOutputs = false;   // TODO: Fix things so shuffling is usable.
    req = clientChannelProperties.modifyContractSendRequest(req);
    if (userKey != null) req.aesKey = userKey;
    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);
    // don't disable lock time. the sequence will be included in the server's signature and thus won't be changeable.
    // by using this sequence value, we avoid extra full replace-by-fee and relative lock time processing.
    refundTx.addInput(multisigOutput).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L);
    refundTx.setLockTime(expiryTime);
    if (Context.get().isEnsureMinRequiredFee()) {
        // 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());
    stateMachine.transition(State.INITIATED);
    // Client should now call getIncompleteRefundTransaction() and send it to the server.
}