mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-24 10:17:45 -03:00
Compare commits
6 commits
bb68bce6aa
...
d79e1a6b5b
Author | SHA1 | Date | |
---|---|---|---|
|
d79e1a6b5b | ||
|
66aa6a47bd | ||
|
7c123c08dd | ||
|
72ec388244 | ||
|
ff9d484876 | ||
|
5658c51871 |
13 changed files with 54 additions and 28 deletions
|
@ -26,7 +26,7 @@
|
|||
* A UTXO entry.
|
||||
*
|
||||
* Serialized format:
|
||||
* - VARINT((coinbase ? 1 : 0) | (height << 1))
|
||||
* - VARINT((height << 1) | (coinbase ? 1 : 0))
|
||||
* - the non-spent CTxOut (via TxOutCompression)
|
||||
*/
|
||||
class Coin
|
||||
|
@ -36,7 +36,7 @@ public:
|
|||
CTxOut out;
|
||||
|
||||
//! whether containing transaction was a coinbase
|
||||
unsigned int fCoinBase : 1;
|
||||
bool fCoinBase : 1;
|
||||
|
||||
//! at which height this containing transaction was included in the active block chain
|
||||
uint32_t nHeight : 31;
|
||||
|
@ -61,7 +61,7 @@ public:
|
|||
template<typename Stream>
|
||||
void Serialize(Stream &s) const {
|
||||
assert(!IsSpent());
|
||||
uint32_t code = nHeight * uint32_t{2} + fCoinBase;
|
||||
uint32_t code{static_cast<uint32_t>(nHeight << 1) | fCoinBase};
|
||||
::Serialize(s, VARINT(code));
|
||||
::Serialize(s, Using<TxOutCompression>(out));
|
||||
}
|
||||
|
|
|
@ -219,7 +219,7 @@ void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry
|
|||
ScriptToUniv(prev_txout.scriptPubKey, /*out=*/o_script_pub_key, /*include_hex=*/true, /*include_address=*/true);
|
||||
|
||||
UniValue p(UniValue::VOBJ);
|
||||
p.pushKV("generated", bool(prev_coin.fCoinBase));
|
||||
p.pushKV("generated", prev_coin.IsCoinBase());
|
||||
p.pushKV("height", uint64_t(prev_coin.nHeight));
|
||||
p.pushKV("value", ValueFromAmount(prev_txout.nValue));
|
||||
p.pushKV("scriptPubKey", std::move(o_script_pub_key));
|
||||
|
|
|
@ -51,7 +51,7 @@ template <typename T>
|
|||
static void TxOutSer(T& ss, const COutPoint& outpoint, const Coin& coin)
|
||||
{
|
||||
ss << outpoint;
|
||||
ss << static_cast<uint32_t>((coin.nHeight << 1) + coin.fCoinBase);
|
||||
ss << (static_cast<uint32_t>(coin.nHeight << 1) | coin.fCoinBase);
|
||||
ss << coin.out;
|
||||
}
|
||||
|
||||
|
|
|
@ -421,6 +421,7 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
|
|||
}
|
||||
|
||||
++nPackagesSelected;
|
||||
pblocktemplate->m_package_feerates.emplace_back(packageFees, static_cast<int32_t>(packageSize));
|
||||
|
||||
// Update transactions that depend on each of these
|
||||
nDescendantsUpdated += UpdatePackagesForAdded(mempool, ancestors, mapModifiedTx);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <policy/policy.h>
|
||||
#include <primitives/block.h>
|
||||
#include <txmempool.h>
|
||||
#include <util/feefrac.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
@ -39,6 +40,9 @@ struct CBlockTemplate
|
|||
std::vector<CAmount> vTxFees;
|
||||
std::vector<int64_t> vTxSigOpsCost;
|
||||
std::vector<unsigned char> vchCoinbaseCommitment;
|
||||
/* A vector of package fee rates, ordered by the sequence in which
|
||||
* packages are selected for inclusion in the block template.*/
|
||||
std::vector<FeeFrac> m_package_feerates;
|
||||
};
|
||||
|
||||
// Container for tracking updates to ancestor feerate as we include (parent)
|
||||
|
|
|
@ -1160,7 +1160,7 @@ static RPCHelpMan gettxout()
|
|||
UniValue o(UniValue::VOBJ);
|
||||
ScriptToUniv(coin->out.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true);
|
||||
ret.pushKV("scriptPubKey", std::move(o));
|
||||
ret.pushKV("coinbase", (bool)coin->fCoinBase);
|
||||
ret.pushKV("coinbase", coin->IsCoinBase());
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
@ -1834,8 +1834,8 @@ static inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&
|
|||
return (set.count(key) != 0) || SetHasKeys(set, args...);
|
||||
}
|
||||
|
||||
// outpoint (needed for the utxo index) + nHeight + fCoinBase
|
||||
static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
|
||||
// outpoint (needed for the utxo index) + nHeight|fCoinBase
|
||||
static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t);
|
||||
|
||||
static RPCHelpMan getblockstats()
|
||||
{
|
||||
|
|
|
@ -514,7 +514,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
|
|||
DataStream ss1{"97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"_hex};
|
||||
Coin cc1;
|
||||
ss1 >> cc1;
|
||||
BOOST_CHECK_EQUAL(cc1.fCoinBase, false);
|
||||
BOOST_CHECK_EQUAL(cc1.IsCoinBase(), false);
|
||||
BOOST_CHECK_EQUAL(cc1.nHeight, 203998U);
|
||||
BOOST_CHECK_EQUAL(cc1.out.nValue, CAmount{60000000000});
|
||||
BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("816115944e077fe7c803cfa57f29b36bf87c1d35"_hex_u8)))));
|
||||
|
@ -523,7 +523,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
|
|||
DataStream ss2{"8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex};
|
||||
Coin cc2;
|
||||
ss2 >> cc2;
|
||||
BOOST_CHECK_EQUAL(cc2.fCoinBase, true);
|
||||
BOOST_CHECK_EQUAL(cc2.IsCoinBase(), true);
|
||||
BOOST_CHECK_EQUAL(cc2.nHeight, 120891U);
|
||||
BOOST_CHECK_EQUAL(cc2.out.nValue, 110397);
|
||||
BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"_hex_u8)))));
|
||||
|
@ -532,7 +532,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
|
|||
DataStream ss3{"000006"_hex};
|
||||
Coin cc3;
|
||||
ss3 >> cc3;
|
||||
BOOST_CHECK_EQUAL(cc3.fCoinBase, false);
|
||||
BOOST_CHECK_EQUAL(cc3.IsCoinBase(), false);
|
||||
BOOST_CHECK_EQUAL(cc3.nHeight, 0U);
|
||||
BOOST_CHECK_EQUAL(cc3.out.nValue, 0);
|
||||
BOOST_CHECK_EQUAL(cc3.out.scriptPubKey.size(), 0U);
|
||||
|
@ -870,7 +870,7 @@ Coin MakeCoin()
|
|||
Coin coin;
|
||||
coin.out.nValue = m_rng.rand32();
|
||||
coin.nHeight = m_rng.randrange(4096);
|
||||
coin.fCoinBase = 0;
|
||||
coin.fCoinBase = false;
|
||||
return coin;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ void utxo_snapshot_fuzz(FuzzBufferType buffer)
|
|||
outfile << coinbase->GetHash();
|
||||
WriteCompactSize(outfile, 1); // number of coins for the hash
|
||||
WriteCompactSize(outfile, 0); // index of coin
|
||||
outfile << Coin(coinbase->vout[0], height, /*fCoinBaseIn=*/1);
|
||||
outfile << Coin(coinbase->vout[0], height, /*fCoinBaseIn=*/true);
|
||||
height++;
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ void utxo_snapshot_fuzz(FuzzBufferType buffer)
|
|||
outfile << coinbase->GetHash();
|
||||
WriteCompactSize(outfile, 1); // number of coins for the hash
|
||||
WriteCompactSize(outfile, 999); // index of coin
|
||||
outfile << Coin{coinbase->vout[0], /*nHeightIn=*/999, /*fCoinBaseIn=*/0};
|
||||
outfile << Coin{coinbase->vout[0], /*nHeightIn=*/999, /*fCoinBaseIn=*/false};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <txmempool.h>
|
||||
#include <uint256.h>
|
||||
#include <util/check.h>
|
||||
#include <util/feefrac.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/time.h>
|
||||
#include <util/translation.h>
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include <test/util/setup_common.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
|
@ -123,19 +125,22 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
|||
tx.vout[0].nValue = 5000000000LL - 1000;
|
||||
// This tx has a low fee: 1000 satoshis
|
||||
Txid hashParentTx = tx.GetHash(); // save this txid for later use
|
||||
AddToMempool(tx_mempool, entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
|
||||
const auto parent_tx{entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)};
|
||||
AddToMempool(tx_mempool, parent_tx);
|
||||
|
||||
// This tx has a medium fee: 10000 satoshis
|
||||
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
|
||||
tx.vout[0].nValue = 5000000000LL - 10000;
|
||||
Txid hashMediumFeeTx = tx.GetHash();
|
||||
AddToMempool(tx_mempool, entry.Fee(10000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
|
||||
const auto medium_fee_tx{entry.Fee(10000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx)};
|
||||
AddToMempool(tx_mempool, medium_fee_tx);
|
||||
|
||||
// This tx has a high fee, but depends on the first transaction
|
||||
tx.vin[0].prevout.hash = hashParentTx;
|
||||
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee
|
||||
Txid hashHighFeeTx = tx.GetHash();
|
||||
AddToMempool(tx_mempool, entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
|
||||
const auto high_fee_tx{entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)};
|
||||
AddToMempool(tx_mempool, high_fee_tx);
|
||||
|
||||
std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options);
|
||||
BOOST_REQUIRE(block_template);
|
||||
|
@ -145,6 +150,21 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
|||
BOOST_CHECK(block.vtx[2]->GetHash() == hashHighFeeTx);
|
||||
BOOST_CHECK(block.vtx[3]->GetHash() == hashMediumFeeTx);
|
||||
|
||||
// Test the inclusion of package feerates in the block template and ensure they are sequential.
|
||||
const auto block_package_feerates = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock()->m_package_feerates;
|
||||
BOOST_CHECK(block_package_feerates.size() == 2);
|
||||
|
||||
// parent_tx and high_fee_tx are added to the block as a package.
|
||||
const auto combined_txs_fee = parent_tx.GetFee() + high_fee_tx.GetFee();
|
||||
const auto combined_txs_size = parent_tx.GetTxSize() + high_fee_tx.GetTxSize();
|
||||
FeeFrac package_feefrac{combined_txs_fee, combined_txs_size};
|
||||
// The package should be added first.
|
||||
BOOST_CHECK(block_package_feerates[0] == package_feefrac);
|
||||
|
||||
// The medium_fee_tx should be added next.
|
||||
FeeFrac medium_tx_feefrac{medium_fee_tx.GetFee(), medium_fee_tx.GetTxSize()};
|
||||
BOOST_CHECK(block_package_feerates[1] == medium_tx_feefrac);
|
||||
|
||||
// Test that a package below the block min tx fee doesn't get included
|
||||
tx.vin[0].prevout.hash = hashHighFeeTx;
|
||||
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee
|
||||
|
|
|
@ -23,7 +23,8 @@ struct TxInUndoFormatter
|
|||
{
|
||||
template<typename Stream>
|
||||
void Ser(Stream &s, const Coin& txout) {
|
||||
::Serialize(s, VARINT(txout.nHeight * uint32_t{2} + txout.fCoinBase ));
|
||||
uint32_t nCode{static_cast<uint32_t>(txout.nHeight << 1) | txout.fCoinBase};
|
||||
::Serialize(s, VARINT(nCode));
|
||||
if (txout.nHeight > 0) {
|
||||
// Required to maintain compatibility with older undo format.
|
||||
::Serialize(s, (unsigned char)0);
|
||||
|
|
|
@ -2334,7 +2334,7 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
|
|||
COutPoint out(hash, o);
|
||||
Coin coin;
|
||||
bool is_spent = view.SpendCoin(out, &coin);
|
||||
if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) {
|
||||
if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.IsCoinBase()) {
|
||||
if (!is_bip30_exception) {
|
||||
fClean = false; // transaction output mismatch
|
||||
}
|
||||
|
|
|
@ -143,8 +143,8 @@
|
|||
"txs": 1,
|
||||
"utxo_increase": 2,
|
||||
"utxo_increase_actual": 1,
|
||||
"utxo_size_inc": 163,
|
||||
"utxo_size_inc_actual": 75
|
||||
"utxo_size_inc": 161,
|
||||
"utxo_size_inc_actual": 74
|
||||
},
|
||||
{
|
||||
"avgfee": 4440,
|
||||
|
@ -182,8 +182,8 @@
|
|||
"txs": 2,
|
||||
"utxo_increase": 3,
|
||||
"utxo_increase_actual": 2,
|
||||
"utxo_size_inc": 235,
|
||||
"utxo_size_inc_actual": 147
|
||||
"utxo_size_inc": 232,
|
||||
"utxo_size_inc_actual": 145
|
||||
},
|
||||
{
|
||||
"avgfee": 21390,
|
||||
|
@ -221,8 +221,8 @@
|
|||
"txs": 5,
|
||||
"utxo_increase": 6,
|
||||
"utxo_increase_actual": 4,
|
||||
"utxo_size_inc": 441,
|
||||
"utxo_size_inc_actual": 300
|
||||
"utxo_size_inc": 435,
|
||||
"utxo_size_inc_actual": 296
|
||||
}
|
||||
]
|
||||
}
|
|
@ -171,16 +171,16 @@ class GetblockstatsTest(BitcoinTestFramework):
|
|||
genesis_stats = self.nodes[0].getblockstats(0)
|
||||
assert_equal(genesis_stats["blockhash"], "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")
|
||||
assert_equal(genesis_stats["utxo_increase"], 1)
|
||||
assert_equal(genesis_stats["utxo_size_inc"], 117)
|
||||
assert_equal(genesis_stats["utxo_size_inc"], 116)
|
||||
assert_equal(genesis_stats["utxo_increase_actual"], 0)
|
||||
assert_equal(genesis_stats["utxo_size_inc_actual"], 0)
|
||||
|
||||
self.log.info('Test tip including OP_RETURN')
|
||||
tip_stats = self.nodes[0].getblockstats(tip)
|
||||
assert_equal(tip_stats["utxo_increase"], 6)
|
||||
assert_equal(tip_stats["utxo_size_inc"], 441)
|
||||
assert_equal(tip_stats["utxo_size_inc"], 435)
|
||||
assert_equal(tip_stats["utxo_increase_actual"], 4)
|
||||
assert_equal(tip_stats["utxo_size_inc_actual"], 300)
|
||||
assert_equal(tip_stats["utxo_size_inc_actual"], 296)
|
||||
|
||||
self.log.info("Test when only header is known")
|
||||
block = self.generateblock(self.nodes[0], output="raw(55)", transactions=[], submit=False)
|
||||
|
|
Loading…
Add table
Reference in a new issue