diff options
author | MarcoFalke <falke.marco@gmail.com> | 2020-12-24 15:32:02 +0100 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2020-12-24 15:32:10 +0100 |
commit | f656165e9c0d09e654efabd56e6581638e35c26c (patch) | |
tree | 4346a432ef3d3c855964d3c594d89fe06db50289 /src | |
parent | cc592a85ea0c371f7269dbcad32857c181b657d1 (diff) | |
parent | 66d012ad7f9381bacfc9b8388fa2ebf82cb86c9e (diff) |
Merge #18772: rpc: calculate fees in getblock using BlockUndo data
66d012ad7f9381bacfc9b8388fa2ebf82cb86c9e test: RPC: getblock fee calculations (Elliott Jin)
bf7d6e31b1062ab5f90e14e83c56309f499fa2e9 RPC: getblock: tx fee calculation for verbosity 2 via Undo data (Elliott Jin)
Pull request description:
This change is progress towards #18771 . It adapts the fee calculation part of #16083 and addresses some feedback. The additional "verbosity level 3" features are planned for a future PR.
**Original PR description:**
> Using block undo data (like in #14802) we can now show fee information for each transaction in a block without the need for additional -txindex and/or a ton of costly lookups. For a start we'll add transaction fee information to getblock verbosity level 2. This comes at a negligible speed penalty (<1%).
ACKs for top commit:
luke-jr:
tACK 66d012ad7f9381bacfc9b8388fa2ebf82cb86c9e
fjahr:
tACK 66d012ad7f9381bacfc9b8388fa2ebf82cb86c9e
MarcoFalke:
review ACK 66d012ad7f9381bacfc9b8388fa2ebf82cb86c9e 🗜
Tree-SHA512: be1fe4b866946a8dc36427f7dc72a20e10860e320a28fa49bc85bd2a93a0d699768179be29fa52e18b2ed8505d3ec272e586753ef2239b4230e0aefd233acaa2
Diffstat (limited to 'src')
-rw-r--r-- | src/core_io.h | 3 | ||||
-rw-r--r-- | src/core_write.cpp | 31 | ||||
-rw-r--r-- | src/rpc/blockchain.cpp | 18 |
3 files changed, 41 insertions, 11 deletions
diff --git a/src/core_io.h b/src/core_io.h index aaee9c445d..fa6900a42a 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -18,6 +18,7 @@ class CTransaction; struct CMutableTransaction; class uint256; class UniValue; +class CTxUndo; // core_read.cpp CScript ParseScript(const std::string& s); @@ -45,6 +46,6 @@ std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0); std::string SighashToStr(unsigned char sighash_type); void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); void ScriptToUniv(const CScript& script, UniValue& out, bool include_address); -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0); +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr); #endif // BITCOIN_CORE_IO_H diff --git a/src/core_write.cpp b/src/core_write.cpp index 3980d8cb2e..675864200b 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -11,7 +11,9 @@ #include <script/standard.h> #include <serialize.h> #include <streams.h> +#include <undo.h> #include <univalue.h> +#include <util/check.h> #include <util/system.h> #include <util/strencodings.h> @@ -177,7 +179,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("addresses", a); } -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags) +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo) { entry.pushKV("txid", tx.GetHash().GetHex()); entry.pushKV("hash", tx.GetWitnessHash().GetHex()); @@ -189,13 +191,20 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, entry.pushKV("weight", GetTransactionWeight(tx)); entry.pushKV("locktime", (int64_t)tx.nLockTime); - UniValue vin(UniValue::VARR); + UniValue vin{UniValue::VARR}; + + // If available, use Undo data to calculate the fee. Note that txundo == nullptr + // for coinbase transactions and for transactions where undo data is unavailable. + const bool calculate_fee = txundo != nullptr; + CAmount amt_total_in = 0; + CAmount amt_total_out = 0; + for (unsigned int i = 0; i < tx.vin.size(); i++) { const CTxIn& txin = tx.vin[i]; UniValue in(UniValue::VOBJ); - if (tx.IsCoinBase()) + if (tx.IsCoinBase()) { in.pushKV("coinbase", HexStr(txin.scriptSig)); - else { + } else { in.pushKV("txid", txin.prevout.hash.GetHex()); in.pushKV("vout", (int64_t)txin.prevout.n); UniValue o(UniValue::VOBJ); @@ -210,6 +219,10 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, } in.pushKV("txinwitness", txinwitness); } + if (calculate_fee) { + const CTxOut& prev_txout = txundo->vprevout[i].out; + amt_total_in += prev_txout.nValue; + } in.pushKV("sequence", (int64_t)txin.nSequence); vin.push_back(in); } @@ -228,9 +241,19 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, ScriptPubKeyToUniv(txout.scriptPubKey, o, true); out.pushKV("scriptPubKey", o); vout.push_back(out); + + if (calculate_fee) { + amt_total_out += txout.nValue; + } } entry.pushKV("vout", vout); + if (calculate_fee) { + const CAmount fee = amt_total_in - amt_total_out; + CHECK_NONFATAL(MoneyRange(fee)); + entry.pushKV("fee", ValueFromAmount(fee)); + } + if (!hashBlock.IsNull()) entry.pushKV("blockhash", hashBlock.GetHex()); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 57327e6004..9047492642 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -172,16 +172,21 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn result.pushKV("versionHex", strprintf("%08x", block.nVersion)); result.pushKV("merkleroot", block.hashMerkleRoot.GetHex()); UniValue txs(UniValue::VARR); - for(const auto& tx : block.vtx) - { - if(txDetails) - { + if (txDetails) { + CBlockUndo blockUndo; + const bool have_undo = !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex); + for (size_t i = 0; i < block.vtx.size(); ++i) { + const CTransactionRef& tx = block.vtx.at(i); + // coinbase transaction (i == 0) doesn't have undo data + const CTxUndo* txundo = (have_undo && i) ? &blockUndo.vtxundo.at(i - 1) : nullptr; UniValue objTx(UniValue::VOBJ); - TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags()); + TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags(), txundo); txs.push_back(objTx); } - else + } else { + for (const CTransactionRef& tx : block.vtx) { txs.push_back(tx->GetHash().GetHex()); + } } result.pushKV("tx", txs); result.pushKV("time", block.GetBlockTime()); @@ -936,6 +941,7 @@ static RPCHelpMan getblock() {RPCResult::Type::OBJ, "", "", { {RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"}, + {RPCResult::Type::NUM, "fee", "The transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"}, }}, }}, }}, |