diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index ad7e574ad..86de05315 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -260,6 +260,7 @@ static const CRPCCommand vRPCCommands[] = { "decoderawtransaction", &decoderawtransaction, false, false, false }, { "signrawtransaction", &signrawtransaction, false, false, false }, { "sendrawtransaction", &sendrawtransaction, false, false, false }, + { "getnormalizedtxid", &getnormalizedtxid, true, true, false }, { "gettxoutsetinfo", &gettxoutsetinfo, true, false, false }, { "gettxout", &gettxout, true, false, false }, { "lockunspent", &lockunspent, false, false, true }, diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 137c045d5..bf87ff4e3 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -194,6 +194,7 @@ extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getnormalizedtxid(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp); diff --git a/src/main.h b/src/main.h index 5478ce2af..bbd3d32c6 100644 --- a/src/main.h +++ b/src/main.h @@ -514,6 +514,11 @@ public: return SerializeHash(*this); } + uint256 GetNormalizedHash() const + { + return SignatureHash(CScript(), *this, 0, SIGHASH_ALL); + } + bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const { // Time based nLockTime implemented in 0.1.6 diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 6c199219d..9e9093442 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -576,3 +576,25 @@ Value sendrawtransaction(const Array& params, bool fHelp) return hashTx.GetHex(); } + +Value getnormalizedtxid(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error("blah"); + + // parse hex string from parameter + vector txData(ParseHexV(params[0], "parameter")); + CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); + CTransaction tx; + + // deserialize binary data stream + try { + ssData >> tx; + } + catch (std::exception &e) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + } + uint256 hashNormalized = tx.GetNormalizedHash(); + + return hashNormalized.GetHex(); +} diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index dab5b440c..054753370 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -45,6 +45,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry) entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime))); } entry.push_back(Pair("txid", wtx.GetHash().GetHex())); + entry.push_back(Pair("normtxid", wtx.GetNormalizedHash().GetHex())); entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime())); entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived)); BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) diff --git a/src/script.h b/src/script.h index 9113024b3..6a51b9704 100644 --- a/src/script.h +++ b/src/script.h @@ -670,6 +670,7 @@ public: bool IsCanonicalPubKey(const std::vector &vchPubKey); bool IsCanonicalSignature(const std::vector &vchSig); +uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); bool EvalScript(std::vector >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector >& vSolutionsRet); int ScriptSigArgsExpected(txnouttype t, const std::vector >& vSolutions);