diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py index df02c1697..aa403f058 100755 --- a/qa/rpc-tests/rawtransactions.py +++ b/qa/rpc-tests/rawtransactions.py @@ -138,5 +138,11 @@ class RawTransactionsTest(BitcoinTestFramework): self.sync_all() assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx + inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}] + outputs = { self.nodes[0].getnewaddress() : 1 } + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + decrawtx= self.nodes[0].decoderawtransaction(rawtx) + assert_equal(decrawtx['vin'][0]['sequence'], 1000) + if __name__ == '__main__': RawTransactionsTest().main() diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 95d7a085a..d5e2fc279 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -71,7 +71,7 @@ static bool AppInitRawTx(int argc, char* argv[]) strUsage = HelpMessageGroup(_("Commands:")); strUsage += HelpMessageOpt("delin=N", _("Delete input N from TX")); strUsage += HelpMessageOpt("delout=N", _("Delete output N from TX")); - strUsage += HelpMessageOpt("in=TXID:VOUT", _("Add input to TX")); + strUsage += HelpMessageOpt("in=TXID:VOUT(:SEQUENCE_NUMBER)", _("Add input to TX")); strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N")); strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N")); strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX")); @@ -181,15 +181,15 @@ static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal) static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput) { + std::vector vStrInputParts; + boost::split(vStrInputParts, strInput, boost::is_any_of(":")); + // separate TXID:VOUT in string - size_t pos = strInput.find(':'); - if ((pos == string::npos) || - (pos == 0) || - (pos == (strInput.size() - 1))) + if (vStrInputParts.size()<2) throw runtime_error("TX input missing separator"); // extract and validate TXID - string strTxid = strInput.substr(0, pos); + string strTxid = vStrInputParts[0]; if ((strTxid.size() != 64) || !IsHex(strTxid)) throw runtime_error("invalid TX input txid"); uint256 txid(uint256S(strTxid)); @@ -198,13 +198,18 @@ static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput) static const unsigned int maxVout = MAX_BLOCK_SIZE / minTxOutSz; // extract and validate vout - string strVout = strInput.substr(pos + 1, string::npos); + string strVout = vStrInputParts[1]; int vout = atoi(strVout); if ((vout < 0) || (vout > (int)maxVout)) throw runtime_error("invalid TX input vout"); + // extract the optional sequence number + uint32_t nSequenceIn=std::numeric_limits::max(); + if (vStrInputParts.size() > 2) + nSequenceIn = atoi(vStrInputParts[2]); + // append to transaction input list - CTxIn txin(txid, vout); + CTxIn txin(txid, vout, CScript(), nSequenceIn); tx.vin.push_back(txin); } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 32b4ad47f..4517ffcbb 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -334,6 +334,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) " {\n" " \"txid\":\"id\", (string, required) The transaction id\n" " \"vout\":n (numeric, required) The output number\n" + " \"sequence\":n (numeric, optional) The sequence number\n" " }\n" " ,...\n" " ]\n" @@ -384,6 +385,12 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits::max() - 1 : std::numeric_limits::max()); + + // set the sequence number if passed in the parameters object + const UniValue& sequenceObj = find_value(o, "sequence"); + if (sequenceObj.isNum()) + nSequence = sequenceObj.get_int(); + CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence); rawTx.vin.push_back(in); diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json index 3bf80ca43..5cb383de8 100644 --- a/src/test/data/bitcoin-util-test.json +++ b/src/test/data/bitcoin-util-test.json @@ -86,5 +86,18 @@ "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o", "outdata=54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"], "output_cmp": "txcreatedata2.hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:4294967293", + "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o"], + "output_cmp": "txcreatedata_seq0.hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:1"], + "output_cmp": "txcreatedata_seq1.hex" } ] diff --git a/src/test/data/txcreatedata_seq0.hex b/src/test/data/txcreatedata_seq0.hex new file mode 100644 index 000000000..db02b5e4a --- /dev/null +++ b/src/test/data/txcreatedata_seq0.hex @@ -0,0 +1 @@ +01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000 diff --git a/src/test/data/txcreatedata_seq1.hex b/src/test/data/txcreatedata_seq1.hex new file mode 100644 index 000000000..4cedcd975 --- /dev/null +++ b/src/test/data/txcreatedata_seq1.hex @@ -0,0 +1 @@ +01000000021f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff1f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000010000000180a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac00000000