|
|
|
@ -1682,9 +1682,9 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P
@@ -1682,9 +1682,9 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P
|
|
|
|
|
if (pindexSlow) { |
|
|
|
|
CBlock block; |
|
|
|
|
if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { |
|
|
|
|
BOOST_FOREACH(const CTransaction &tx, block.vtx) { |
|
|
|
|
if (tx.GetHash() == hash) { |
|
|
|
|
txOut = tx; |
|
|
|
|
for (const auto& tx : block.vtx) { |
|
|
|
|
if (tx->GetHash() == hash) { |
|
|
|
|
txOut = *tx; |
|
|
|
|
hashBlock = pindexSlow->GetBlockHash(); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
@ -2223,7 +2223,7 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
@@ -2223,7 +2223,7 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
|
|
|
|
|
|
|
|
|
|
// undo transactions in reverse order
|
|
|
|
|
for (int i = block.vtx.size() - 1; i >= 0; i--) { |
|
|
|
|
const CTransaction &tx = block.vtx[i]; |
|
|
|
|
const CTransaction &tx = *(block.vtx[i]); |
|
|
|
|
uint256 hash = tx.GetHash(); |
|
|
|
|
|
|
|
|
|
// Check that all outputs are available and match the outputs in the block itself
|
|
|
|
@ -2417,8 +2417,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
@@ -2417,8 +2417,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|
|
|
|
fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash)); |
|
|
|
|
|
|
|
|
|
if (fEnforceBIP30) { |
|
|
|
|
BOOST_FOREACH(const CTransaction& tx, block.vtx) { |
|
|
|
|
const CCoins* coins = view.AccessCoins(tx.GetHash()); |
|
|
|
|
for (const auto& tx : block.vtx) { |
|
|
|
|
const CCoins* coins = view.AccessCoins(tx->GetHash()); |
|
|
|
|
if (coins && !coins->IsPruned()) |
|
|
|
|
return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"), |
|
|
|
|
REJECT_INVALID, "bad-txns-BIP30"); |
|
|
|
@ -2474,7 +2474,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
@@ -2474,7 +2474,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|
|
|
|
txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
|
|
|
|
|
for (unsigned int i = 0; i < block.vtx.size(); i++) |
|
|
|
|
{ |
|
|
|
|
const CTransaction &tx = block.vtx[i]; |
|
|
|
|
const CTransaction &tx = *(block.vtx[i]); |
|
|
|
|
|
|
|
|
|
nInputs += tx.vin.size(); |
|
|
|
|
|
|
|
|
@ -2544,10 +2544,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
@@ -2544,10 +2544,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|
|
|
|
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001); |
|
|
|
|
|
|
|
|
|
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); |
|
|
|
|
if (block.vtx[0].GetValueOut() > blockReward) |
|
|
|
|
if (block.vtx[0]->GetValueOut() > blockReward) |
|
|
|
|
return state.DoS(100, |
|
|
|
|
error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", |
|
|
|
|
block.vtx[0].GetValueOut(), blockReward), |
|
|
|
|
block.vtx[0]->GetValueOut(), blockReward), |
|
|
|
|
REJECT_INVALID, "bad-cb-amount"); |
|
|
|
|
|
|
|
|
|
if (!control.Wait()) |
|
|
|
@ -2590,7 +2590,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
@@ -2590,7 +2590,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|
|
|
|
// Watch for changes to the previous coinbase transaction.
|
|
|
|
|
static uint256 hashPrevBestCoinBase; |
|
|
|
|
GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); |
|
|
|
|
hashPrevBestCoinBase = block.vtx[0].GetHash(); |
|
|
|
|
hashPrevBestCoinBase = block.vtx[0]->GetHash(); |
|
|
|
|
|
|
|
|
|
// Erase orphan transactions include or precluded by this block
|
|
|
|
|
if (vOrphanErase.size()) { |
|
|
|
@ -2807,7 +2807,8 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
@@ -2807,7 +2807,8 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
|
|
|
|
|
if (!fBare) { |
|
|
|
|
// Resurrect mempool transactions from the disconnected block.
|
|
|
|
|
std::vector<uint256> vHashUpdate; |
|
|
|
|
BOOST_FOREACH(const CTransaction &tx, block.vtx) { |
|
|
|
|
for (const auto& it : block.vtx) { |
|
|
|
|
const CTransaction& tx = *it; |
|
|
|
|
// ignore validation errors in resurrected transactions
|
|
|
|
|
CValidationState stateDummy; |
|
|
|
|
if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) { |
|
|
|
@ -2828,8 +2829,8 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
@@ -2828,8 +2829,8 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
|
|
|
|
|
UpdateTip(pindexDelete->pprev, chainparams); |
|
|
|
|
// Let wallets know transactions went from 1-confirmed to
|
|
|
|
|
// 0-confirmed or conflicted:
|
|
|
|
|
BOOST_FOREACH(const CTransaction &tx, block.vtx) { |
|
|
|
|
GetMainSignals().SyncTransaction(tx, pindexDelete->pprev, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK); |
|
|
|
|
for (const auto& tx : block.vtx) { |
|
|
|
|
GetMainSignals().SyncTransaction(*tx, pindexDelete->pprev, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK); |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
@ -2844,7 +2845,7 @@ static int64_t nTimePostConnect = 0;
@@ -2844,7 +2845,7 @@ static int64_t nTimePostConnect = 0;
|
|
|
|
|
* Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock |
|
|
|
|
* corresponding to pindexNew, to bypass loading it again from disk. |
|
|
|
|
*/ |
|
|
|
|
bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, std::vector<std::shared_ptr<const CTransaction>> &txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int>> &txChanged) |
|
|
|
|
bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, std::vector<std::shared_ptr<const CTransaction>> &txConflicted, std::vector<std::tuple<std::shared_ptr<const CTransaction>,CBlockIndex*,int>> &txChanged) |
|
|
|
|
{ |
|
|
|
|
assert(pindexNew->pprev == chainActive.Tip()); |
|
|
|
|
// Read block from disk.
|
|
|
|
@ -2884,7 +2885,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
@@ -2884,7 +2885,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
|
|
|
|
|
// Update chainActive & related variables.
|
|
|
|
|
UpdateTip(pindexNew, chainparams); |
|
|
|
|
|
|
|
|
|
for(unsigned int i=0; i < pblock->vtx.size(); i++) |
|
|
|
|
for (unsigned int i=0; i < pblock->vtx.size(); i++) |
|
|
|
|
txChanged.emplace_back(pblock->vtx[i], pindexNew, i); |
|
|
|
|
|
|
|
|
|
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; |
|
|
|
@ -2967,7 +2968,7 @@ static void PruneBlockIndexCandidates() {
@@ -2967,7 +2968,7 @@ static void PruneBlockIndexCandidates() {
|
|
|
|
|
* Try to make some progress towards making pindexMostWork the active block. |
|
|
|
|
* pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. |
|
|
|
|
*/ |
|
|
|
|
static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound, std::vector<std::shared_ptr<const CTransaction>>& txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int>>& txChanged) |
|
|
|
|
static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound, std::vector<std::shared_ptr<const CTransaction>>& txConflicted, std::vector<std::tuple<std::shared_ptr<const CTransaction>,CBlockIndex*,int>>& txChanged) |
|
|
|
|
{ |
|
|
|
|
AssertLockHeld(cs_main); |
|
|
|
|
const CBlockIndex *pindexOldTip = chainActive.Tip(); |
|
|
|
@ -3068,7 +3069,7 @@ static void NotifyHeaderTip() {
@@ -3068,7 +3069,7 @@ static void NotifyHeaderTip() {
|
|
|
|
|
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) { |
|
|
|
|
CBlockIndex *pindexMostWork = NULL; |
|
|
|
|
CBlockIndex *pindexNewTip = NULL; |
|
|
|
|
std::vector<std::tuple<CTransaction,CBlockIndex*,int>> txChanged; |
|
|
|
|
std::vector<std::tuple<std::shared_ptr<const CTransaction>,CBlockIndex*,int>> txChanged; |
|
|
|
|
if (pblock) |
|
|
|
|
txChanged.reserve(pblock->vtx.size()); |
|
|
|
|
do { |
|
|
|
@ -3109,13 +3110,13 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
@@ -3109,13 +3110,13 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
|
|
|
|
|
|
|
|
|
|
// throw all transactions though the signal-interface
|
|
|
|
|
// while _not_ holding the cs_main lock
|
|
|
|
|
for(std::shared_ptr<const CTransaction> tx : txConflicted) |
|
|
|
|
for (const auto& tx : txConflicted) |
|
|
|
|
{ |
|
|
|
|
GetMainSignals().SyncTransaction(*tx, pindexNewTip, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK); |
|
|
|
|
} |
|
|
|
|
// ... and about transactions that got confirmed:
|
|
|
|
|
for(unsigned int i = 0; i < txChanged.size(); i++) |
|
|
|
|
GetMainSignals().SyncTransaction(std::get<0>(txChanged[i]), std::get<1>(txChanged[i]), std::get<2>(txChanged[i])); |
|
|
|
|
for (unsigned int i = 0; i < txChanged.size(); i++) |
|
|
|
|
GetMainSignals().SyncTransaction(*std::get<0>(txChanged[i]), std::get<1>(txChanged[i]), std::get<2>(txChanged[i])); |
|
|
|
|
|
|
|
|
|
// Notify external listeners about the new tip.
|
|
|
|
|
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload); |
|
|
|
@ -3454,22 +3455,22 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
@@ -3454,22 +3455,22 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
|
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed"); |
|
|
|
|
|
|
|
|
|
// First transaction must be coinbase, the rest must not be
|
|
|
|
|
if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) |
|
|
|
|
if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false, "first tx is not coinbase"); |
|
|
|
|
for (unsigned int i = 1; i < block.vtx.size(); i++) |
|
|
|
|
if (block.vtx[i].IsCoinBase()) |
|
|
|
|
if (block.vtx[i]->IsCoinBase()) |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-cb-multiple", false, "more than one coinbase"); |
|
|
|
|
|
|
|
|
|
// Check transactions
|
|
|
|
|
for (const auto& tx : block.vtx) |
|
|
|
|
if (!CheckTransaction(tx, state, false)) |
|
|
|
|
if (!CheckTransaction(*tx, state, false)) |
|
|
|
|
return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), |
|
|
|
|
strprintf("Transaction check failed (tx hash %s) %s", tx.GetHash().ToString(), state.GetDebugMessage())); |
|
|
|
|
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage())); |
|
|
|
|
|
|
|
|
|
unsigned int nSigOps = 0; |
|
|
|
|
for (const auto& tx : block.vtx) |
|
|
|
|
{ |
|
|
|
|
nSigOps += GetLegacySigOpCount(tx); |
|
|
|
|
nSigOps += GetLegacySigOpCount(*tx); |
|
|
|
|
} |
|
|
|
|
if (nSigOps * WITNESS_SCALE_FACTOR > MAX_BLOCK_SIGOPS_COST) |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-blk-sigops", false, "out-of-bounds SigOpCount"); |
|
|
|
@ -3505,8 +3506,8 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
@@ -3505,8 +3506,8 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
|
|
|
|
|
static int GetWitnessCommitmentIndex(const CBlock& block) |
|
|
|
|
{ |
|
|
|
|
int commitpos = -1; |
|
|
|
|
for (size_t o = 0; o < block.vtx[0].vout.size(); o++) { |
|
|
|
|
if (block.vtx[0].vout[o].scriptPubKey.size() >= 38 && block.vtx[0].vout[o].scriptPubKey[0] == OP_RETURN && block.vtx[0].vout[o].scriptPubKey[1] == 0x24 && block.vtx[0].vout[o].scriptPubKey[2] == 0xaa && block.vtx[0].vout[o].scriptPubKey[3] == 0x21 && block.vtx[0].vout[o].scriptPubKey[4] == 0xa9 && block.vtx[0].vout[o].scriptPubKey[5] == 0xed) { |
|
|
|
|
for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) { |
|
|
|
|
if (block.vtx[0]->vout[o].scriptPubKey.size() >= 38 && block.vtx[0]->vout[o].scriptPubKey[0] == OP_RETURN && block.vtx[0]->vout[o].scriptPubKey[1] == 0x24 && block.vtx[0]->vout[o].scriptPubKey[2] == 0xaa && block.vtx[0]->vout[o].scriptPubKey[3] == 0x21 && block.vtx[0]->vout[o].scriptPubKey[4] == 0xa9 && block.vtx[0]->vout[o].scriptPubKey[5] == 0xed) { |
|
|
|
|
commitpos = o; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -3517,10 +3518,12 @@ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPr
@@ -3517,10 +3518,12 @@ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPr
|
|
|
|
|
{ |
|
|
|
|
int commitpos = GetWitnessCommitmentIndex(block); |
|
|
|
|
static const std::vector<unsigned char> nonce(32, 0x00); |
|
|
|
|
if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && block.vtx[0].wit.IsEmpty()) { |
|
|
|
|
block.vtx[0].wit.vtxinwit.resize(1); |
|
|
|
|
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.resize(1); |
|
|
|
|
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0] = nonce; |
|
|
|
|
if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && block.vtx[0]->wit.IsEmpty()) { |
|
|
|
|
CMutableTransaction tx(*block.vtx[0]); |
|
|
|
|
tx.wit.vtxinwit.resize(1); |
|
|
|
|
tx.wit.vtxinwit[0].scriptWitness.stack.resize(1); |
|
|
|
|
tx.wit.vtxinwit[0].scriptWitness.stack[0] = nonce; |
|
|
|
|
block.vtx[0] = std::make_shared<const CTransaction>(std::move(tx)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -3530,7 +3533,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
@@ -3530,7 +3533,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
|
|
|
|
|
int commitpos = GetWitnessCommitmentIndex(block); |
|
|
|
|
bool fHaveWitness = false; |
|
|
|
|
for (size_t t = 1; t < block.vtx.size(); t++) { |
|
|
|
|
if (!block.vtx[t].wit.IsNull()) { |
|
|
|
|
if (!block.vtx[t]->wit.IsNull()) { |
|
|
|
|
fHaveWitness = true; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
@ -3551,8 +3554,8 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
@@ -3551,8 +3554,8 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
|
|
|
|
|
out.scriptPubKey[5] = 0xed; |
|
|
|
|
memcpy(&out.scriptPubKey[6], witnessroot.begin(), 32); |
|
|
|
|
commitment = std::vector<unsigned char>(out.scriptPubKey.begin(), out.scriptPubKey.end()); |
|
|
|
|
const_cast<std::vector<CTxOut>*>(&block.vtx[0].vout)->push_back(out); |
|
|
|
|
block.vtx[0].UpdateHash(); |
|
|
|
|
const_cast<std::vector<CTxOut>*>(&block.vtx[0]->vout)->push_back(out); |
|
|
|
|
block.vtx[0]->UpdateHash(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
UpdateUncommittedBlockStructures(block, pindexPrev, consensusParams); |
|
|
|
@ -3601,7 +3604,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
@@ -3601,7 +3604,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
|
|
|
|
|
|
|
|
|
|
// Check that all transactions are finalized
|
|
|
|
|
for (const auto& tx : block.vtx) { |
|
|
|
|
if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { |
|
|
|
|
if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) { |
|
|
|
|
return state.DoS(10, false, REJECT_INVALID, "bad-txns-nonfinal", false, "non-final transaction"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -3610,8 +3613,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
@@ -3610,8 +3613,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
|
|
|
|
|
if (nHeight >= consensusParams.BIP34Height) |
|
|
|
|
{ |
|
|
|
|
CScript expect = CScript() << nHeight; |
|
|
|
|
if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || |
|
|
|
|
!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { |
|
|
|
|
if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() || |
|
|
|
|
!std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) { |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-cb-height", false, "block height mismatch in coinbase"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -3633,11 +3636,11 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
@@ -3633,11 +3636,11 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
|
|
|
|
|
// The malleation check is ignored; as the transaction tree itself
|
|
|
|
|
// already does not permit it, it is impossible to trigger in the
|
|
|
|
|
// witness tree.
|
|
|
|
|
if (block.vtx[0].wit.vtxinwit.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0].size() != 32) { |
|
|
|
|
if (block.vtx[0]->wit.vtxinwit.size() != 1 || block.vtx[0]->wit.vtxinwit[0].scriptWitness.stack.size() != 1 || block.vtx[0]->wit.vtxinwit[0].scriptWitness.stack[0].size() != 32) { |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-witness-nonce-size", true, strprintf("%s : invalid witness nonce size", __func__)); |
|
|
|
|
} |
|
|
|
|
CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin()); |
|
|
|
|
if (memcmp(hashWitness.begin(), &block.vtx[0].vout[commitpos].scriptPubKey[6], 32)) { |
|
|
|
|
CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0]->wit.vtxinwit[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin()); |
|
|
|
|
if (memcmp(hashWitness.begin(), &block.vtx[0]->vout[commitpos].scriptPubKey[6], 32)) { |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "bad-witness-merkle-match", true, strprintf("%s : witness merkle commitment mismatch", __func__)); |
|
|
|
|
} |
|
|
|
|
fHaveWitness = true; |
|
|
|
@ -3647,7 +3650,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
@@ -3647,7 +3650,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
|
|
|
|
|
// No witness data is allowed in blocks that don't commit to witness data, as this would otherwise leave room for spam
|
|
|
|
|
if (!fHaveWitness) { |
|
|
|
|
for (size_t i = 0; i < block.vtx.size(); i++) { |
|
|
|
|
if (!block.vtx[i].wit.IsNull()) { |
|
|
|
|
if (!block.vtx[i]->wit.IsNull()) { |
|
|
|
|
return state.DoS(100, false, REJECT_INVALID, "unexpected-witness", true, strprintf("%s : unexpected witness data found", __func__)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -4953,7 +4956,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
@@ -4953,7 +4956,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
|
|
|
|
|
// however we MUST always provide at least what the remote peer needs
|
|
|
|
|
typedef std::pair<unsigned int, uint256> PairType; |
|
|
|
|
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn) |
|
|
|
|
connman.PushMessageWithFlag(pfrom, SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, block.vtx[pair.first]); |
|
|
|
|
connman.PushMessageWithFlag(pfrom, SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *block.vtx[pair.first]); |
|
|
|
|
} |
|
|
|
|
// else
|
|
|
|
|
// no response
|
|
|
|
|