mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Fix compact block handling to not ban if block is invalid
This commit is contained in:
parent
c93beac43f
commit
88c35491ab
@ -167,7 +167,7 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
|
|||||||
// check its own merkle root and cache that check.
|
// check its own merkle root and cache that check.
|
||||||
if (state.CorruptionPossible())
|
if (state.CorruptionPossible())
|
||||||
return READ_STATUS_FAILED; // Possible Short ID collision
|
return READ_STATUS_FAILED; // Possible Short ID collision
|
||||||
return READ_STATUS_INVALID;
|
return READ_STATUS_CHECKBLOCK_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogPrint("cmpctblock", "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool and %lu txn requested\n", header.GetHash().ToString(), prefilled_count, mempool_count, vtx_missing.size());
|
LogPrint("cmpctblock", "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool and %lu txn requested\n", header.GetHash().ToString(), prefilled_count, mempool_count, vtx_missing.size());
|
||||||
|
@ -124,6 +124,8 @@ typedef enum ReadStatus_t
|
|||||||
READ_STATUS_OK,
|
READ_STATUS_OK,
|
||||||
READ_STATUS_INVALID, // Invalid object, peer is sending bogus crap
|
READ_STATUS_INVALID, // Invalid object, peer is sending bogus crap
|
||||||
READ_STATUS_FAILED, // Failed to process object
|
READ_STATUS_FAILED, // Failed to process object
|
||||||
|
READ_STATUS_CHECKBLOCK_FAILED, // Used only by FillBlock to indicate a
|
||||||
|
// failure in CheckBlock.
|
||||||
} ReadStatus;
|
} ReadStatus;
|
||||||
|
|
||||||
class CBlockHeaderAndShortTxIDs {
|
class CBlockHeaderAndShortTxIDs {
|
||||||
|
46
src/main.cpp
46
src/main.cpp
@ -179,8 +179,10 @@ namespace {
|
|||||||
* Sources of received blocks, saved to be able to send them reject
|
* Sources of received blocks, saved to be able to send them reject
|
||||||
* messages or ban them when processing happens afterwards. Protected by
|
* messages or ban them when processing happens afterwards. Protected by
|
||||||
* cs_main.
|
* cs_main.
|
||||||
|
* Set mapBlockSource[hash].second to false if the node should not be
|
||||||
|
* punished if the block is invalid.
|
||||||
*/
|
*/
|
||||||
map<uint256, NodeId> mapBlockSource;
|
map<uint256, std::pair<NodeId, bool>> mapBlockSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter for transactions that were recently rejected by
|
* Filter for transactions that were recently rejected by
|
||||||
@ -3759,7 +3761,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp)
|
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool fMayBanPeerIfInvalid)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
@ -3769,7 +3771,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
|
|||||||
bool fNewBlock = false;
|
bool fNewBlock = false;
|
||||||
bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fForceProcessing, dbp, &fNewBlock);
|
bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fForceProcessing, dbp, &fNewBlock);
|
||||||
if (pindex && pfrom) {
|
if (pindex && pfrom) {
|
||||||
mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
|
mapBlockSource[pindex->GetBlockHash()] = std::make_pair(pfrom->GetId(), fMayBanPeerIfInvalid);
|
||||||
if (fNewBlock) pfrom->nLastBlockTime = GetTime();
|
if (fNewBlock) pfrom->nLastBlockTime = GetTime();
|
||||||
}
|
}
|
||||||
CheckBlockIndex(chainparams.GetConsensus());
|
CheckBlockIndex(chainparams.GetConsensus());
|
||||||
@ -4749,16 +4751,16 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
|
|||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
const uint256 hash(block.GetHash());
|
const uint256 hash(block.GetHash());
|
||||||
std::map<uint256, NodeId>::iterator it = mapBlockSource.find(hash);
|
std::map<uint256, std::pair<NodeId, bool>>::iterator it = mapBlockSource.find(hash);
|
||||||
|
|
||||||
int nDoS = 0;
|
int nDoS = 0;
|
||||||
if (state.IsInvalid(nDoS)) {
|
if (state.IsInvalid(nDoS)) {
|
||||||
if (it != mapBlockSource.end() && State(it->second)) {
|
if (it != mapBlockSource.end() && State(it->second.first)) {
|
||||||
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
||||||
CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), hash};
|
CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), hash};
|
||||||
State(it->second)->rejects.push_back(reject);
|
State(it->second.first)->rejects.push_back(reject);
|
||||||
if (nDoS > 0)
|
if (nDoS > 0 && it->second.second)
|
||||||
Misbehaving(it->second, nDoS);
|
Misbehaving(it->second.first, nDoS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (it != mapBlockSource.end())
|
if (it != mapBlockSource.end())
|
||||||
@ -5868,6 +5870,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()), resp.blockhash));
|
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()), resp.blockhash));
|
||||||
pfrom->PushMessage(NetMsgType::GETDATA, invs);
|
pfrom->PushMessage(NetMsgType::GETDATA, invs);
|
||||||
} else {
|
} else {
|
||||||
|
// Block is either okay, or possibly we received
|
||||||
|
// READ_STATUS_CHECKBLOCK_FAILED.
|
||||||
|
// Note that CheckBlock can only fail for one of a few reasons:
|
||||||
|
// 1. bad-proof-of-work (impossible here, because we've already
|
||||||
|
// accepted the header)
|
||||||
|
// 2. merkleroot doesn't match the transactions given (already
|
||||||
|
// caught in FillBlock with READ_STATUS_FAILED, so
|
||||||
|
// impossible here)
|
||||||
|
// 3. the block is otherwise invalid (eg invalid coinbase,
|
||||||
|
// block is too big, too many legacy sigops, etc).
|
||||||
|
// So if CheckBlock failed, #3 is the only possibility.
|
||||||
|
// Under BIP 152, we don't DoS-ban unless proof of work is
|
||||||
|
// invalid (we don't require all the stateless checks to have
|
||||||
|
// been run). This is handled below, so just treat this as
|
||||||
|
// though the block was successfully read, and rely on the
|
||||||
|
// handling in ProcessNewBlock to ensure the block index is
|
||||||
|
// updated, reject messages go out, etc.
|
||||||
MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
|
MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
|
||||||
fBlockRead = true;
|
fBlockRead = true;
|
||||||
}
|
}
|
||||||
@ -5876,16 +5895,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
CValidationState state;
|
CValidationState state;
|
||||||
// Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
|
// Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
|
||||||
// even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
|
// even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
|
||||||
ProcessNewBlock(state, chainparams, pfrom, &block, true, NULL);
|
// BIP 152 permits peers to relay compact blocks after validating
|
||||||
|
// the header only; we should not punish peers if the block turns
|
||||||
|
// out to be invalid.
|
||||||
|
ProcessNewBlock(state, chainparams, pfrom, &block, true, NULL, false);
|
||||||
int nDoS;
|
int nDoS;
|
||||||
if (state.IsInvalid(nDoS)) {
|
if (state.IsInvalid(nDoS)) {
|
||||||
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
||||||
pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
|
pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
|
||||||
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash());
|
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash());
|
||||||
if (nDoS > 0) {
|
|
||||||
LOCK(cs_main);
|
|
||||||
Misbehaving(pfrom->GetId(), nDoS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6056,7 +6074,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
// need it even though it is not a candidate for a new best tip.
|
// need it even though it is not a candidate for a new best tip.
|
||||||
forceProcessing |= MarkBlockAsReceived(block.GetHash());
|
forceProcessing |= MarkBlockAsReceived(block.GetHash());
|
||||||
}
|
}
|
||||||
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL);
|
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, true);
|
||||||
int nDoS;
|
int nDoS;
|
||||||
if (state.IsInvalid(nDoS)) {
|
if (state.IsInvalid(nDoS)) {
|
||||||
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
||||||
|
@ -223,7 +223,7 @@ static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
|
|||||||
* @param[out] dbp The already known disk position of pblock, or NULL if not yet stored.
|
* @param[out] dbp The already known disk position of pblock, or NULL if not yet stored.
|
||||||
* @return True if state.IsValid()
|
* @return True if state.IsValid()
|
||||||
*/
|
*/
|
||||||
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp);
|
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool fMayBanPeerIfInvalid);
|
||||||
/** Check whether enough disk space is available for an incoming block */
|
/** Check whether enough disk space is available for an incoming block */
|
||||||
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
|
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
|
||||||
/** Open a block file (blk?????.dat) */
|
/** Open a block file (blk?????.dat) */
|
||||||
|
@ -132,7 +132,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL))
|
if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, false))
|
||||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
|
||||||
++nHeight;
|
++nHeight;
|
||||||
blockHashes.push_back(pblock->GetHash().GetHex());
|
blockHashes.push_back(pblock->GetHash().GetHex());
|
||||||
@ -757,7 +757,7 @@ UniValue submitblock(const JSONRPCRequest& request)
|
|||||||
CValidationState state;
|
CValidationState state;
|
||||||
submitblock_StateCatcher sc(block.GetHash());
|
submitblock_StateCatcher sc(block.GetHash());
|
||||||
RegisterValidationInterface(&sc);
|
RegisterValidationInterface(&sc);
|
||||||
bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL);
|
bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, false);
|
||||||
UnregisterValidationInterface(&sc);
|
UnregisterValidationInterface(&sc);
|
||||||
if (fBlockPresent)
|
if (fBlockPresent)
|
||||||
{
|
{
|
||||||
|
@ -223,7 +223,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||||||
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
|
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
|
||||||
pblock->nNonce = blockinfo[i].nonce;
|
pblock->nNonce = blockinfo[i].nonce;
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL));
|
BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, false));
|
||||||
BOOST_CHECK(state.IsValid());
|
BOOST_CHECK(state.IsValid());
|
||||||
pblock->hashPrevBlock = pblock->GetHash();
|
pblock->hashPrevBlock = pblock->GetHash();
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
|
|||||||
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
|
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
ProcessNewBlock(state, chainparams, NULL, &block, true, NULL);
|
ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, false);
|
||||||
|
|
||||||
CBlock result = block;
|
CBlock result = block;
|
||||||
return result;
|
return result;
|
||||||
|
Loading…
Reference in New Issue
Block a user