From d7078533ebd32bb5071f4dba8e3d9c5a3b1f0d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Jan=C3=ADk?= Date: Mon, 29 Jun 2015 20:14:02 +0200 Subject: [PATCH] Add OP_RETURN support in createrawtransaction RPC call, add tests. --- src/rpcrawtransaction.cpp | 43 ++++++++++++++++++++++++--------------- src/test/rpc_tests.cpp | 18 ++++++++++++++++ 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index a3246b41fb..9eeca5b7d9 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -318,8 +318,9 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) throw runtime_error( - "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,...}\n" - "\nCreate a transaction spending the given inputs and sending to the given addresses.\n" + "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...}\n" + "\nCreate a transaction spending the given inputs and creating new outputs.\n" + "Outputs can be addresses or data.\n" "Returns hex-encoded raw transaction.\n" "Note that the transaction's inputs are not signed, and\n" "it is not stored in the wallet or transmitted to the network.\n" @@ -328,23 +329,25 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) "1. \"transactions\" (string, required) A json array of json objects\n" " [\n" " {\n" - " \"txid\":\"id\", (string, required) The transaction id\n" + " \"txid\":\"id\", (string, required) The transaction id\n" " \"vout\":n (numeric, required) The output number\n" " }\n" " ,...\n" " ]\n" - "2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n" + "2. \"outputs\" (string, required) a json object with outputs\n" " {\n" " \"address\": x.xxx (numeric, required) The key is the bitcoin address, the value is the " + CURRENCY_UNIT + " amount\n" - " ,...\n" + " \"data\": \"hex\", (string, required) The key is \"data\", the value is hex encoded data\n" + " ...\n" " }\n" - "\nResult:\n" "\"transaction\" (string) hex string of the transaction\n" "\nExamples\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") + + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"data\\\":\\\"00010203\\\"}\"") + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"") + + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"") ); LOCK(cs_main); @@ -375,19 +378,27 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) set setAddress; vector addrList = sendTo.getKeys(); BOOST_FOREACH(const string& name_, addrList) { - CBitcoinAddress address(name_); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_); - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); - setAddress.insert(address); + if (name_ == "data") { + std::vector data = ParseHexV(sendTo[name_].getValStr(),"Data"); - CScript scriptPubKey = GetScriptForDestination(address.Get()); - CAmount nAmount = AmountFromValue(sendTo[name_]); + CTxOut out(0, CScript() << OP_RETURN << data); + rawTx.vout.push_back(out); + } else { + CBitcoinAddress address(name_); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_); - CTxOut out(nAmount, scriptPubKey); - rawTx.vout.push_back(out); + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); + setAddress.insert(address); + + CScript scriptPubKey = GetScriptForDestination(address.Get()); + CAmount nAmount = AmountFromValue(sendTo[name_]); + + CTxOut out(nAmount, scriptPubKey); + rawTx.vout.push_back(out); + } } return EncodeHexTx(rawTx); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 7946b02855..a65572e6f6 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -110,6 +110,24 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign) BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true); } +BOOST_AUTO_TEST_CASE(rpc_createraw_op_return) +{ + BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\"}")); + + // Allow more than one data transaction output + BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\",\"data\":\"68656c6c6f776f726c64\"}")); + + // Key not "data" (bad address) + BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"somedata\":\"68656c6c6f776f726c64\"}"), runtime_error); + + // Bad hex encoding of data output + BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345\"}"), runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345g\"}"), runtime_error); + + // Data 81 bytes long + BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081\"}")); +} + BOOST_AUTO_TEST_CASE(rpc_format_monetary_values) { BOOST_CHECK(ValueFromAmount(0LL).write() == "0.00000000");