mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-07-01 11:11:15 +02:00
RPC: getblock: tx fee calculation for verbosity 2 via Undo data
Co-authored-by: Felix Weis <mail@felixweis.com>
This commit is contained in:
@ -18,6 +18,7 @@ class CTransaction;
|
|||||||
struct CMutableTransaction;
|
struct CMutableTransaction;
|
||||||
class uint256;
|
class uint256;
|
||||||
class UniValue;
|
class UniValue;
|
||||||
|
class CTxUndo;
|
||||||
|
|
||||||
// core_read.cpp
|
// core_read.cpp
|
||||||
CScript ParseScript(const std::string& s);
|
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);
|
std::string SighashToStr(unsigned char sighash_type);
|
||||||
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
|
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
|
||||||
void ScriptToUniv(const CScript& script, UniValue& out, bool include_address);
|
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
|
#endif // BITCOIN_CORE_IO_H
|
||||||
|
@ -11,7 +11,9 @@
|
|||||||
#include <script/standard.h>
|
#include <script/standard.h>
|
||||||
#include <serialize.h>
|
#include <serialize.h>
|
||||||
#include <streams.h>
|
#include <streams.h>
|
||||||
|
#include <undo.h>
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
#include <util/check.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
|
|
||||||
@ -177,7 +179,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
|
|||||||
out.pushKV("addresses", a);
|
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("txid", tx.GetHash().GetHex());
|
||||||
entry.pushKV("hash", tx.GetWitnessHash().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("weight", GetTransactionWeight(tx));
|
||||||
entry.pushKV("locktime", (int64_t)tx.nLockTime);
|
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++) {
|
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||||
const CTxIn& txin = tx.vin[i];
|
const CTxIn& txin = tx.vin[i];
|
||||||
UniValue in(UniValue::VOBJ);
|
UniValue in(UniValue::VOBJ);
|
||||||
if (tx.IsCoinBase())
|
if (tx.IsCoinBase()) {
|
||||||
in.pushKV("coinbase", HexStr(txin.scriptSig));
|
in.pushKV("coinbase", HexStr(txin.scriptSig));
|
||||||
else {
|
} else {
|
||||||
in.pushKV("txid", txin.prevout.hash.GetHex());
|
in.pushKV("txid", txin.prevout.hash.GetHex());
|
||||||
in.pushKV("vout", (int64_t)txin.prevout.n);
|
in.pushKV("vout", (int64_t)txin.prevout.n);
|
||||||
UniValue o(UniValue::VOBJ);
|
UniValue o(UniValue::VOBJ);
|
||||||
@ -210,6 +219,10 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
|
|||||||
}
|
}
|
||||||
in.pushKV("txinwitness", txinwitness);
|
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);
|
in.pushKV("sequence", (int64_t)txin.nSequence);
|
||||||
vin.push_back(in);
|
vin.push_back(in);
|
||||||
}
|
}
|
||||||
@ -228,9 +241,19 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
|
|||||||
ScriptPubKeyToUniv(txout.scriptPubKey, o, true);
|
ScriptPubKeyToUniv(txout.scriptPubKey, o, true);
|
||||||
out.pushKV("scriptPubKey", o);
|
out.pushKV("scriptPubKey", o);
|
||||||
vout.push_back(out);
|
vout.push_back(out);
|
||||||
|
|
||||||
|
if (calculate_fee) {
|
||||||
|
amt_total_out += txout.nValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
entry.pushKV("vout", vout);
|
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())
|
if (!hashBlock.IsNull())
|
||||||
entry.pushKV("blockhash", hashBlock.GetHex());
|
entry.pushKV("blockhash", hashBlock.GetHex());
|
||||||
|
|
||||||
|
@ -162,17 +162,22 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
|
|||||||
result.pushKV("versionHex", strprintf("%08x", block.nVersion));
|
result.pushKV("versionHex", strprintf("%08x", block.nVersion));
|
||||||
result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
|
result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
|
||||||
UniValue txs(UniValue::VARR);
|
UniValue txs(UniValue::VARR);
|
||||||
for(const auto& tx : block.vtx)
|
if (txDetails) {
|
||||||
{
|
CBlockUndo blockUndo;
|
||||||
if(txDetails)
|
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);
|
UniValue objTx(UniValue::VOBJ);
|
||||||
TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags());
|
TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags(), txundo);
|
||||||
txs.push_back(objTx);
|
txs.push_back(objTx);
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
|
for (const CTransactionRef& tx : block.vtx) {
|
||||||
txs.push_back(tx->GetHash().GetHex());
|
txs.push_back(tx->GetHash().GetHex());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
result.pushKV("tx", txs);
|
result.pushKV("tx", txs);
|
||||||
result.pushKV("time", block.GetBlockTime());
|
result.pushKV("time", block.GetBlockTime());
|
||||||
result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
|
result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
|
||||||
@ -926,6 +931,7 @@ static RPCHelpMan getblock()
|
|||||||
{RPCResult::Type::OBJ, "", "",
|
{RPCResult::Type::OBJ, "", "",
|
||||||
{
|
{
|
||||||
{RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"},
|
{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"},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
{RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
|
{RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
|
||||||
|
Reference in New Issue
Block a user