@Test public void oneTx() throws Exception { // Check basic tx serialization. Coin v1 = COIN; Transaction t1 = createFakeTx(params, v1, myAddress); t1.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("1.2.3.4"))); t1.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("5.6.7.8"))); t1.getConfidence().setSource(TransactionConfidence.Source.NETWORK); myWallet.receivePending(t1, null); Wallet wallet1 = roundTrip(myWallet); assertEquals(1, wallet1.getTransactions(true).size()); assertEquals(v1, wallet1.getBalance(Wallet.BalanceType.ESTIMATED)); Transaction t1copy = wallet1.getTransaction(t1.getHash()); assertArrayEquals(t1.bitcoinSerialize(), t1copy.bitcoinSerialize()); assertEquals(2, t1copy.getConfidence().numBroadcastPeers()); assertEquals(TransactionConfidence.Source.NETWORK, t1copy.getConfidence().getSource()); Protos.Wallet walletProto = new WalletProtobufSerializer().walletToProto(myWallet); assertEquals(Protos.Key.Type.ORIGINAL, walletProto.getKey(0).getType()); assertEquals(0, walletProto.getExtensionCount()); assertEquals(1, walletProto.getTransactionCount()); assertEquals(6, walletProto.getKeyCount()); Protos.Transaction t1p = walletProto.getTransaction(0); assertEquals(0, t1p.getBlockHashCount()); assertArrayEquals(t1.getHash().getBytes(), t1p.getHash().toByteArray()); assertEquals(Protos.Transaction.Pool.PENDING, t1p.getPool()); assertFalse(t1p.hasLockTime()); assertFalse(t1p.getTransactionInput(0).hasSequence()); assertArrayEquals( t1.getInputs().get(0).getOutpoint().getHash().getBytes(), t1p.getTransactionInput(0).getTransactionOutPointHash().toByteArray()); assertEquals(0, t1p.getTransactionInput(0).getTransactionOutPointIndex()); assertEquals(t1p.getTransactionOutput(0).getValue(), v1.value); }
@Before public void setUp() throws Exception { unitTestParams = UnitTestParams.get(); wallet = new Wallet(unitTestParams); wallet.addKey(new ECKey()); resetBlockStore(); Transaction tx1 = createFakeTx( unitTestParams, Utils.toNanoCoins(2, 0), wallet.getKeys().get(0).toAddress(unitTestParams)); // add a second input so can test granularity of byte cache. Transaction prevTx = new Transaction(unitTestParams); TransactionOutput prevOut = new TransactionOutput( unitTestParams, prevTx, Utils.toNanoCoins(1, 0), wallet.getKeys().get(0).toAddress(unitTestParams)); prevTx.addOutput(prevOut); // Connect it. tx1.addInput(prevOut); Transaction tx2 = createFakeTx( unitTestParams, Utils.toNanoCoins(1, 0), new ECKey().toAddress(unitTestParams)); Block b1 = createFakeBlock(blockStore, tx1, tx2).block; BitcoinSerializer bs = new BitcoinSerializer(unitTestParams); ByteArrayOutputStream bos = new ByteArrayOutputStream(); bs.serialize(tx1, bos); tx1BytesWithHeader = bos.toByteArray(); tx1Bytes = tx1.bitcoinSerialize(); bos.reset(); bs.serialize(tx2, bos); tx2BytesWithHeader = bos.toByteArray(); tx2Bytes = tx2.bitcoinSerialize(); bos.reset(); bs.serialize(b1, bos); b1BytesWithHeader = bos.toByteArray(); b1Bytes = b1.bitcoinSerialize(); }
private static void sendTransactionsToListener( StoredBlock block, NewBlockType blockType, BlockChainListener listener, int relativityOffset, List<Transaction> transactions, boolean clone, Set<Sha256Hash> falsePositives) throws VerificationException { for (Transaction tx : transactions) { try { if (listener.isTransactionRelevant(tx)) { falsePositives.remove(tx.getHash()); if (clone) tx = new Transaction(tx.params, tx.bitcoinSerialize()); listener.receiveFromBlock(tx, block, blockType, relativityOffset++); } } catch (ScriptException e) { // We don't want scripts we don't understand to break the block chain so just note that this // tx was // not scanned here and continue. log.warn("Failed to parse a script: " + e.toString()); } catch (ProtocolException e) { // Failed to duplicate tx, should never happen. throw new RuntimeException(e); } } }
@Before public void setup() throws Exception { BriefLogFormatter.init(); tx1 = TestUtils.createFakeTx(params, Utils.toNanoCoins(1, 0), new ECKey().toAddress(params)); tx2 = new Transaction(params, tx1.bitcoinSerialize()); address1 = new PeerAddress(InetAddress.getByAddress(new byte[] {127, 0, 0, 1})); address2 = new PeerAddress(InetAddress.getByAddress(new byte[] {127, 0, 0, 2})); address3 = new PeerAddress(InetAddress.getByAddress(new byte[] {127, 0, 0, 3})); }
@Test public void testUpdateLength() { NetworkParameters params = UnitTestParams.get(); Block block = params .getGenesisBlock() .createNextBlockWithCoinbase( Block.BLOCK_VERSION_GENESIS, new ECKey().getPubKey(), Block.BLOCK_HEIGHT_GENESIS); assertEquals(block.bitcoinSerialize().length, block.length); final int origBlockLen = block.length; Transaction tx = new Transaction(params); // this is broken until the transaction has > 1 input + output (which is required anyway...) // assertTrue(tx.length == tx.bitcoinSerialize().length && tx.length == 8); byte[] outputScript = new byte[10]; Arrays.fill(outputScript, (byte) ScriptOpCodes.OP_FALSE); tx.addOutput(new TransactionOutput(params, null, Coin.SATOSHI, outputScript)); tx.addInput( new TransactionInput( params, null, new byte[] {(byte) ScriptOpCodes.OP_FALSE}, new TransactionOutPoint(params, 0, Sha256Hash.of(new byte[] {1})))); int origTxLength = 8 + 2 + 8 + 1 + 10 + 40 + 1 + 1; assertEquals(tx.bitcoinSerialize().length, tx.length); assertEquals(origTxLength, tx.length); block.addTransaction(tx); assertEquals(block.bitcoinSerialize().length, block.length); assertEquals(origBlockLen + tx.length, block.length); block .getTransactions() .get(1) .getInputs() .get(0) .setScriptBytes(new byte[] {(byte) ScriptOpCodes.OP_FALSE, (byte) ScriptOpCodes.OP_FALSE}); assertEquals(block.length, origBlockLen + tx.length); assertEquals(tx.length, origTxLength + 1); block.getTransactions().get(1).getInputs().get(0).setScriptBytes(new byte[] {}); assertEquals(block.length, block.bitcoinSerialize().length); assertEquals(block.length, origBlockLen + tx.length); assertEquals(tx.length, origTxLength - 1); block .getTransactions() .get(1) .addInput( new TransactionInput( params, null, new byte[] {(byte) ScriptOpCodes.OP_FALSE}, new TransactionOutPoint(params, 0, Sha256Hash.of(new byte[] {1})))); assertEquals(block.length, origBlockLen + tx.length); assertEquals(tx.length, origTxLength + 41); // - 1 + 40 + 1 + 1 }
/** * Generates a Payment message based on the information in the PaymentRequest. Provide * transactions built by the wallet. If the PaymentRequest did not specify a payment_url, returns * null. * * @param txns list of transactions to be included with the Payment message. * @param refundAddr will be used by the merchant to send money back if there was a problem. * @param memo is a message to include in the payment message sent to the merchant. */ public @Nullable Protos.Payment getPayment( List<Transaction> txns, @Nullable Address refundAddr, @Nullable String memo) throws IOException { if (!paymentDetails.hasPaymentUrl()) return null; Protos.Payment.Builder payment = Protos.Payment.newBuilder(); if (paymentDetails.hasMerchantData()) payment.setMerchantData(paymentDetails.getMerchantData()); if (refundAddr != null) { Protos.Output.Builder refundOutput = Protos.Output.newBuilder(); refundOutput.setAmount(totalValue.longValue()); refundOutput.setScript( ByteString.copyFrom(ScriptBuilder.createOutputScript(refundAddr).getProgram())); payment.addRefundTo(refundOutput); } if (memo != null) { payment.setMemo(memo); } for (Transaction txn : txns) { txn.verify(); ByteArrayOutputStream o = new ByteArrayOutputStream(); txn.bitcoinSerialize(o); payment.addTransactions(ByteString.copyFrom(o.toByteArray())); } return payment.build(); }
/** * This is required for signatures which use a sigHashType which cannot be represented using * SigHash and anyoneCanPay See transaction * c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73, which has sigHashType 0 */ public static synchronized byte[] serializeForSignature( Transaction spendingTx, int inputIndex, byte[] connectedScript, byte sigHashType) { NetworkParameters params = TestNet3Params.get(); // The SIGHASH flags are used in the design of contracts, please see this page for a further // understanding of // the purposes of the code in this method: // // https://en.bitcoin.it/wiki/Contracts try { Transaction tx = new Transaction(params, spendingTx.bitcoinSerialize()); // Store all the input scripts and clear them in preparation for signing. If we're signing a // fresh // transaction that step isn't very helpful, but it doesn't add much cost relative to the // actual // EC math so we'll do it anyway. // // Also store the input sequence numbers in case we are clearing them with SigHash.NONE/SINGLE byte[][] inputScripts = new byte[tx.getInputs().size()][]; long[] inputSequenceNumbers = new long[tx.getInputs().size()]; for (int i = 0; i < tx.getInputs().size(); i++) { inputScripts[i] = tx.getInputs().get(i).getScriptBytes(); inputSequenceNumbers[i] = tx.getInputs().get(i).getSequenceNumber(); tx.getInput(i).setScriptSig(new Script(new byte[0])); } // This step has no purpose beyond being synchronized with the reference clients bugs. // OP_CODESEPARATOR // is a legacy holdover from a previous, broken design of executing scripts that shipped in // Bitcoin 0.1. // It was seriously flawed and would have let anyone take anyone elses money. Later versions // switched to // the design we use today where scripts are executed independently but share a stack. This // left the // OP_CODESEPARATOR instruction having no purpose as it was only meant to be used internally, // not actually // ever put into scripts. Deleting OP_CODESEPARATOR is a step that should never be required // but if we don't // do it, we could split off the main chain. connectedScript = Script.removeAllInstancesOfOp(connectedScript, ScriptOpCodes.OP_CODESEPARATOR); // Set the input to the script of its output. Satoshi does this but the step has no obvious // purpose as // the signature covers the hash of the prevout transaction which obviously includes the // output script // already. Perhaps it felt safer to him in some way, or is another leftover from how the code // was written. TransactionInput input = tx.getInputs().get(inputIndex); input.setScriptSig(new Script(connectedScript)); List<TransactionOutput> outputs = tx.getOutputs(); if ((sigHashType & 0x1f) == (Transaction.SigHash.NONE.ordinal() + 1)) { // SIGHASH_NONE means no outputs are signed at all - the signature is effectively for a // "blank cheque". // this.outputs = new ArrayList<TransactionOutput>(0); tx.clearOutputs(); // The signature isn't broken by new versions of the transaction issued by other parties. for (int i = 0; i < tx.getInputs().size(); i++) if (i != inputIndex) tx.getInputs().get(i).setSequenceNumber(0); } else if ((sigHashType & 0x1f) == (Transaction.SigHash.SINGLE.ordinal() + 1)) { // SIGHASH_SINGLE means only sign the output at the same index as the input (ie, my output). if (inputIndex >= tx.getOutputs().size()) { // The input index is beyond the number of outputs, it's a buggy signature made by a // broken // Bitcoin implementation. The reference client also contains a bug in handling this case: // any transaction output that is signed in this case will result in both the signed // output // and any future outputs to this public key being steal-able by anyone who has // the resulting signature and the public key (both of which are part of the signed tx // input). // Put the transaction back to how we found it. // // TODO: Only allow this to happen if we are checking a signature, not signing a // transactions for (int i = 0; i < tx.getInputs().size(); i++) { // tx.getInputs().get(i).setScriptSig(inputScripts[i]); /* tx.getInputs().get(i).setScriptSig(ScriptBuilder.createMultiSigInputScriptBytes( Arrays.asList(inputScripts[i])));*/ tx.getInput(i).setScriptSig(new Script(inputScripts[i])); tx.getInputs().get(i).setSequenceNumber(inputSequenceNumbers[i]); } // this.outputs = outputs; // Satoshis bug is that SignatureHash was supposed to return a hash and on this codepath // it // actually returns the constant "1" to indicate an error, which is never checked for. // Oops. return Utils.HEX.decode( "0100000000000000000000000000000000000000000000000000000000000000"); } // In SIGHASH_SINGLE the outputs after the matching input index are deleted, and the outputs // before // that position are "nulled out". Unintuitively, the value in a "null" transaction is set // to -1. /* this.outputs = new ArrayList<TransactionOutput>(this.outputs.subList(0, inputIndex + 1)); for (int i = 0; i < inputIndex; i++) this.outputs.set(i, new TransactionOutput(params, this, Coin.NEGATIVE_SATOSHI, new byte[] {})); // The signature isn't broken by new versions of the transaction issued by other parties. for (int i = 0; i < inputs.size(); i++) if (i != inputIndex) inputs.get(i).setSequenceNumber(0);*/ // In SIGHASH_SINGLE the outputs after the matching input index are deleted, and the outputs // before // that position are "nulled out". Unintuitively, the value in a "null" transaction is set // to -1. // tx.outputs = new ArrayList<TransactionOutput>(tx.getOutputs().subList(0, inputIndex + // 1)); tx.clearOutputs(); for (int i = 0; i <= inputIndex; i++) if (i == inputIndex) { // need to make sure the output at inputIndex stays the same tx.addOutput(spendingTx.getOutput(inputIndex)); } else { // this.outputs.set(i, new TransactionOutput(params, this, Coin.NEGATIVE_SATOSHI, new // byte[] {})); tx.addOutput(new TransactionOutput(params, tx, Coin.NEGATIVE_SATOSHI, new byte[] {})); } // The signature isn't broken by new versions of the transaction issued by other parties. for (int i = 0; i < tx.getInputs().size(); i++) if (i != inputIndex) tx.getInputs().get(i).setSequenceNumber(0); } List<TransactionInput> inputs = tx.getInputs(); if ((sigHashType & (byte) 0x80) == 0x80) { // SIGHASH_ANYONECANPAY means the signature in the input is not broken by // changes/additions/removals // of other inputs. For example, this is useful for building assurance contracts. tx.clearInputs(); tx.getInputs().add(input); } ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(256); tx.bitcoinSerialize(bos); // We also have to write a hash type (sigHashType is actually an unsigned char) uint32ToByteStreamLE(0x000000ff & sigHashType, bos); // Note that this is NOT reversed to ensure it will be signed correctly. If it were to be // printed out // however then we would expect that it is IS reversed. byte[] txSignatureBytes = bos.toByteArray(); bos.close(); // Put the transaction back to how we found it. // tx.inputs = inputs; tx.clearInputs(); for (int i = 0; i < inputs.size(); i++) { tx.addInput(inputs.get(i)); } for (int i = 0; i < inputs.size(); i++) { inputs.get(i).setScriptSig(new Script(inputScripts[i])); inputs.get(i).setSequenceNumber(inputSequenceNumbers[i]); } // this.outputs = outputs; tx.clearOutputs(); for (int i = 0; i < outputs.size(); i++) { tx.addOutput(outputs.get(i)); } return txSignatureBytes; } catch (IOException e) { throw new RuntimeException(e); // Cannot happen. } }