/** * Sets the transaction lock time. * * @param transaction the transaction * @param locktime the locktime * @return the transaction */ public static Transaction setTransactionLockTime (Transaction transaction, int locktime) { transaction.setLockTime(locktime); for (TransactionInput input : transaction.getInputs()) { input.setSequenceNumber(0); } return transaction; }
@Test public void testToStringWhenLockTimeIsSpecifiedInBlockHeight() { Transaction tx = FakeTxBuilder.createFakeTx(PARAMS); TransactionInput input = tx.getInput(0); input.setSequenceNumber(42); int TEST_LOCK_TIME = 20; tx.setLockTime(TEST_LOCK_TIME); Calendar cal = Calendar.getInstance(); cal.set(2085, 10, 4, 17, 53, 21); cal.set(Calendar.MILLISECOND, 0); BlockChain mockBlockChain = createMock(BlockChain.class); EasyMock.expect(mockBlockChain.estimateBlockTime(TEST_LOCK_TIME)).andReturn(cal.getTime()); replay(mockBlockChain); String str = tx.toString(mockBlockChain); assertEquals(str.contains("block " + TEST_LOCK_TIME), true); assertEquals(str.contains("estimated to be reached at"), true); }
@Test public void optInFullRBF() { // a standard transaction as wallets would create Transaction tx = FakeTxBuilder.createFakeTx(PARAMS); assertFalse(tx.isOptInFullRBF()); tx.getInputs().get(0).setSequenceNumber(TransactionInput.NO_SEQUENCE - 2); assertTrue(tx.isOptInFullRBF()); }
assertTrue(transaction.isCached()); transaction.getInputs().get(0).setSequenceNumber(1); assertTrue(transaction.isCached()); transaction.getInputs().get(0).setSequenceNumber(transaction.getInputs().get(0).getSequenceNumber());
@Test public void optInFullRBF() throws Exception { Transaction tx = FakeTxBuilder.createFakeTx(PARAMS); tx.getInput(0).setSequenceNumber(TransactionInput.NO_SEQUENCE - 2); DefaultRiskAnalysis analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx, NO_DEPS); assertEquals(RiskAnalysis.Result.NON_FINAL, analysis.analyze()); assertEquals(tx, analysis.getNonFinal()); } }
private void addOnlyInputToTransaction(Transaction t, TransactionOutPointWithValue prevOut, long sequence) throws ScriptException { TransactionInput input = new TransactionInput(params, t, new byte[]{}, prevOut.outpoint); input.setSequenceNumber(sequence); t.addInput(input); if (prevOut.scriptPubKey.getChunks().get(0).equalsOpCode(OP_TRUE)) { input.setScriptSig(new ScriptBuilder().op(OP_1).build()); } else { // Sign input checkState(prevOut.scriptPubKey.isSentToRawPubKey()); Sha256Hash hash = t.hashForSignature(0, prevOut.scriptPubKey, SigHash.ALL, false); input.setScriptSig(ScriptBuilder.createInputScript( new TransactionSignature(coinbaseOutKey.sign(hash), SigHash.ALL, false)) ); } }
@Test public void testSequenceNumber() throws Exception { Wallet wallet = new Wallet(PARAMS); Transaction tx1 = createFakeTx(PARAMS, Coin.COIN, wallet.currentReceiveAddress()); tx1.getInput(0).setSequenceNumber(TransactionInput.NO_SEQUENCE); wallet.receivePending(tx1, null); Transaction tx2 = createFakeTx(PARAMS, Coin.COIN, wallet.currentReceiveAddress()); tx2.getInput(0).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1); wallet.receivePending(tx2, null); Wallet walletCopy = roundTrip(wallet); Transaction tx1copy = checkNotNull(walletCopy.getTransaction(tx1.getHash())); assertEquals(TransactionInput.NO_SEQUENCE, tx1copy.getInput(0).getSequenceNumber()); Transaction tx2copy = checkNotNull(walletCopy.getTransaction(tx2.getHash())); assertEquals(TransactionInput.NO_SEQUENCE - 1, tx2copy.getInput(0).getSequenceNumber()); }
@Test public void nonFinalDependency() { // Final tx has a dependency that is non-final. Transaction tx1 = new Transaction(PARAMS); tx1.addInput(PARAMS.getGenesisBlock().getTransactions().get(0).getOutput(0)).setSequenceNumber(1); TransactionOutput output = tx1.addOutput(COIN, key1); tx1.setLockTime(TIMESTAMP + 86400); Transaction tx2 = new Transaction(PARAMS); tx2.addInput(output); tx2.addOutput(COIN, new ECKey()); DefaultRiskAnalysis analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx2, ImmutableList.of(tx1)); assertEquals(RiskAnalysis.Result.NON_FINAL, analysis.analyze()); assertEquals(tx1, analysis.getNonFinal()); }
refundTx.addInput(multisigOutput).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L); refundTx.setLockTime(expiryTime); if (Context.get().isEnsureMinRequiredFee()) {
refundTx.addInput(multisigOutput).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L); refundTx.setLockTime(expiryTime); if (Context.get().isEnsureMinRequiredFee()) {
@Test public void testCLTVPaymentChannelTransactionRefund() { BigInteger time = BigInteger.valueOf(20); ECKey from = new ECKey(), to = new ECKey(), incorrect = new ECKey(); Script outputScript = ScriptBuilder.createCLTVPaymentChannelOutput(time, from, to); Transaction tx = new Transaction(PARAMS); tx.addInput(new TransactionInput(PARAMS, tx, new byte[] {})); tx.getInput(0).setSequenceNumber(0); tx.setLockTime(time.add(BigInteger.ONE).longValue()); TransactionSignature fromSig = tx.calculateSignature(0, from, outputScript, Transaction.SigHash.SINGLE, false); TransactionSignature incorrectSig = tx.calculateSignature(0, incorrect, outputScript, Transaction.SigHash.SINGLE, false); Script scriptSig = ScriptBuilder.createCLTVPaymentChannelRefund(fromSig); Script invalidScriptSig = ScriptBuilder.createCLTVPaymentChannelRefund(incorrectSig); try { scriptSig.correctlySpends(tx, 0, outputScript, Script.ALL_VERIFY_FLAGS); } catch (ScriptException e) { e.printStackTrace(); fail("Refund failed to correctly spend the payment channel"); } try { invalidScriptSig.correctlySpends(tx, 0, outputScript, Script.ALL_VERIFY_FLAGS); fail("Invalid sig passed"); } catch (ScriptException e) { } }
@Test public void testCategory2WithChange() throws Exception { // Specifically target case 2 with significant change // Generate a ton of small outputs StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, OTHER_ADDRESS), BigInteger.ONE, 1); int i = 0; while (i <= CENT.divide(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(10))) { Transaction tx = createFakeTxWithChangeAddress(PARAMS, Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(10), myAddress, OTHER_ADDRESS); tx.getInput(0).setSequenceNumber(i++); // Keep every transaction unique wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); } // The selector will choose 2 with MIN_TX_FEE fee SendRequest request1 = SendRequest.to(OTHER_ADDRESS, CENT.add(SATOSHI)); request1.ensureMinRequiredFee = true; wallet.completeTx(request1); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request1.tx.getFee()); assertEquals(request1.tx.getInputs().size(), i); // We should have spent all inputs assertEquals(2, request1.tx.getOutputs().size()); // and gotten change back }
refundTx.addInput(contract.getOutput(0)).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L); refundTx.setLockTime(expiryTime); if (Context.get().isEnsureMinRequiredFee()) {
refundTx.addInput(contract.getOutput(0)).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L); refundTx.setLockTime(expiryTime); if (Context.get().isEnsureMinRequiredFee()) {
refundTx.addInput(contract.getOutput(0)).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L); refundTx.setLockTime(expiryTime); if (Context.get().isEnsureMinRequiredFee()) {
@Test public void selfCreatedAreNotRisky() { Transaction tx = new Transaction(PARAMS); tx.addInput(PARAMS.getGenesisBlock().getTransactions().get(0).getOutput(0)).setSequenceNumber(1); tx.addOutput(COIN, key1); tx.setLockTime(TIMESTAMP + 86400); { // Is risky ... DefaultRiskAnalysis analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx, NO_DEPS); assertEquals(RiskAnalysis.Result.NON_FINAL, analysis.analyze()); } tx.getConfidence().setSource(TransactionConfidence.Source.SELF); { // Is no longer risky. DefaultRiskAnalysis analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx, NO_DEPS); assertEquals(RiskAnalysis.Result.OK, analysis.analyze()); } }
refundTx.addInput(contract.getOutput(0)).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L); refundTx.setLockTime(expiryTime); if (Context.get().isEnsureMinRequiredFee()) {
tx.getInput(0).setSequenceNumber(0); tx.setLockTime(time.subtract(BigInteger.ONE).longValue()); TransactionSignature fromSig =
@Test public void nonFinal() throws Exception { // Verify that just having a lock time in the future is not enough to be considered risky (it's still final). Transaction tx = new Transaction(PARAMS); TransactionInput input = tx.addInput(PARAMS.getGenesisBlock().getTransactions().get(0).getOutput(0)); tx.addOutput(COIN, key1); tx.setLockTime(TIMESTAMP + 86400); DefaultRiskAnalysis analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx, NO_DEPS); assertEquals(RiskAnalysis.Result.OK, analysis.analyze()); assertNull(analysis.getNonFinal()); // Set a sequence number on the input to make it genuinely non-final. Verify it's risky. input.setSequenceNumber(TransactionInput.NO_SEQUENCE - 1); analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx, NO_DEPS); assertEquals(RiskAnalysis.Result.NON_FINAL, analysis.analyze()); assertEquals(tx, analysis.getNonFinal()); // If the lock time is the current block, it's about to become final and we consider it non-risky. tx.setLockTime(1000); analysis = DefaultRiskAnalysis.FACTORY.create(wallet, tx, NO_DEPS); assertEquals(RiskAnalysis.Result.OK, analysis.analyze()); }
t2.getInput(0).setSequenceNumber(0xDEADBEEF); t2.addOutput(COIN, new ECKey()); Transaction t1 = new Transaction(PARAMS);