mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-13 12:33:42 +02:00
Merge f656165e9c into merged_master (Bitcoin PR #18772)
I'm gonna be honest, I largely just rewrote this one. It adds a "fee" field to the RPC transaction output, which I replaced with a feemap which is directly extracted from the transaction rather than computed implicitly from inputs - outputs. Removed a functional test that fee computations become impossible without chain data, since in Elements there is no chain data lookup involved.
This commit is contained in:
commit
658b2312da
5 changed files with 77 additions and 11 deletions
|
|
@ -19,6 +19,7 @@ class CTransaction;
|
|||
struct CMutableTransaction;
|
||||
class uint256;
|
||||
class UniValue;
|
||||
class CTxUndo;
|
||||
|
||||
// core_read.cpp
|
||||
CScript ParseScript(const std::string& s);
|
||||
|
|
@ -47,6 +48,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
|
||||
|
|
|
|||
|
|
@ -13,7 +13,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>
|
||||
|
||||
|
|
@ -225,7 +227,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
|
|||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
|
@ -241,13 +243,14 @@ 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};
|
||||
|
||||
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);
|
||||
|
|
@ -317,6 +320,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
|
|||
}
|
||||
entry.pushKV("vin", vin);
|
||||
|
||||
CAmountMap fee_map{};
|
||||
UniValue vout(UniValue::VARR);
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
||||
const CTxOut& txout = tx.vout[i];
|
||||
|
|
@ -350,6 +354,10 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
|
|||
out.pushKV("valuecommitment", txout.nValue.GetHex());
|
||||
}
|
||||
if (g_con_elementsmode) {
|
||||
if (txout.IsFee()) {
|
||||
fee_map[txout.nAsset.GetAsset()] += txout.nValue.GetAmount();
|
||||
}
|
||||
|
||||
if (txout.nAsset.IsExplicit()) {
|
||||
out.pushKV("asset", txout.nAsset.GetAsset().GetHex());
|
||||
} else {
|
||||
|
|
@ -369,6 +377,19 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
|
|||
}
|
||||
entry.pushKV("vout", vout);
|
||||
|
||||
// ELEMENTS: add fee map rather than single fee. Unlike other areas of the RPC,
|
||||
// we do not look up labels here and will always use the asset hex (contrast
|
||||
// `AmountMapToUniv` in rpc/util.cpp. This is because this is a pure function
|
||||
// so we do not have access to `policyAsset` or `gAssetsDir`. (We will get link
|
||||
// errors if we try to use these.)
|
||||
if (g_con_elementsmode) {
|
||||
UniValue fee_obj(UniValue::VOBJ);
|
||||
for(std::map<CAsset, CAmount>::const_iterator it = fee_map.begin(); it != fee_map.end(); ++it) {
|
||||
fee_obj.pushKV(it->first.GetHex(), ValueFromAmount(it->second));
|
||||
}
|
||||
entry.pushKV("fee", fee_obj);
|
||||
}
|
||||
|
||||
if (!hashBlock.IsNull())
|
||||
entry.pushKV("blockhash", hashBlock.GetHex());
|
||||
|
||||
|
|
|
|||
|
|
@ -203,16 +203,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());
|
||||
|
|
@ -1015,6 +1020,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"},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ Tests correspond to code in rpc/blockchain.cpp.
|
|||
"""
|
||||
from decimal import Decimal
|
||||
import http.client
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from test_framework.blocktools import (
|
||||
|
|
@ -36,7 +37,9 @@ from test_framework.util import (
|
|||
assert_raises,
|
||||
assert_raises_rpc_error,
|
||||
assert_is_hash_string,
|
||||
get_datadir_path,
|
||||
)
|
||||
from test_framework.wallet import MiniWallet
|
||||
|
||||
|
||||
class BlockchainTest(BitcoinTestFramework):
|
||||
|
|
@ -55,6 +58,7 @@ class BlockchainTest(BitcoinTestFramework):
|
|||
self._test_getblockheader()
|
||||
self._test_stopatheight()
|
||||
self._test_waitforblockheight()
|
||||
self._test_getblock()
|
||||
assert self.nodes[0].verifychain(4, 0)
|
||||
|
||||
def mine_chain(self):
|
||||
|
|
@ -348,6 +352,38 @@ class BlockchainTest(BitcoinTestFramework):
|
|||
assert_waitforheight(current_height)
|
||||
assert_waitforheight(current_height + 1)
|
||||
|
||||
def _test_getblock(self):
|
||||
node = self.nodes[0]
|
||||
|
||||
miniwallet = MiniWallet(node)
|
||||
miniwallet.generate(5)
|
||||
node.generate(100)
|
||||
|
||||
fee_per_byte = Decimal('0.00000010')
|
||||
fee_per_kb = 1000 * fee_per_byte
|
||||
|
||||
miniwallet.send_self_transfer(fee_rate=fee_per_kb, from_node=node)
|
||||
blockhash = node.generate(1)[0]
|
||||
|
||||
self.log.info("Test that getblock with verbosity 1 doesn't include fee")
|
||||
block = node.getblock(blockhash, 1)
|
||||
assert 'fee' not in block['tx'][1]
|
||||
|
||||
self.log.info('Test that getblock with verbosity 2 includes expected fee')
|
||||
block = node.getblock(blockhash, 2)
|
||||
tx = block['tx'][1]
|
||||
assert 'fee' in tx
|
||||
asset_hex = node.getsidechaininfo()['pegged_asset']
|
||||
assert_equal(tx['fee'], { asset_hex: tx['vsize'] * fee_per_byte })
|
||||
|
||||
self.log.info("Test that getblock with verbosity 2 still works with pruned Undo data")
|
||||
datadir = get_datadir_path(self.options.tmpdir, 0)
|
||||
|
||||
def move_block_file(old, new):
|
||||
old_path = os.path.join(datadir, self.chain, 'blocks', old)
|
||||
new_path = os.path.join(datadir, self.chain, 'blocks', new)
|
||||
os.rename(old_path, new_path)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
BlockchainTest().main()
|
||||
|
|
|
|||
|
|
@ -28,5 +28,7 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"fee": {
|
||||
},
|
||||
"hex": "01000000000001010000000000000000000000000000000000000000000000000000000000000000010000000005f5e1000017a9146edf12858999f0dae74f9c692e6694ee3621b2ac8700000000"
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue