createrawtransaction enchancement
- allowing create OP_RETURN vouts (field "data" in "outputs" json)
- allowing using script (hex), in "outputs" (for example, you can use any P2PK, P2PKH or P2SH script as destination)
- advanced duplicates checking (users can't use same destination in various forms, for example, you can't make one vout as address and second vout, same address, but coded with P2PK script)
- allowing to bypass duplicates check for notaries (for example, to manually create splitfunds txes, using daemon RPC only), for common users it's forbidden
Useful usage:
Don't forget that you can create raw transaction with empty vins, like
createrawtransaction "[]" "{\"RKZWgNw9rvMJCHeD6mFgFNrJGxCoT2bft1\":0.777}"
and then fund it (with vins) using fundrawtransaction.
Duplicates testing vectors (passed):
createrawtransaction "[]" "{\"RKZWgNw9rvMJCHeD6mFgFNrJGxCoT2bft1\":0.777,\"2102c42516ab9b0958f349783222c8b665314ce0f12ae513af1c15e10e8045b87544ac\":0.01}"
createrawtransaction "[]" "{\"76a91470c770cd22061696c01011a020892d136caba70588ac\":0.777,\"2102c42516ab9b0958f349783222c8b665314ce0f12ae513af1c15e10e8045b87544ac\":0.01}"
createrawtransaction "[]" "{\"2102c42516ab9b0958f349783222c8b665314ce0f12ae513af1c15e10e8045b87544ac\":0.777,\"76a91470c770cd22061696c01011a020892d136caba70588ac\":0.01}"
createrawtransaction "[]" "{\"data\":\"010203\",\"76a91470c770cd22061696c01011a020892d136caba70588ac\":0.01}"
createrawtransaction "[]" "{\"RKZWgNw9rvMJCHeD6mFgFNrJGxCoT2bft1\":0.777,\"76a91470c770cd22061696c01011a020892d136caba70588ac\":0.01}"
createrawtransaction "[]" "{\"76a91470c770cd22061696c01011a020892d136caba70588ac\":0.777,\"RKZWgNw9rvMJCHeD6mFgFNrJGxCoT2bft1\":0.01}"
createrawtransaction "[]" "{\"76a91470c770cd22061696c01011a020892d136caba70588ac\":0.777,\"a914fe6ac2ca169440909ab86e2e015db0938b92634787\":0.01}"
createrawtransaction "[]" "{\"76a91470c770cd22061696c01011a020892d136caba70588ac\":0.777,\"a914fe6ac2ca169440909ab86e2e015db0938b92634787\":0.01,\"a914fe6ac2ca169440909ab86e2e015db0938b92634787\":0.02}"
createrawtransaction "[]" "{\"76a91470c770cd22061696c01011a020892d136caba70588ac\":0.777,\"a914fe6ac2ca169440909ab86e2e015db0938b92634787\":0.01,\"data\":\"00010203\"}"
This commit is contained in:
@@ -727,27 +727,31 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
|
|||||||
|
|
||||||
UniValue createrawtransaction(const UniValue& params, bool fHelp)
|
UniValue createrawtransaction(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
|
string examplescriptPubKey = "21021ce1eac70455c3e6c52d67c133549b8aed4a588fba594372e8048e65c4f0fcb6ac";
|
||||||
|
|
||||||
if (fHelp || params.size() < 2 || params.size() > 4)
|
if (fHelp || params.size() < 2 || params.size() > 4)
|
||||||
throw runtime_error(
|
throw runtime_error(
|
||||||
"createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,...} ( locktime ) ( expiryheight )\n"
|
"createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,...} ( locktime ) ( expiryheight )\n"
|
||||||
"\nCreate a transaction spending the given inputs and sending to the given addresses.\n"
|
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
|
||||||
|
"Outputs can be addresses or standart scripts (in hex) or data.\n"
|
||||||
"Returns hex-encoded raw transaction.\n"
|
"Returns hex-encoded raw transaction.\n"
|
||||||
"Note that the transaction's inputs are not signed, and\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"
|
"it is not stored in the wallet or transmitted to the network.\n"
|
||||||
|
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. \"transactions\" (string, required) A json array of json objects\n"
|
"1. \"inputs\" (array, required) A json array of json objects\n"
|
||||||
" [\n"
|
" [\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"
|
" \"vout\":n, (numeric, required) The output number\n"
|
||||||
" \"sequence\":n (numeric, optional) The sequence number\n"
|
" \"sequence\":n (numeric, optional) The sequence number\n"
|
||||||
" }\n"
|
" } \n"
|
||||||
" ,...\n"
|
" ,...\n"
|
||||||
" ]\n"
|
" ]\n"
|
||||||
"2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n"
|
"2. \"outputs\" (object, required) a json object with outputs\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" \"address\": x.xxx (numeric, required) The key is the Komodo address, the value is the " + CURRENCY_UNIT + " amount\n"
|
" \"address\": x.xxx, (numeric or string, required) The key is the komodo address or script (in hex), the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n"
|
||||||
|
" \"data\": \"hex\" (string, required) The key is \"data\", the value is hex encoded data\n"
|
||||||
" ,...\n"
|
" ,...\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
|
"3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
|
||||||
@@ -757,7 +761,11 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
|
|||||||
|
|
||||||
"\nExamples\n"
|
"\nExamples\n"
|
||||||
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"")
|
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"")
|
||||||
+ HelpExampleRpc("createrawtransaction", "[{\"txid\":\"myid\",\"vout\":0}], {\"address\":0.01}")
|
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\""+examplescriptPubKey+"\\\":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}]\", \"{\\\""+examplescriptPubKey+"\\\":0.01}\"")
|
||||||
|
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
@@ -817,22 +825,61 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::set<CTxDestination> destinations;
|
std::set<CTxDestination> destinations;
|
||||||
|
//std::set<std::string> destinations;
|
||||||
|
|
||||||
vector<string> addrList = sendTo.getKeys();
|
vector<string> addrList = sendTo.getKeys();
|
||||||
for (const std::string& name_ : addrList) {
|
|
||||||
CTxDestination destination = DecodeDestination(name_);
|
if (addrList.size() != sendTo.size()) {
|
||||||
if (!IsValidDestination(destination)) {
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid outputs")); // for checking edge case, should never happened ...
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Komodo address: ") + name_);
|
}
|
||||||
|
|
||||||
|
//for (const std::string& name_ : addrList) {
|
||||||
|
for (size_t idx = 0; idx < sendTo.size(); idx++) {
|
||||||
|
|
||||||
|
const std::string& name_ = addrList[idx];
|
||||||
|
|
||||||
|
CScript scriptPubKey;
|
||||||
|
CTxDestination destination;
|
||||||
|
|
||||||
|
if (name_ == "data") {
|
||||||
|
std::vector<unsigned char> data = ParseHexV(sendTo[name_].getValStr(),"Data");
|
||||||
|
CTxOut out(0, CScript() << OP_RETURN << data);
|
||||||
|
rawTx.vout.push_back(out);
|
||||||
|
} else {
|
||||||
|
destination = DecodeDestination(name_);
|
||||||
|
if (IsValidDestination(destination)) {
|
||||||
|
scriptPubKey = GetScriptForDestination(destination);
|
||||||
|
} else if (IsHex(name_)) {
|
||||||
|
std::vector<unsigned char> data(ParseHex(name_));
|
||||||
|
scriptPubKey = CScript(data.begin(), data.end());
|
||||||
|
// destination is not valid, but we should convert it to valid anyway, to be able to check duplicates,
|
||||||
|
// so we need to get destination from existing scriptPubKey via ExtractDestination
|
||||||
|
if (!(ExtractDestination(scriptPubKey, destination) &&
|
||||||
|
(scriptPubKey.IsPayToPublicKeyHash() || scriptPubKey.IsPayToPublicKey() || scriptPubKey.IsPayToScriptHash())
|
||||||
|
)) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid script: ") + name_ + std::string(" (only P2PKH, P2PK and P2SH scripts are allowed)"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Komodo address or script: ") + name_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fExperimentalMode && IS_KOMODO_NOTARY)) {
|
||||||
|
// support of sending duplicates in createrawtransaction requires experimental features enabled and
|
||||||
|
// notary flag, to prevent common users to get messed up with duplicates
|
||||||
|
|
||||||
|
//if (!destinations.insert(EncodeDestination(destination)).second) {
|
||||||
|
if (!destinations.insert(destination).second) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated destination: ") + name_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAmount nAmount = AmountFromValue(sendTo[name_]); // operator[](const std::string& key) const;
|
||||||
|
CAmount nAmount = AmountFromValue(sendTo[idx]); // operator[](size_t index) const;
|
||||||
|
|
||||||
|
CTxOut out(nAmount, scriptPubKey);
|
||||||
|
rawTx.vout.push_back(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!destinations.insert(destination).second) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
|
|
||||||
}
|
|
||||||
|
|
||||||
CScript scriptPubKey = GetScriptForDestination(destination);
|
|
||||||
CAmount nAmount = AmountFromValue(sendTo[name_]);
|
|
||||||
|
|
||||||
CTxOut out(nAmount, scriptPubKey);
|
|
||||||
rawTx.vout.push_back(out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return EncodeHexTx(rawTx);
|
return EncodeHexTx(rawTx);
|
||||||
|
|||||||
Reference in New Issue
Block a user