Skip to content

Commit

Permalink
rpc: Add verifyrawtransactions call
Browse files Browse the repository at this point in the history
Add a RPC call to verify a set of raw transactions without propagating them.

Implements bitcoin#4162.

    verifyrawtransactions ["hexstring",...] ( options )

    Verifies one or more raw transactions (serialized, hex-encoded). If transactions depend on each other, they must be provided in order.

    Arguments:
    1. ["hexstring",...] (array of strings, required) The hex string of the raw transactions)
    2. options   (json object, optional)
         {
           "include_mempool"          (boolean, optional, default=true) Whether to include the mem pool
           "check_final"              (boolean, optional, default=true) Check that the transactions will be final by next block
           "check_standard"           (boolean, optional, default=true) Perform transaction standard checks
         }

    Result:
    null if the verification was successful, otherwise an error object:
    {
      "index":n,                (numeric) Index in transactions array of failed transaction
      "hash":"hex",             (string) Transaction hash of failed transaction
      "code": n,                (numeric) Reject code
      "reason": "text"          (string) Reject reason
      "debug_message": "text"   (string) Reject debug message
    }
  • Loading branch information
laanwj committed Mar 18, 2016
1 parent 29e1131 commit add2259
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/rpc/client.cpp
Expand Up @@ -100,6 +100,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "prioritisetransaction", 2 },
{ "setban", 2 },
{ "setban", 3 },
{ "verifyrawtransactions", 0 },
{ "verifyrawtransactions", 1 },
};

class CRPCConvertTable
Expand Down
115 changes: 115 additions & 0 deletions src/rpc/rawtransaction.cpp
Expand Up @@ -839,3 +839,118 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)

return hashTx.GetHex();
}

UniValue verifyrawtransactions(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"verifyrawtransactions [\"hexstring\",...] ( options )\n"
"\nVerifies one or more raw transactions (serialized, hex-encoded). If transactions depend on each other, they must be provided in order.\n"
"\nArguments:\n"
"1. [\"hexstring\",...] (array of strings, required) The hex string of the raw transactions)\n"
"2. options (json object, optional)\n"
" {\n"
" \"include_mempool\" (boolean, optional, default=true) Whether to include the mem pool\n"
" \"check_final\" (boolean, optional, default=true) Check that the transactions will be final by next block\n"
" \"check_standard\" (boolean, optional, default=true) Perform transaction standard checks\n"
" }\n"
"\nResult:\n"
"null if the verification was successful, otherwise an error object:\n"
"{\n"
" \"index\":n, (numeric) Index in transactions array of failed transaction\n"
" \"hash\":\"hex\", (string) Transaction hash of failed transaction\n"
" \"code\": n, (numeric) Reject code\n"
" \"reason\": \"text\" (string) Reject reason\n"
" \"debug_message\": \"text\" (string) Reject debug message\n"
"}\n"
"\nExamples:\n"
"\nCreate a transaction\n"
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
"Sign the transaction, and get back the hex\n"
+ HelpExampleCli("signrawtransaction", "\"myhex\"") +
"\nVerify the transaction (signed hex)\n"
+ HelpExampleCli("verifyrawtransactions", "'[\"signedhex\"]'") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("verifyrawtransactions", "[\"signedhex\"]")
);

LOCK2(cs_main,mempool.cs);

// Parse parameters
std::vector<std::string> hexes;
bool includeMempool = true;
bool checkFinal = true;
bool checkStandard = true;
if (params.size() < 1)
throw JSONRPCError(RPC_TYPE_ERROR, "Missing transactions argument");
if (params[0].isArray()) {
for (size_t i=0; i<params[0].size(); ++i)
hexes.push_back(params[0][i].get_str());
} else {
throw JSONRPCError(RPC_TYPE_ERROR, "First argument must be an array of strings");
}
if (params.size() > 1) {
const UniValue &options = params[1];
if (!options.isObject())
throw JSONRPCError(RPC_TYPE_ERROR, "Second argument must be an object specifying options");
UniValue o;
o = find_value(options, "include_mempool");
if (o.isBool())
includeMempool = o.get_bool();
o = find_value(options, "check_final");
if (o.isBool())
checkFinal = o.get_bool();
o = find_value(options, "check_standard");
if (o.isBool())
checkStandard = o.get_bool();
}

// Parse hex strings as transactions
std::vector<CTransaction> txes;
for (size_t i=0; i<hexes.size(); ++i) {
CTransaction tx;
if (!DecodeHexTx(tx, hexes[i]))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed (index %i)", i));
txes.push_back(tx);
}

// Check transactions, one by one, inserting them into a temporary cache
CCoinsViewMemPool coinsTipMempool(pcoinsTip, mempool);
CCoinsViewCache view(includeMempool ? (CCoinsView*)&coinsTipMempool : pcoinsTip);
int height = chainActive.Height() + 1;
for (size_t i=0; i<txes.size(); ++i) {
const CTransaction &tx = txes[i];
bool ok = true;
CValidationState state;
if (ok)
ok = CheckTransaction(tx, state);
if (ok && checkStandard) {
std::string reason;
if (!IsStandardTx(tx, reason)) {
ok = false;
state.DoS(0, false, REJECT_NONSTANDARD, reason);
}
}
if (ok && checkFinal && !CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) {
ok = false;
state.DoS(0, false, REJECT_NONSTANDARD, "non-final");
}
if (ok) {
ok = CheckInputs(tx, state, view, true,
checkStandard ? STANDARD_SCRIPT_VERIFY_FLAGS : MANDATORY_SCRIPT_VERIFY_FLAGS,
true);
}
if (ok) {
UpdateCoins(tx, state, view, height);
} else {
UniValue rv(UniValue::VOBJ);
rv.push_back(Pair("index", (int)i));
rv.push_back(Pair("hash", tx.GetHash().ToString()));
rv.push_back(Pair("code", (int)state.GetRejectCode()));
rv.push_back(Pair("reason", state.GetRejectReason()));
rv.push_back(Pair("debug_message", state.GetDebugMessage()));
return rv;
}
}
return NullUniValue;
}
1 change: 1 addition & 0 deletions src/rpc/server.cpp
Expand Up @@ -307,6 +307,7 @@ static const CRPCCommand vRPCCommands[] =
{ "rawtransactions", "getrawtransaction", &getrawtransaction, true },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false },
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */
{ "rawtransactions", "verifyrawtransactions", &verifyrawtransactions, true },

/* Utility functions */
{ "util", "createmultisig", &createmultisig, true },
Expand Down
1 change: 1 addition & 0 deletions src/rpc/server.h
Expand Up @@ -219,6 +219,7 @@ extern UniValue createrawtransaction(const UniValue& params, bool fHelp);
extern UniValue decoderawtransaction(const UniValue& params, bool fHelp);
extern UniValue decodescript(const UniValue& params, bool fHelp);
extern UniValue signrawtransaction(const UniValue& params, bool fHelp);
extern UniValue verifyrawtransactions(const UniValue& params, bool fHelp);
extern UniValue sendrawtransaction(const UniValue& params, bool fHelp);
extern UniValue gettxoutproof(const UniValue& params, bool fHelp);
extern UniValue verifytxoutproof(const UniValue& params, bool fHelp);
Expand Down

0 comments on commit add2259

Please sign in to comment.