aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp124
1 files changed, 71 insertions, 53 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 27ab677eb..2c98de070 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -196,7 +196,7 @@ namespace {
*
* Memory used: 1.3 MB
*/
- boost::scoped_ptr<CRollingBloomFilter> recentRejects;
+ std::unique_ptr<CRollingBloomFilter> recentRejects;
uint256 hashRecentRejectsChainTip;
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
@@ -532,7 +532,7 @@ CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) {
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
* at most count entries. */
-void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller) {
+void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams) {
if (count == 0)
return;
@@ -589,6 +589,10 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl
// We consider the chain that this peer is on invalid.
return;
}
+ if (!State(nodeid)->fHaveWitness && IsWitnessEnabled(pindex->pprev, consensusParams)) {
+ // We wouldn't download this block or its descendants from this peer.
+ return;
+ }
if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
if (pindex->nChainTx)
state->pindexLastCommonBlock = pindex;
@@ -1492,13 +1496,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true)) {
+ PrecomputedTransactionData txdata(tx);
+ if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata)) {
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// need to turn both off, and compare against just turning off CLEANSTACK
// to see if the failure is specifically due to witness validation.
- if (CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true) &&
- !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true)) {
- // Only the witness is wrong, so the transaction itself may be fine.
+ if (tx.wit.IsNull() && CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata) &&
+ !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata)) {
+ // Only the witness is missing, so the transaction itself may be fine.
state.SetCorruptionPossible();
}
return false;
@@ -1513,7 +1518,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
- if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true))
+ if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata))
{
return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s",
__func__, hash.ToString(), FormatStateMessage(state));
@@ -1910,7 +1915,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
const CScriptWitness *witness = (nIn < ptxTo->wit.vtxinwit.size()) ? &ptxTo->wit.vtxinwit[nIn].scriptWitness : NULL;
- if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore), &error)) {
+ if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error)) {
return false;
}
return true;
@@ -1969,7 +1974,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
}
}// namespace Consensus
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
@@ -1996,7 +2001,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
assert(coins);
// Verify signature
- CScriptCheck check(*coins, tx, i, flags, cacheStore);
+ CScriptCheck check(*coins, tx, i, flags, cacheStore, &txdata);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -2009,7 +2014,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// avoid splitting the network between upgraded and
// non-upgraded nodes.
CScriptCheck check2(*coins, tx, i,
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata);
if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
@@ -2405,6 +2410,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
vPos.reserve(block.vtx.size());
blockundo.vtxundo.reserve(block.vtx.size() - 1);
+ std::vector<PrecomputedTransactionData> txdata;
+ 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];
@@ -2451,13 +2458,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops");
+ txdata.emplace_back(tx);
if (!tx.IsCoinBase())
{
nFees += view.GetValueIn(tx)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks;
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
- if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL))
+ if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : NULL))
return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state));
control.Add(vChecks);
@@ -4633,6 +4641,7 @@ std::string GetWarnings(const std::string& strFor)
string strStatusBar;
string strRPC;
string strGUI;
+ const string uiAlertSeperator = "<hr />";
if (!CLIENT_VERSION_IS_RELEASE) {
strStatusBar = "This is a pre-release test build - use at your own risk - do not use for mining or merchant applications";
@@ -4645,18 +4654,19 @@ std::string GetWarnings(const std::string& strFor)
// Misc warnings like out of disk space and clock is wrong
if (strMiscWarning != "")
{
- strStatusBar = strGUI = strMiscWarning;
+ strStatusBar = strMiscWarning;
+ strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + strMiscWarning;
}
if (fLargeWorkForkFound)
{
strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
- strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
+ strGUI += strGUI.empty() ? "" : uiAlertSeperator + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
}
else if (fLargeWorkInvalidChainFound)
{
strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.";
- strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
+ strGUI += strGUI.empty() ? "" : uiAlertSeperator + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
}
if (strFor == "gui")
@@ -4779,10 +4789,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
pfrom->PushMessage(NetMsgType::BLOCK, block);
else if (inv.type == MSG_FILTERED_BLOCK)
{
- LOCK(pfrom->cs_filter);
- if (pfrom->pfilter)
+ bool send = false;
+ CMerkleBlock merkleBlock;
{
- CMerkleBlock merkleBlock(block, *pfrom->pfilter);
+ LOCK(pfrom->cs_filter);
+ if (pfrom->pfilter) {
+ send = true;
+ merkleBlock = CMerkleBlock(block, *pfrom->pfilter);
+ }
+ }
+ if (send) {
pfrom->PushMessage(NetMsgType::MERKLEBLOCK, merkleBlock);
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
// This avoids hurting performance by pointlessly requiring a round-trip
@@ -4903,6 +4919,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (strCommand == NetMsgType::VERSION)
{
+ // Feeler connections exist only to verify if address is online.
+ if (pfrom->fFeeler) {
+ assert(pfrom->fInbound == false);
+ pfrom->fDisconnect = true;
+ }
+
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
@@ -5005,11 +5027,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CAddress addr = GetLocalAddress(&pfrom->addr);
if (addr.IsRoutable())
{
- LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString());
+ LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr);
} else if (IsPeerAddrLocalGood(pfrom)) {
addr.SetIP(pfrom->addrLocal);
- LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString());
+ LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr);
}
}
@@ -5021,12 +5043,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->fGetAddr = true;
}
addrman.Good(pfrom->addr);
- } else {
- if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom)
- {
- addrman.Add(addrFrom, addrFrom);
- addrman.Good(addrFrom);
- }
}
pfrom->fSuccessfullyConnected = true;
@@ -5387,7 +5403,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
vector<CBlock> vHeaders;
int nLimit = MAX_HEADERS_RESULTS;
- LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id);
+ LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom->id);
for (; pindex; pindex = chainActive.Next(pindex))
{
vHeaders.push_back(pindex->GetBlockHeader());
@@ -5477,7 +5493,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (!fMissingInputs2)
{
int nDos = 0;
- if (stateDummy.IsInvalid(nDos) && nDos > 0 && (!state.CorruptionPossible() || State(fromPeer)->fHaveWitness))
+ if (stateDummy.IsInvalid(nDos) && nDos > 0)
{
// Punish peer that gave us an invalid orphan tx
Misbehaving(fromPeer, nDos);
@@ -5488,7 +5504,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Probably non-standard or insufficient fee/priority
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
vEraseQueue.push_back(orphanHash);
- if (!stateDummy.CorruptionPossible()) {
+ if (orphanTx.wit.IsNull() && !stateDummy.CorruptionPossible()) {
+ // Do not use rejection cache for witness transactions or
+ // witness-stripped transactions, as they can have been malleated.
+ // See https://github.com/bitcoin/bitcoin/issues/8279 for details.
assert(recentRejects);
recentRejects->insert(orphanHash);
}
@@ -5526,7 +5545,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint("mempool", "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
}
} else {
- if (!state.CorruptionPossible()) {
+ if (tx.wit.IsNull() && !state.CorruptionPossible()) {
+ // Do not use rejection cache for witness transactions or
+ // witness-stripped transactions, as they can have been malleated.
+ // See https://github.com/bitcoin/bitcoin/issues/8279 for details.
assert(recentRejects);
recentRejects->insert(tx.GetHash());
}
@@ -5558,9 +5580,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
- if (nDoS > 0 && (!state.CorruptionPossible() || State(pfrom->id)->fHaveWitness)) {
- // When a non-witness-supporting peer gives us a transaction that would
- // be accepted if witness validation was off, we can't blame them for it.
+ if (nDoS > 0) {
Misbehaving(pfrom->GetId(), nDoS);
}
}
@@ -6044,8 +6064,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CBloomFilter filter;
vRecv >> filter;
- LOCK(pfrom->cs_filter);
-
if (!filter.IsWithinSizeConstraints())
{
// There is no excuse for sending a too-large filter
@@ -6054,11 +6072,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
else
{
+ LOCK(pfrom->cs_filter);
delete pfrom->pfilter;
pfrom->pfilter = new CBloomFilter(filter);
pfrom->pfilter->UpdateEmptyFull();
+ pfrom->fRelayTxes = true;
}
- pfrom->fRelayTxes = true;
}
@@ -6069,20 +6088,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Nodes must NEVER send a data item > 520 bytes (the max size for a script data object,
// and thus, the maximum size any matched object can have) in a filteradd message
- if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE)
- {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 100);
+ bool bad = false;
+ if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) {
+ bad = true;
} else {
LOCK(pfrom->cs_filter);
- if (pfrom->pfilter)
+ if (pfrom->pfilter) {
pfrom->pfilter->insert(vData);
- else
- {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 100);
+ } else {
+ bad = true;
}
}
+ if (bad) {
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 100);
+ }
}
@@ -6705,15 +6725,13 @@ bool SendMessages(CNode* pto)
if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
vector<CBlockIndex*> vToDownload;
NodeId staller = -1;
- FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
+ FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
BOOST_FOREACH(CBlockIndex *pindex, vToDownload) {
- if (State(pto->GetId())->fHaveWitness || !IsWitnessEnabled(pindex->pprev, consensusParams)) {
- uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
- vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
- MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
- LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
- pindex->nHeight, pto->id);
- }
+ uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
+ vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
+ MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
+ LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
+ pindex->nHeight, pto->id);
}
if (state.nBlocksInFlight == 0 && staller != -1) {
if (State(staller)->nStallingSince == 0) {