mirror of
https://github.com/dashpay/dash.git
synced 2024-12-28 05:23:01 +01:00
Switch from per-tx to per-txout CCoinsViewCache methods in some places
This commit is contained in:
parent
0003911326
commit
f68cdfe92b
@ -35,14 +35,14 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
|
|||||||
dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
|
dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
|
||||||
dummyTransactions[0].vout[1].nValue = 50 * CENT;
|
dummyTransactions[0].vout[1].nValue = 50 * CENT;
|
||||||
dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
|
dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
|
||||||
coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0);
|
AddCoins(coinsRet, dummyTransactions[0], 0);
|
||||||
|
|
||||||
dummyTransactions[1].vout.resize(2);
|
dummyTransactions[1].vout.resize(2);
|
||||||
dummyTransactions[1].vout[0].nValue = 21 * CENT;
|
dummyTransactions[1].vout[0].nValue = 21 * CENT;
|
||||||
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
|
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
|
||||||
dummyTransactions[1].vout[1].nValue = 22 * CENT;
|
dummyTransactions[1].vout[1].nValue = 22 * CENT;
|
||||||
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
|
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
|
||||||
coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0);
|
AddCoins(coinsRet, dummyTransactions[1], 0);
|
||||||
|
|
||||||
return dummyTransactions;
|
return dummyTransactions;
|
||||||
}
|
}
|
||||||
|
@ -556,24 +556,26 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
|
|||||||
if (nOut < 0)
|
if (nOut < 0)
|
||||||
throw std::runtime_error("vout must be positive");
|
throw std::runtime_error("vout must be positive");
|
||||||
|
|
||||||
|
COutPoint out(txid, nOut);
|
||||||
std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
|
std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
|
||||||
CScript scriptPubKey(pkData.begin(), pkData.end());
|
CScript scriptPubKey(pkData.begin(), pkData.end());
|
||||||
|
|
||||||
{
|
{
|
||||||
CCoinsModifier coins = view.ModifyCoins(txid);
|
const Coin& coin = view.AccessCoin(out);
|
||||||
if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
|
if (!coin.IsPruned() && coin.out.scriptPubKey != scriptPubKey) {
|
||||||
std::string err("Previous output scriptPubKey mismatch:\n");
|
std::string err("Previous output scriptPubKey mismatch:\n");
|
||||||
err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
|
err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
|
||||||
ScriptToAsmStr(scriptPubKey);
|
ScriptToAsmStr(scriptPubKey);
|
||||||
throw std::runtime_error(err);
|
throw std::runtime_error(err);
|
||||||
}
|
}
|
||||||
if ((unsigned int)nOut >= coins->vout.size())
|
Coin newcoin;
|
||||||
coins->vout.resize(nOut+1);
|
newcoin.out.scriptPubKey = scriptPubKey;
|
||||||
coins->vout[nOut].scriptPubKey = scriptPubKey;
|
newcoin.out.nValue = 0;
|
||||||
coins->vout[nOut].nValue = 0;
|
|
||||||
if (prevOut.exists("amount")) {
|
if (prevOut.exists("amount")) {
|
||||||
coins->vout[nOut].nValue = AmountFromValue(prevOut["amount"]);
|
newcoin.out.nValue = AmountFromValue(prevOut["amount"]);
|
||||||
}
|
}
|
||||||
|
newcoin.nHeight = 1;
|
||||||
|
view.AddCoin(out, std::move(newcoin), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if redeemScript given and private keys given,
|
// if redeemScript given and private keys given,
|
||||||
@ -595,13 +597,13 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
|
|||||||
// Sign what we can:
|
// Sign what we can:
|
||||||
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
|
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
|
||||||
CTxIn& txin = mergedTx.vin[i];
|
CTxIn& txin = mergedTx.vin[i];
|
||||||
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
|
const Coin& coin = view.AccessCoin(txin.prevout);
|
||||||
if (!coins || !coins->IsAvailable(txin.prevout.n)) {
|
if (coin.IsPruned()) {
|
||||||
fComplete = false;
|
fComplete = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
|
const CScript& prevPubKey = coin.out.scriptPubKey;
|
||||||
const CAmount& amount = coins->vout[txin.prevout.n].nValue;
|
const CAmount& amount = coin.out.nValue;
|
||||||
|
|
||||||
SignatureData sigdata;
|
SignatureData sigdata;
|
||||||
// Only sign SIGHASH_SINGLE if there's a corresponding output:
|
// Only sign SIGHASH_SINGLE if there's a corresponding output:
|
||||||
|
@ -213,20 +213,20 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
|
|||||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||||
{
|
{
|
||||||
const COutPoint &prevout = tx.vin[i].prevout;
|
const COutPoint &prevout = tx.vin[i].prevout;
|
||||||
const CCoins *coins = inputs.AccessCoins(prevout.hash);
|
const Coin& coin = inputs.AccessCoin(prevout);
|
||||||
assert(coins);
|
assert(!coin.IsPruned());
|
||||||
|
|
||||||
// If prev is coinbase, check that it's matured
|
// If prev is coinbase, check that it's matured
|
||||||
if (coins->IsCoinBase()) {
|
if (coin.IsCoinBase()) {
|
||||||
if (nSpendHeight - coins->nHeight < COINBASE_MATURITY)
|
if (nSpendHeight - coin.nHeight < COINBASE_MATURITY)
|
||||||
return state.Invalid(false,
|
return state.Invalid(false,
|
||||||
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase",
|
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase",
|
||||||
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight));
|
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for negative or overflow input values
|
// Check for negative or overflow input values
|
||||||
nValueIn += coins->vout[prevout.n].nValue;
|
nValueIn += coin.out.nValue;
|
||||||
if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn))
|
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn))
|
||||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
|
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -637,9 +637,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
|
|||||||
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
|
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
|
||||||
|
|
||||||
BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
|
BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
|
||||||
const uint256& prevHash = txin.prevout.hash;
|
view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail.
|
||||||
CCoins coins;
|
|
||||||
view.AccessCoins(prevHash); // this is certainly allowed to fail
|
|
||||||
}
|
}
|
||||||
|
|
||||||
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
|
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
|
||||||
@ -691,24 +689,26 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
|
|||||||
if (nOut < 0)
|
if (nOut < 0)
|
||||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
|
||||||
|
|
||||||
|
COutPoint out(txid, nOut);
|
||||||
std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
|
std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
|
||||||
CScript scriptPubKey(pkData.begin(), pkData.end());
|
CScript scriptPubKey(pkData.begin(), pkData.end());
|
||||||
|
|
||||||
{
|
{
|
||||||
CCoinsModifier coins = view.ModifyCoins(txid);
|
const Coin& coin = view.AccessCoin(out);
|
||||||
if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
|
if (!coin.IsPruned() && coin.out.scriptPubKey != scriptPubKey) {
|
||||||
std::string err("Previous output scriptPubKey mismatch:\n");
|
std::string err("Previous output scriptPubKey mismatch:\n");
|
||||||
err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
|
err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
|
||||||
ScriptToAsmStr(scriptPubKey);
|
ScriptToAsmStr(scriptPubKey);
|
||||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
|
||||||
}
|
}
|
||||||
if ((unsigned int)nOut >= coins->vout.size())
|
Coin newcoin;
|
||||||
coins->vout.resize(nOut+1);
|
newcoin.out.scriptPubKey = scriptPubKey;
|
||||||
coins->vout[nOut].scriptPubKey = scriptPubKey;
|
newcoin.out.nValue = 0;
|
||||||
coins->vout[nOut].nValue = 0;
|
|
||||||
if (prevOut.exists("amount")) {
|
if (prevOut.exists("amount")) {
|
||||||
coins->vout[nOut].nValue = AmountFromValue(find_value(prevOut, "amount"));
|
newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
|
||||||
}
|
}
|
||||||
|
newcoin.nHeight = 1;
|
||||||
|
view.AddCoin(out, std::move(newcoin), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if redeemScript given and not using the local wallet (private keys
|
// if redeemScript given and not using the local wallet (private keys
|
||||||
@ -766,13 +766,13 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
|
|||||||
// Sign what we can:
|
// Sign what we can:
|
||||||
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
|
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
|
||||||
CTxIn& txin = mergedTx.vin[i];
|
CTxIn& txin = mergedTx.vin[i];
|
||||||
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
|
const Coin& coin = view.AccessCoin(txin.prevout);
|
||||||
if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) {
|
if (coin.IsPruned()) {
|
||||||
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
|
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
|
const CScript& prevPubKey = coin.out.scriptPubKey;
|
||||||
const CAmount& amount = coins->vout[txin.prevout.n].nValue;
|
const CAmount& amount = coin.out.nValue;
|
||||||
|
|
||||||
SignatureData sigdata;
|
SignatureData sigdata;
|
||||||
// Only sign SIGHASH_SINGLE if there's a corresponding output:
|
// Only sign SIGHASH_SINGLE if there's a corresponding output:
|
||||||
@ -844,9 +844,12 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
|
|||||||
nMaxRawTxFee = 0;
|
nMaxRawTxFee = 0;
|
||||||
|
|
||||||
CCoinsViewCache &view = *pcoinsTip;
|
CCoinsViewCache &view = *pcoinsTip;
|
||||||
const CCoins* existingCoins = view.AccessCoins(hashTx);
|
bool fHaveChain = false;
|
||||||
|
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
|
||||||
|
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
|
||||||
|
fHaveChain = !existingCoin.IsPruned();
|
||||||
|
}
|
||||||
bool fHaveMempool = mempool.exists(hashTx);
|
bool fHaveMempool = mempool.exists(hashTx);
|
||||||
bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000;
|
|
||||||
if (!fHaveMempool && !fHaveChain) {
|
if (!fHaveMempool && !fHaveChain) {
|
||||||
// push to local node and sync with wallets
|
// push to local node and sync with wallets
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
|
@ -316,7 +316,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
|||||||
txFrom.vout[6].scriptPubKey = GetScriptForDestination(CScriptID(twentySigops));
|
txFrom.vout[6].scriptPubKey = GetScriptForDestination(CScriptID(twentySigops));
|
||||||
txFrom.vout[6].nValue = 6000;
|
txFrom.vout[6].nValue = 6000;
|
||||||
|
|
||||||
coins.ModifyCoins(txFrom.GetHash())->FromTx(txFrom, 0);
|
AddCoins(coins, txFrom, 0);
|
||||||
|
|
||||||
CMutableTransaction txTo;
|
CMutableTransaction txTo;
|
||||||
txTo.vout.resize(1);
|
txTo.vout.resize(1);
|
||||||
|
@ -102,7 +102,7 @@ void BuildTxs(CMutableTransaction& spendingTx, CCoinsViewCache& coins, CMutableT
|
|||||||
spendingTx.vout[0].nValue = 1;
|
spendingTx.vout[0].nValue = 1;
|
||||||
spendingTx.vout[0].scriptPubKey = CScript();
|
spendingTx.vout[0].scriptPubKey = CScript();
|
||||||
|
|
||||||
coins.ModifyCoins(creationTx.GetHash())->FromTx(creationTx, 0);
|
AddCoins(coins, creationTx, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
|
BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
|
||||||
|
@ -307,14 +307,14 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
|
|||||||
dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
|
dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
|
||||||
dummyTransactions[0].vout[1].nValue = 50*CENT;
|
dummyTransactions[0].vout[1].nValue = 50*CENT;
|
||||||
dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
|
dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
|
||||||
coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0);
|
AddCoins(coinsRet, dummyTransactions[0], 0);
|
||||||
|
|
||||||
dummyTransactions[1].vout.resize(2);
|
dummyTransactions[1].vout.resize(2);
|
||||||
dummyTransactions[1].vout[0].nValue = 21*CENT;
|
dummyTransactions[1].vout[0].nValue = 21*CENT;
|
||||||
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
|
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
|
||||||
dummyTransactions[1].vout[1].nValue = 22*CENT;
|
dummyTransactions[1].vout[1].nValue = 22*CENT;
|
||||||
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
|
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
|
||||||
coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0);
|
AddCoins(coinsRet, dummyTransactions[1], 0);
|
||||||
|
|
||||||
return dummyTransactions;
|
return dummyTransactions;
|
||||||
}
|
}
|
||||||
|
@ -498,8 +498,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||||||
// during reorgs to ensure COINBASE_MATURITY is still met.
|
// during reorgs to ensure COINBASE_MATURITY is still met.
|
||||||
bool fSpendsCoinbase = false;
|
bool fSpendsCoinbase = false;
|
||||||
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
|
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
|
||||||
const CCoins *coins = view.AccessCoins(txin.prevout.hash);
|
const Coin &coin = view.AccessCoin(txin.prevout);
|
||||||
if (coins->IsCoinBase()) {
|
if (coin.IsCoinBase()) {
|
||||||
fSpendsCoinbase = true;
|
fSpendsCoinbase = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -818,15 +818,8 @@ bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
|
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
|
||||||
int nHeight = -1;
|
const Coin& coin = AccessByTxid(*pcoinsTip, hash);
|
||||||
{
|
if (!coin.IsPruned()) pindexSlow = chainActive[coin.nHeight];
|
||||||
const CCoinsViewCache& view = *pcoinsTip;
|
|
||||||
const CCoins* coins = view.AccessCoins(hash);
|
|
||||||
if (coins)
|
|
||||||
nHeight = coins->nHeight;
|
|
||||||
}
|
|
||||||
if (nHeight > 0)
|
|
||||||
pindexSlow = chainActive[nHeight];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pindexSlow) {
|
if (pindexSlow) {
|
||||||
@ -1074,19 +1067,12 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
|
|||||||
if (!tx.IsCoinBase()) {
|
if (!tx.IsCoinBase()) {
|
||||||
txundo.vprevout.reserve(tx.vin.size());
|
txundo.vprevout.reserve(tx.vin.size());
|
||||||
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
|
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
|
||||||
CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash);
|
txundo.vprevout.emplace_back();
|
||||||
unsigned nPos = txin.prevout.n;
|
inputs.SpendCoin(txin.prevout, &txundo.vprevout.back());
|
||||||
|
|
||||||
if (nPos >= coins->vout.size() || coins->vout[nPos].IsNull())
|
|
||||||
assert(false);
|
|
||||||
// mark an outpoint spent, and construct undo information
|
|
||||||
txundo.vprevout.emplace_back(coins->vout[nPos], coins->nHeight, coins->fCoinBase);
|
|
||||||
bool ret = coins->Spend(nPos);
|
|
||||||
assert(ret);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// add outputs
|
// add outputs
|
||||||
inputs.ModifyNewCoins(tx.GetHash(), tx.IsCoinBase())->FromTx(tx, nHeight);
|
AddCoins(inputs, tx, nHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
|
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
|
||||||
@ -1260,24 +1246,21 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
|
|||||||
{
|
{
|
||||||
bool fClean = true;
|
bool fClean = true;
|
||||||
|
|
||||||
CCoinsModifier coins = view.ModifyCoins(out.hash);
|
if (view.HaveCoins(out)) fClean = false; // overwriting transaction output
|
||||||
if (undo.nHeight != 0) {
|
|
||||||
if (!coins->IsPruned()) {
|
if (undo.nHeight == 0) {
|
||||||
if (coins->fCoinBase != undo.fCoinBase || (uint32_t)coins->nHeight != undo.nHeight) fClean = false; // metadata mismatch
|
// Missing undo metadata (height and coinbase). Older versions included this
|
||||||
}
|
// information only in undo records for the last spend of a transactions'
|
||||||
// restore height/coinbase tx metadata from undo data
|
// outputs. This implies that it must be present for some other output of the same tx.
|
||||||
coins->fCoinBase = undo.fCoinBase;
|
const Coin& alternate = AccessByTxid(view, out.hash);
|
||||||
coins->nHeight = undo.nHeight;
|
if (!alternate.IsPruned()) {
|
||||||
|
undo.nHeight = alternate.nHeight;
|
||||||
|
undo.fCoinBase = alternate.fCoinBase;
|
||||||
} else {
|
} else {
|
||||||
// Undo data does not contain height/coinbase. This should never happen
|
return DISCONNECT_FAILED; // adding output for transaction without known metadata
|
||||||
// for newly created undo entries. Previously, this data was only saved
|
|
||||||
// for the last spend of a transaction's outputs, so check IsPruned().
|
|
||||||
if (coins->IsPruned()) fClean = false; // adding output to missing transaction
|
|
||||||
}
|
}
|
||||||
if (coins->IsAvailable(out.n)) fClean = false; // overwriting existing output
|
}
|
||||||
if (coins->vout.size() < out.n+1)
|
view.AddCoin(out, std::move(undo), undo.fCoinBase);
|
||||||
coins->vout.resize(out.n+1);
|
|
||||||
coins->vout[out.n] = std::move(undo.out);
|
|
||||||
|
|
||||||
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
|
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
|
||||||
}
|
}
|
||||||
@ -1313,15 +1296,15 @@ static DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex*
|
|||||||
|
|
||||||
// Check that all outputs are available and match the outputs in the block itself
|
// Check that all outputs are available and match the outputs in the block itself
|
||||||
// exactly.
|
// exactly.
|
||||||
{
|
for (size_t o = 0; o < tx.vout.size(); o++) {
|
||||||
CCoinsModifier outs = view.ModifyCoins(hash);
|
if (!tx.vout[o].scriptPubKey.IsUnspendable()) {
|
||||||
outs->ClearUnspendable();
|
COutPoint out(hash, o);
|
||||||
|
Coin coin;
|
||||||
CCoins outsBlock(tx, pindex->nHeight);
|
view.SpendCoin(out, &coin);
|
||||||
if (*outs != outsBlock) fClean = false; // transaction mismatch
|
if (tx.vout[o] != coin.out) {
|
||||||
|
fClean = false; // transaction output mismatch
|
||||||
// remove outputs
|
}
|
||||||
outs->Clear();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore inputs
|
// restore inputs
|
||||||
@ -1518,12 +1501,14 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
|
|||||||
|
|
||||||
if (fEnforceBIP30) {
|
if (fEnforceBIP30) {
|
||||||
for (const auto& tx : block.vtx) {
|
for (const auto& tx : block.vtx) {
|
||||||
const CCoins* coins = view.AccessCoins(tx->GetHash());
|
for (size_t o = 0; o < tx->vout.size(); o++) {
|
||||||
if (coins && !coins->IsPruned())
|
if (view.HaveCoins(COutPoint(tx->GetHash(), o))) {
|
||||||
return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"),
|
return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"),
|
||||||
REJECT_INVALID, "bad-txns-BIP30");
|
REJECT_INVALID, "bad-txns-BIP30");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// BIP16 didn't become active until Apr 1 2012
|
// BIP16 didn't become active until Apr 1 2012
|
||||||
int64_t nBIP16SwitchTime = 1333238400;
|
int64_t nBIP16SwitchTime = 1333238400;
|
||||||
@ -1588,7 +1573,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
|
|||||||
// be in ConnectBlock because they require the UTXO set
|
// be in ConnectBlock because they require the UTXO set
|
||||||
prevheights.resize(tx.vin.size());
|
prevheights.resize(tx.vin.size());
|
||||||
for (size_t j = 0; j < tx.vin.size(); j++) {
|
for (size_t j = 0; j < tx.vin.size(); j++) {
|
||||||
prevheights[j] = view.AccessCoins(tx.vin[j].prevout.hash)->nHeight;
|
prevheights[j] = view.AccessCoin(tx.vin[j].prevout).nHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) {
|
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user