Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 1,195 Lines • ▼ Show 20 Lines | static void Misbehaving(CNode *node, int howmuch, const std::string &reason) | ||||
Misbehaving(node->GetId(), howmuch, reason); | Misbehaving(node->GetId(), howmuch, reason); | ||||
} | } | ||||
/** | /** | ||||
* Returns true if the given validation state result may result in a peer | * Returns true if the given validation state result may result in a peer | ||||
* banning/disconnecting us. We use this to determine which unaccepted | * banning/disconnecting us. We use this to determine which unaccepted | ||||
* transactions from a whitelisted peer that we can safely relay. | * transactions from a whitelisted peer that we can safely relay. | ||||
*/ | */ | ||||
static bool TxRelayMayResultInDisconnect(const CValidationState &state) { | static bool TxRelayMayResultInDisconnect(const TxValidationState &state) { | ||||
assert(IsTransactionReason(state.GetReason())); | return state.GetResult() == TxValidationResult::TX_CONSENSUS; | ||||
return state.GetReason() == ValidationInvalidReason::CONSENSUS; | |||||
} | } | ||||
/** | /** | ||||
* Potentially ban a node based on the contents of a CValidationState object | * Potentially ban a node based on the contents of a BlockValidationState object | ||||
* | * | ||||
* @param[in] via_compact_block: this bool is passed in because net_processing | * @param[in] via_compact_block: this bool is passed in because net_processing | ||||
* should punish peers differently depending on whether the data was provided in | * should punish peers differently depending on whether the data was provided in | ||||
* a compact block message or not. If the compact block had a valid header, but | * a compact block message or not. If the compact block had a valid header, but | ||||
* contained invalid txs, the peer should not be punished. See BIP 152. | * contained invalid txs, the peer should not be punished. See BIP 152. | ||||
* | * | ||||
* @return Returns true if the peer was punished (probably disconnected) | * @return Returns true if the peer was punished (probably disconnected) | ||||
* | |||||
* Changes here may need to be reflected in TxRelayMayResultInDisconnect(). | |||||
*/ | */ | ||||
static bool MaybePunishNode(NodeId nodeid, const CValidationState &state, | static bool MaybePunishNodeForBlock(NodeId nodeid, | ||||
const BlockValidationState &state, | |||||
bool via_compact_block, | bool via_compact_block, | ||||
const std::string &message = "") { | const std::string &message = "") { | ||||
switch (state.GetReason()) { | switch (state.GetResult()) { | ||||
case ValidationInvalidReason::NONE: | case BlockValidationResult::BLOCK_RESULT_UNSET: | ||||
break; | break; | ||||
// The node is providing invalid data: | // The node is providing invalid data: | ||||
case ValidationInvalidReason::CONSENSUS: | case BlockValidationResult::BLOCK_CONSENSUS: | ||||
case ValidationInvalidReason::BLOCK_MUTATED: | case BlockValidationResult::BLOCK_MUTATED: | ||||
if (!via_compact_block) { | if (!via_compact_block) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(nodeid, 100, message); | Misbehaving(nodeid, 100, message); | ||||
return true; | return true; | ||||
} | } | ||||
break; | break; | ||||
case ValidationInvalidReason::CACHED_INVALID: { | case BlockValidationResult::BLOCK_CACHED_INVALID: { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CNodeState *node_state = State(nodeid); | CNodeState *node_state = State(nodeid); | ||||
if (node_state == nullptr) { | if (node_state == nullptr) { | ||||
break; | break; | ||||
} | } | ||||
// Ban outbound (but not inbound) peers if on an invalid chain. | // Ban outbound (but not inbound) peers if on an invalid chain. | ||||
// Exempt HB compact block peers and manual connections. | // Exempt HB compact block peers and manual connections. | ||||
if (!via_compact_block && !node_state->m_is_inbound && | if (!via_compact_block && !node_state->m_is_inbound && | ||||
!node_state->m_is_manual_connection) { | !node_state->m_is_manual_connection) { | ||||
Misbehaving(nodeid, 100, message); | Misbehaving(nodeid, 100, message); | ||||
return true; | return true; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case ValidationInvalidReason::BLOCK_INVALID_HEADER: | case BlockValidationResult::BLOCK_INVALID_HEADER: | ||||
case ValidationInvalidReason::BLOCK_CHECKPOINT: | case BlockValidationResult::BLOCK_CHECKPOINT: | ||||
case ValidationInvalidReason::BLOCK_INVALID_PREV: { | case BlockValidationResult::BLOCK_INVALID_PREV: { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(nodeid, 100, message); | Misbehaving(nodeid, 100, message); | ||||
} | } | ||||
return true; | return true; | ||||
case ValidationInvalidReason::BLOCK_FINALIZATION: { | case BlockValidationResult::BLOCK_FINALIZATION: { | ||||
// TODO: Use the state object to report this is probably not the | // TODO: Use the state object to report this is probably not the | ||||
// best idea. This is effectively unreachable, unless there is a bug | // best idea. This is effectively unreachable, unless there is a bug | ||||
// somewhere. | // somewhere. | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(nodeid, 20, message); | Misbehaving(nodeid, 20, message); | ||||
} | } | ||||
return true; | return true; | ||||
// Conflicting (but not necessarily invalid) data or different policy: | // Conflicting (but not necessarily invalid) data or different policy: | ||||
case ValidationInvalidReason::BLOCK_MISSING_PREV: { | case BlockValidationResult::BLOCK_MISSING_PREV: { | ||||
// TODO: Handle this much more gracefully (10 DoS points is super | // TODO: Handle this much more gracefully (10 DoS points is super | ||||
// arbitrary) | // arbitrary) | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
Misbehaving(nodeid, 10, message); | Misbehaving(nodeid, 10, message); | ||||
} | } | ||||
return true; | return true; | ||||
case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE: | case BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE: | ||||
case ValidationInvalidReason::BLOCK_TIME_FUTURE: | case BlockValidationResult::BLOCK_TIME_FUTURE: | ||||
case ValidationInvalidReason::TX_NOT_STANDARD: | break; | ||||
case ValidationInvalidReason::TX_MISSING_INPUTS: | } | ||||
case ValidationInvalidReason::TX_PREMATURE_SPEND: | if (message != "") { | ||||
case ValidationInvalidReason::TX_CONFLICT: | LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message); | ||||
case ValidationInvalidReason::TX_MEMPOOL_POLICY: | } | ||||
return false; | |||||
} | |||||
/** | |||||
* Potentially ban a node based on the contents of a TxValidationState object | |||||
* | |||||
* @return Returns true if the peer was punished (probably disconnected) | |||||
* | |||||
* Changes here may need to be reflected in TxRelayMayResultInDisconnect(). | |||||
*/ | |||||
static bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState &state, | |||||
const std::string &message = "") { | |||||
switch (state.GetResult()) { | |||||
case TxValidationResult::TX_RESULT_UNSET: | |||||
break; | |||||
// The node is providing invalid data: | |||||
case TxValidationResult::TX_CONSENSUS: { | |||||
LOCK(cs_main); | |||||
Misbehaving(nodeid, 100, message); | |||||
return true; | |||||
} | |||||
// Conflicting (but not necessarily invalid) data or different policy: | |||||
case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE: | |||||
case TxValidationResult::TX_NOT_STANDARD: | |||||
case TxValidationResult::TX_MISSING_INPUTS: | |||||
case TxValidationResult::TX_PREMATURE_SPEND: | |||||
case TxValidationResult::TX_CONFLICT: | |||||
case TxValidationResult::TX_MEMPOOL_POLICY: | |||||
break; | break; | ||||
} | } | ||||
if (message != "") { | if (message != "") { | ||||
LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message); | LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message); | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 190 Lines • ▼ Show 20 Lines | void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Handle invalid block rejection and consequent peer banning, maintain which | * Handle invalid block rejection and consequent peer banning, maintain which | ||||
* peers announce compact blocks. | * peers announce compact blocks. | ||||
*/ | */ | ||||
void PeerLogicValidation::BlockChecked(const CBlock &block, | void PeerLogicValidation::BlockChecked(const CBlock &block, | ||||
const CValidationState &state) { | const BlockValidationState &state) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
const BlockHash hash = block.GetHash(); | const BlockHash hash = block.GetHash(); | ||||
std::map<BlockHash, std::pair<NodeId, bool>>::iterator it = | std::map<BlockHash, std::pair<NodeId, bool>>::iterator it = | ||||
mapBlockSource.find(hash); | mapBlockSource.find(hash); | ||||
if (state.IsInvalid()) { | if (state.IsInvalid()) { | ||||
// Don't send reject message with code 0 or an internal reject code. | // Don't send reject message with code 0 or an internal reject code. | ||||
if (it != mapBlockSource.end() && State(it->second.first) && | if (it != mapBlockSource.end() && State(it->second.first) && | ||||
state.GetRejectCode() > 0 && | state.GetRejectCode() > 0 && | ||||
state.GetRejectCode() < REJECT_INTERNAL) { | state.GetRejectCode() < REJECT_INTERNAL) { | ||||
CBlockReject reject = { | CBlockReject reject = { | ||||
uint8_t(state.GetRejectCode()), | uint8_t(state.GetRejectCode()), | ||||
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), | state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), | ||||
hash}; | hash}; | ||||
State(it->second.first)->rejects.push_back(reject); | State(it->second.first)->rejects.push_back(reject); | ||||
MaybePunishNode(/*nodeid=*/it->second.first, state, | MaybePunishNodeForBlock(/*nodeid=*/it->second.first, state, | ||||
/*via_compact_block=*/!it->second.second); | /*via_compact_block=*/!it->second.second); | ||||
} | } | ||||
} | } | ||||
// Check that: | // Check that: | ||||
// 1. The block is valid | // 1. The block is valid | ||||
// 2. We're not in initial block download | // 2. We're not in initial block download | ||||
// 3. This is currently the best block we're aware of. We haven't updated | // 3. This is currently the best block we're aware of. We haven't updated | ||||
// the tip yet so we have no way to check this directly here. Instead we | // the tip yet so we have no way to check this directly here. Instead we | ||||
// just check that there are currently no other blocks in flight. | // just check that there are currently no other blocks in flight. | ||||
▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | bool need_activate_chain = false; | ||||
// in the unlock of cs_main before ActivateBestChain but after | // in the unlock of cs_main before ActivateBestChain but after | ||||
// AcceptBlock). In this case, we need to run ActivateBestChain | // AcceptBlock). In this case, we need to run ActivateBestChain | ||||
// prior to checking the relay conditions below. | // prior to checking the relay conditions below. | ||||
need_activate_chain = true; | need_activate_chain = true; | ||||
} | } | ||||
} | } | ||||
} // release cs_main before calling ActivateBestChain | } // release cs_main before calling ActivateBestChain | ||||
if (need_activate_chain) { | if (need_activate_chain) { | ||||
CValidationState state; | BlockValidationState state; | ||||
if (!ActivateBestChain(config, state, a_recent_block)) { | if (!ActivateBestChain(config, state, a_recent_block)) { | ||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", | LogPrint(BCLog::NET, "failed to activate chain (%s)\n", | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
const CBlockIndex *pindex = LookupBlockIndex(hash); | const CBlockIndex *pindex = LookupBlockIndex(hash); | ||||
▲ Show 20 Lines • Show All 317 Lines • ▼ Show 20 Lines | const CBlockIndex *pindexLast = nullptr; | ||||
// If we don't have the last header, then they'll have given us | // If we don't have the last header, then they'll have given us | ||||
// something new (if these headers are valid). | // something new (if these headers are valid). | ||||
if (!LookupBlockIndex(hashLastBlock)) { | if (!LookupBlockIndex(hashLastBlock)) { | ||||
received_new_header = true; | received_new_header = true; | ||||
} | } | ||||
} | } | ||||
CValidationState state; | BlockValidationState state; | ||||
if (!ProcessNewBlockHeaders(config, headers, state, &pindexLast)) { | if (!ProcessNewBlockHeaders(config, headers, state, &pindexLast)) { | ||||
if (state.IsInvalid()) { | if (state.IsInvalid()) { | ||||
MaybePunishNode(pfrom->GetId(), state, via_compact_block, | MaybePunishNodeForBlock(pfrom->GetId(), state, via_compact_block, | ||||
"invalid header received"); | "invalid header received"); | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CNodeState *nodestate = State(pfrom->GetId()); | CNodeState *nodestate = State(pfrom->GetId()); | ||||
if (nodestate->nUnconnectingHeaders > 0) { | if (nodestate->nUnconnectingHeaders > 0) { | ||||
▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | while (!done && !orphan_work_set.empty()) { | ||||
auto orphan_it = mapOrphanTransactions.find(orphanTxId); | auto orphan_it = mapOrphanTransactions.find(orphanTxId); | ||||
if (orphan_it == mapOrphanTransactions.end()) { | if (orphan_it == mapOrphanTransactions.end()) { | ||||
continue; | continue; | ||||
} | } | ||||
const CTransactionRef porphanTx = orphan_it->second.tx; | const CTransactionRef porphanTx = orphan_it->second.tx; | ||||
const CTransaction &orphanTx = *porphanTx; | const CTransaction &orphanTx = *porphanTx; | ||||
NodeId fromPeer = orphan_it->second.fromPeer; | NodeId fromPeer = orphan_it->second.fromPeer; | ||||
// Use a new CValidationState because orphans come from different peers | // Use a new TxValidationState because orphans come from different peers | ||||
// (and we call MaybePunishNode based on the source peer from the orphan | // (and we call MaybePunishNodeForTx based on the source peer from the | ||||
// map, not based on the peer that relayed the previous transaction). | // orphan map, not based on the peer that relayed the previous | ||||
CValidationState orphan_state; | // transaction). | ||||
TxValidationState orphan_state; | |||||
auto it = rejectCountPerNode.find(fromPeer); | auto it = rejectCountPerNode.find(fromPeer); | ||||
if (it != rejectCountPerNode.end() && | if (it != rejectCountPerNode.end() && | ||||
it->second > MAX_NON_STANDARD_ORPHAN_PER_NODE) { | it->second > MAX_NON_STANDARD_ORPHAN_PER_NODE) { | ||||
continue; | continue; | ||||
} | } | ||||
if (AcceptToMemoryPool(config, g_mempool, orphan_state, porphanTx, | if (AcceptToMemoryPool(config, g_mempool, orphan_state, porphanTx, | ||||
false /* bypass_limits */, | false /* bypass_limits */, | ||||
Amount::zero() /* nAbsurdFee */)) { | Amount::zero() /* nAbsurdFee */)) { | ||||
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", | LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", | ||||
orphanTxId.ToString()); | orphanTxId.ToString()); | ||||
RelayTransaction(orphanTxId, *connman); | RelayTransaction(orphanTxId, *connman); | ||||
for (size_t i = 0; i < orphanTx.vout.size(); i++) { | for (size_t i = 0; i < orphanTx.vout.size(); i++) { | ||||
auto it_by_prev = | auto it_by_prev = | ||||
mapOrphanTransactionsByPrev.find(COutPoint(orphanTxId, i)); | mapOrphanTransactionsByPrev.find(COutPoint(orphanTxId, i)); | ||||
if (it_by_prev != mapOrphanTransactionsByPrev.end()) { | if (it_by_prev != mapOrphanTransactionsByPrev.end()) { | ||||
for (const auto &elem : it_by_prev->second) { | for (const auto &elem : it_by_prev->second) { | ||||
orphan_work_set.insert(elem->first); | orphan_work_set.insert(elem->first); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
EraseOrphanTx(orphanTxId); | EraseOrphanTx(orphanTxId); | ||||
done = true; | done = true; | ||||
} else if (orphan_state.GetReason() != | } else if (orphan_state.GetResult() != | ||||
ValidationInvalidReason::TX_MISSING_INPUTS) { | TxValidationResult::TX_MISSING_INPUTS) { | ||||
if (orphan_state.IsInvalid()) { | if (orphan_state.IsInvalid()) { | ||||
// Punish peer that gave us an invalid orphan tx | // Punish peer that gave us an invalid orphan tx | ||||
MaybePunishNode(fromPeer, orphan_state, | MaybePunishNodeForTx(fromPeer, orphan_state); | ||||
/*via_compact_block*/ false); | |||||
LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", | LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", | ||||
orphanTxId.ToString()); | orphanTxId.ToString()); | ||||
} | } | ||||
// Has inputs but not accepted to mempool | // Has inputs but not accepted to mempool | ||||
// Probably non-standard or insufficient fee | // Probably non-standard or insufficient fee | ||||
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", | LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", | ||||
orphanTxId.ToString()); | orphanTxId.ToString()); | ||||
assert(IsTransactionReason(orphan_state.GetReason())); | |||||
assert(recentRejects); | assert(recentRejects); | ||||
recentRejects->insert(orphanTxId); | recentRejects->insert(orphanTxId); | ||||
EraseOrphanTx(orphanTxId); | EraseOrphanTx(orphanTxId); | ||||
done = true; | done = true; | ||||
} | } | ||||
g_mempool.check(pcoinsTip.get()); | g_mempool.check(pcoinsTip.get()); | ||||
▲ Show 20 Lines • Show All 525 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::GETBLOCKS) { | ||||
// for getheaders requests, and there are no known nodes which support | // for getheaders requests, and there are no known nodes which support | ||||
// compact blocks but still use getblocks to request blocks. | // compact blocks but still use getblocks to request blocks. | ||||
{ | { | ||||
std::shared_ptr<const CBlock> a_recent_block; | std::shared_ptr<const CBlock> a_recent_block; | ||||
{ | { | ||||
LOCK(cs_most_recent_block); | LOCK(cs_most_recent_block); | ||||
a_recent_block = most_recent_block; | a_recent_block = most_recent_block; | ||||
} | } | ||||
CValidationState state; | BlockValidationState state; | ||||
if (!ActivateBestChain(config, state, a_recent_block)) { | if (!ActivateBestChain(config, state, a_recent_block)) { | ||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", | LogPrint(BCLog::NET, "failed to activate chain (%s)\n", | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
} | } | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::TX) { | ||||
const CTransaction &tx = *ptx; | const CTransaction &tx = *ptx; | ||||
const TxId &txid = tx.GetId(); | const TxId &txid = tx.GetId(); | ||||
CInv inv(MSG_TX, txid); | CInv inv(MSG_TX, txid); | ||||
pfrom->AddInventoryKnown(inv); | pfrom->AddInventoryKnown(inv); | ||||
LOCK2(cs_main, g_cs_orphans); | LOCK2(cs_main, g_cs_orphans); | ||||
CValidationState state; | TxValidationState state; | ||||
CNodeState *nodestate = State(pfrom->GetId()); | CNodeState *nodestate = State(pfrom->GetId()); | ||||
nodestate->m_tx_download.m_tx_announced.erase(txid); | nodestate->m_tx_download.m_tx_announced.erase(txid); | ||||
nodestate->m_tx_download.m_tx_in_flight.erase(txid); | nodestate->m_tx_download.m_tx_in_flight.erase(txid); | ||||
EraseTxRequest(txid); | EraseTxRequest(txid); | ||||
if (!AlreadyHave(inv) && | if (!AlreadyHave(inv) && | ||||
AcceptToMemoryPool(config, g_mempool, state, ptx, | AcceptToMemoryPool(config, g_mempool, state, ptx, | ||||
Show All 17 Lines | if (strCommand == NetMsgType::TX) { | ||||
"AcceptToMemoryPool: peer=%d: accepted %s " | "AcceptToMemoryPool: peer=%d: accepted %s " | ||||
"(poolsz %u txn, %u kB)\n", | "(poolsz %u txn, %u kB)\n", | ||||
pfrom->GetId(), tx.GetId().ToString(), g_mempool.size(), | pfrom->GetId(), tx.GetId().ToString(), g_mempool.size(), | ||||
g_mempool.DynamicMemoryUsage() / 1000); | g_mempool.DynamicMemoryUsage() / 1000); | ||||
// Recursively process any orphan transactions that depended on this | // Recursively process any orphan transactions that depended on this | ||||
// one | // one | ||||
ProcessOrphanTx(config, connman, pfrom->orphan_work_set); | ProcessOrphanTx(config, connman, pfrom->orphan_work_set); | ||||
} else if (state.GetReason() == | } else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { | ||||
ValidationInvalidReason::TX_MISSING_INPUTS) { | |||||
// It may be the case that the orphans parents have all been | // It may be the case that the orphans parents have all been | ||||
// rejected. | // rejected. | ||||
bool fRejectedParents = false; | bool fRejectedParents = false; | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
if (recentRejects->contains(txin.prevout.GetTxId())) { | if (recentRejects->contains(txin.prevout.GetTxId())) { | ||||
fRejectedParents = true; | fRejectedParents = true; | ||||
break; | break; | ||||
} | } | ||||
Show All 26 Lines | if (strCommand == NetMsgType::TX) { | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"not keeping orphan with rejected parents %s\n", | "not keeping orphan with rejected parents %s\n", | ||||
tx.GetId().ToString()); | tx.GetId().ToString()); | ||||
// We will continue to reject this tx since it has rejected | // We will continue to reject this tx since it has rejected | ||||
// parents so avoid re-requesting it from other peers. | // parents so avoid re-requesting it from other peers. | ||||
recentRejects->insert(tx.GetId()); | recentRejects->insert(tx.GetId()); | ||||
} | } | ||||
} else { | } else { | ||||
assert(IsTransactionReason(state.GetReason())); | |||||
assert(recentRejects); | assert(recentRejects); | ||||
recentRejects->insert(tx.GetId()); | recentRejects->insert(tx.GetId()); | ||||
if (RecursiveDynamicUsage(*ptx) < 100000) { | if (RecursiveDynamicUsage(*ptx) < 100000) { | ||||
AddToCompactExtraTransactions(ptx); | AddToCompactExtraTransactions(ptx); | ||||
} | } | ||||
if (pfrom->HasPermission(PF_FORCERELAY)) { | if (pfrom->HasPermission(PF_FORCERELAY)) { | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::TX) { | ||||
state.GetRejectCode() < REJECT_INTERNAL) { | state.GetRejectCode() < REJECT_INTERNAL) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, | pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, | ||||
uint8_t(state.GetRejectCode()), | uint8_t(state.GetRejectCode()), | ||||
state.GetRejectReason().substr( | state.GetRejectReason().substr( | ||||
0, MAX_REJECT_MESSAGE_LENGTH), | 0, MAX_REJECT_MESSAGE_LENGTH), | ||||
inv.hash)); | inv.hash)); | ||||
} | } | ||||
MaybePunishNode(pfrom->GetId(), state, /*via_compact_block*/ false); | MaybePunishNodeForTx(pfrom->GetId(), state); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::CMPCTBLOCK) { | if (strCommand == NetMsgType::CMPCTBLOCK) { | ||||
// Ignore cmpctblock received while importing | // Ignore cmpctblock received while importing | ||||
if (fImporting || fReindex) { | if (fImporting || fReindex) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
Show All 24 Lines | if (strCommand == NetMsgType::CMPCTBLOCK) { | ||||
} | } | ||||
if (!LookupBlockIndex(cmpctblock.header.GetHash())) { | if (!LookupBlockIndex(cmpctblock.header.GetHash())) { | ||||
received_new_header = true; | received_new_header = true; | ||||
} | } | ||||
} | } | ||||
const CBlockIndex *pindex = nullptr; | const CBlockIndex *pindex = nullptr; | ||||
CValidationState state; | BlockValidationState state; | ||||
if (!ProcessNewBlockHeaders(config, {cmpctblock.header}, state, | if (!ProcessNewBlockHeaders(config, {cmpctblock.header}, state, | ||||
&pindex)) { | &pindex)) { | ||||
if (state.IsInvalid()) { | if (state.IsInvalid()) { | ||||
MaybePunishNode(pfrom->GetId(), state, | MaybePunishNodeForBlock(pfrom->GetId(), state, | ||||
/*via_compact_block*/ true, | /*via_compact_block*/ true, | ||||
"invalid header via cmpctblock"); | "invalid header via cmpctblock"); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
// When we succeed in decoding a block's txids from a cmpctblock | // When we succeed in decoding a block's txids from a cmpctblock | ||||
// message we typically jump to the BLOCKTXN handling code, with a | // message we typically jump to the BLOCKTXN handling code, with a | ||||
// dummy (empty) BLOCKTXN message, to re-use the logic there in | // dummy (empty) BLOCKTXN message, to re-use the logic there in | ||||
// completing processing of the putative block (without cs_main). | // completing processing of the putative block (without cs_main). | ||||
▲ Show 20 Lines • Show All 486 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::AVARESPONSE && !fImporting && !fReindex && | ||||
} | } | ||||
if (updates.size()) { | if (updates.size()) { | ||||
for (avalanche::BlockUpdate &u : updates) { | for (avalanche::BlockUpdate &u : updates) { | ||||
CBlockIndex *pindex = u.getBlockIndex(); | CBlockIndex *pindex = u.getBlockIndex(); | ||||
switch (u.getStatus()) { | switch (u.getStatus()) { | ||||
case avalanche::BlockUpdate::Status::Invalid: | case avalanche::BlockUpdate::Status::Invalid: | ||||
case avalanche::BlockUpdate::Status::Rejected: { | case avalanche::BlockUpdate::Status::Rejected: { | ||||
CValidationState state; | BlockValidationState state; | ||||
ParkBlock(config, state, pindex); | ParkBlock(config, state, pindex); | ||||
if (!state.IsValid()) { | if (!state.IsValid()) { | ||||
return error("Database error: %s", | return error("Database error: %s", | ||||
state.GetRejectReason()); | state.GetRejectReason()); | ||||
} | } | ||||
} break; | } break; | ||||
case avalanche::BlockUpdate::Status::Accepted: | case avalanche::BlockUpdate::Status::Accepted: | ||||
case avalanche::BlockUpdate::Status::Finalized: { | case avalanche::BlockUpdate::Status::Finalized: { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
UnparkBlock(pindex); | UnparkBlock(pindex); | ||||
} break; | } break; | ||||
} | } | ||||
} | } | ||||
CValidationState state; | BlockValidationState state; | ||||
if (!ActivateBestChain(config, state)) { | if (!ActivateBestChain(config, state)) { | ||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", | LogPrint(BCLog::NET, "failed to activate chain (%s)\n", | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,403 Lines • Show Last 20 Lines |