MWEB: Pegout maturity
This commit is contained in:
parent
3e70891275
commit
9a9dfec9ac
@ -109,10 +109,13 @@ void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool
|
||||
bool fCoinbase = tx.IsCoinBase();
|
||||
const uint256& txid = tx.GetHash();
|
||||
for (size_t i = 0; i < tx.vout.size(); ++i) {
|
||||
// MWEB: The first output in the HogEx transaction is the HogAddr.
|
||||
// The HogAddr is always spent in the next HogEx, so should not be subjected to pegout maturity rules.
|
||||
bool fPegout = tx.IsHogEx() && i > 0;
|
||||
bool overwrite = check_for_overwrite ? cache.HaveCoin(COutPoint(txid, i)) : fCoinbase;
|
||||
// Coinbase transactions can always be overwritten, in order to correctly
|
||||
// deal with the pre-BIP30 occurrences of duplicate coinbase transactions.
|
||||
cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), overwrite);
|
||||
cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase, fPegout), overwrite);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
19
src/coins.h
19
src/coins.h
@ -40,27 +40,35 @@ public:
|
||||
//! at which height this containing transaction was included in the active block chain
|
||||
uint32_t nHeight : 31;
|
||||
|
||||
//! whether output was a pegout from a hogex transaction
|
||||
bool fPegout;
|
||||
|
||||
//! construct a Coin from a CTxOut and height/coinbase information.
|
||||
Coin(CTxOut&& outIn, int nHeightIn, bool fCoinBaseIn) : out(std::move(outIn)), fCoinBase(fCoinBaseIn), nHeight(nHeightIn) {}
|
||||
Coin(const CTxOut& outIn, int nHeightIn, bool fCoinBaseIn) : out(outIn), fCoinBase(fCoinBaseIn),nHeight(nHeightIn) {}
|
||||
Coin(CTxOut&& outIn, int nHeightIn, bool fCoinBaseIn, bool fPegoutIn) : out(std::move(outIn)), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), fPegout(fPegoutIn) {}
|
||||
Coin(const CTxOut& outIn, int nHeightIn, bool fCoinBaseIn, bool fPegoutIn) : out(outIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), fPegout(fPegoutIn) {}
|
||||
|
||||
void Clear() {
|
||||
out.SetNull();
|
||||
fCoinBase = false;
|
||||
fPegout = false;
|
||||
nHeight = 0;
|
||||
}
|
||||
|
||||
//! empty constructor
|
||||
Coin() : fCoinBase(false), nHeight(0) { }
|
||||
Coin() : fCoinBase(false), nHeight(0), fPegout(false) {}
|
||||
|
||||
bool IsCoinBase() const {
|
||||
return fCoinBase;
|
||||
}
|
||||
|
||||
bool IsPegout() const {
|
||||
return fPegout;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream &s) const {
|
||||
assert(!IsSpent());
|
||||
uint32_t code = nHeight * uint32_t{2} + fCoinBase;
|
||||
uint32_t code = nHeight * uint32_t{2} + fCoinBase + (fPegout ? (uint32_t{1} << 31) : uint32_t{0});
|
||||
::Serialize(s, VARINT(code));
|
||||
::Serialize(s, Using<TxOutCompression>(out));
|
||||
}
|
||||
@ -69,7 +77,8 @@ public:
|
||||
void Unserialize(Stream &s) {
|
||||
uint32_t code = 0;
|
||||
::Unserialize(s, VARINT(code));
|
||||
nHeight = code >> 1;
|
||||
fPegout = code >> 31;
|
||||
nHeight = (code & ~(uint32_t{1} << 31)) >> 1;
|
||||
fCoinBase = code & 1;
|
||||
::Unserialize(s, Using<TxOutCompression>(out));
|
||||
}
|
||||
|
||||
@ -19,6 +19,8 @@ static const unsigned int MAX_BLOCK_WEIGHT = 4000000;
|
||||
static const int64_t MAX_BLOCK_SIGOPS_COST = 80000;
|
||||
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
|
||||
static const int COINBASE_MATURITY = 100;
|
||||
/** MWEB: Pegout transaction outputs can only be spent after this number of new blocks (network rule) */
|
||||
static const int PEGOUT_MATURITY = 6;
|
||||
|
||||
static const int WITNESS_SCALE_FACTOR = 4;
|
||||
|
||||
|
||||
@ -186,6 +186,12 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state,
|
||||
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
|
||||
}
|
||||
|
||||
// If coin is a pegout, check that it's matured
|
||||
if (coin.IsPegout() && nSpendHeight - coin.nHeight < PEGOUT_MATURITY) {
|
||||
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-pegout",
|
||||
strprintf("tried to spend pegout output at depth %d", nSpendHeight - coin.nHeight));
|
||||
}
|
||||
|
||||
// Check for negative or overflow input values
|
||||
nValueIn += coin.out.nValue;
|
||||
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
|
||||
|
||||
@ -93,9 +93,9 @@ BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
|
||||
|
||||
CBlockUndo block_undo;
|
||||
block_undo.vtxundo.emplace_back();
|
||||
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[3]), 1000, true);
|
||||
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(600, included_scripts[4]), 10000, false);
|
||||
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(700, excluded_scripts[3]), 100000, false);
|
||||
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[3]), 1000, true, false);
|
||||
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(600, included_scripts[4]), 10000, false, false);
|
||||
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(700, excluded_scripts[3]), 100000, false, false);
|
||||
|
||||
BlockFilter block_filter(BlockFilterType::BASIC, block, block_undo);
|
||||
const GCSFilter& filter = block_filter.GetFilter();
|
||||
@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test)
|
||||
for (unsigned int ii = 0; ii < prev_scripts.size(); ii++) {
|
||||
std::vector<unsigned char> raw_script = ParseHex(prev_scripts[ii].get_str());
|
||||
CTxOut txout(0, CScript(raw_script.begin(), raw_script.end()));
|
||||
tx_undo.vprevout.emplace_back(txout, 0, false);
|
||||
tx_undo.vprevout.emplace_back(txout, 0, false, false);
|
||||
}
|
||||
|
||||
uint256 prev_filter_header_basic;
|
||||
|
||||
@ -413,7 +413,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
|
||||
// Update the expected result to know about the new output coins
|
||||
assert(tx.vout.size() == 1);
|
||||
const COutPoint outpoint(tx.GetHash(), 0);
|
||||
result[outpoint] = Coin(tx.vout[0], height, CTransaction(tx).IsCoinBase());
|
||||
result[outpoint] = Coin(tx.vout[0], height, CTransaction(tx).IsCoinBase(), false);
|
||||
|
||||
// Call UpdateCoins on the top cache
|
||||
CTxUndo undo;
|
||||
@ -768,12 +768,13 @@ static void CheckAddCoinBase(CAmount base_value, CAmount cache_value, CAmount mo
|
||||
{
|
||||
SingleEntryCacheTest test(base_value, cache_value, cache_flags);
|
||||
|
||||
bool fPegout = false;
|
||||
CAmount result_value;
|
||||
char result_flags;
|
||||
try {
|
||||
CTxOut output;
|
||||
output.nValue = modify_value;
|
||||
test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase), coinbase);
|
||||
test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase, fPegout), coinbase);
|
||||
test.cache.SelfTest();
|
||||
GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
|
||||
} catch (std::logic_error&) {
|
||||
|
||||
@ -401,7 +401,7 @@ bool CCoinsViewDB::Upgrade() {
|
||||
COutPoint outpoint(key.second, 0);
|
||||
for (size_t i = 0; i < old_coins.vout.size(); ++i) {
|
||||
if (!old_coins.vout[i].IsNull() && !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
|
||||
Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase);
|
||||
Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase, false);
|
||||
outpoint.n = i;
|
||||
CoinEntry entry(&outpoint);
|
||||
batch.Write(entry, newcoin);
|
||||
|
||||
@ -528,6 +528,12 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
|
||||
txToRemove.insert(it);
|
||||
break;
|
||||
}
|
||||
|
||||
// MWEB: Remove pegout if immature
|
||||
if (coin.IsPegout() && ((signed long)nMemPoolHeight) - coin.nHeight < PEGOUT_MATURITY) {
|
||||
txToRemove.insert(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!validLP) {
|
||||
@ -917,7 +923,7 @@ bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const {
|
||||
CTransactionRef ptx = mempool.get(outpoint.hash);
|
||||
if (ptx) {
|
||||
if (outpoint.n < ptx->vout.size()) {
|
||||
coin = Coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false);
|
||||
coin = Coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false, ptx->mweb_tx.HasPegOut());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@ -720,7 +720,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
||||
bool fSpendsCoinbase = false;
|
||||
for (const CTxIn &txin : tx.vin) {
|
||||
const Coin &coin = m_view.AccessCoin(txin.prevout);
|
||||
if (coin.IsCoinBase()) {
|
||||
if (coin.IsCoinBase() || coin.IsPegout()) {
|
||||
fSpendsCoinbase = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user