Skip to content

Commit 6664587

Browse files
committed
Merge #1515: v30 patches
b7ee5fb Merge bitcoin/bitcoin#33001: test: Do not pass tests on unhandled exceptions (merge-script) 1ac1f75 Merge bitcoin/bitcoin#32765: test: Fix list index out of range error in feature_bip68_sequence.py (merge-script) 0f06ceb Merge bitcoin/bitcoin#33395: net: do not apply whitelist permissions to onion inbounds (merge-script) 53a5bd0 Merge bitcoin/bitcoin#33296: net: check for empty header before calling FillBlock (Ava Chow) Pull request description: Cherry-picks of bugfix patches included in the Bitcoin v30 release. net: check for empty header before calling FillBlock bitcoin/bitcoin#33296 net: do not apply whitelist permissions to onion inbounds bitcoin/bitcoin#33395 test: Fix list index out of range error in feature_bip68_sequence.py bitcoin/bitcoin#32765 test: Do not pass tests on unhandled exceptions bitcoin/bitcoin#33001 ACKs for top commit: delta1: ACK b7ee5fb Tree-SHA512: 7fee367e549a0a5f8b2461be317dc8469feb0f907993f86638e9ca8ca333f9643fa90ecec4dd4edeba2d7e9098aa953f047dbaa0d35a9fc75a68fb62391c7616
2 parents 7820602 + b7ee5fb commit 6664587

File tree

6 files changed

+69
-23
lines changed

6 files changed

+69
-23
lines changed

src/net.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -569,9 +569,9 @@ void CNode::CloseSocketDisconnect()
569569
}
570570
}
571571

572-
void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const {
572+
void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr) const {
573573
for (const auto& subnet : vWhitelistedRange) {
574-
if (subnet.m_subnet.Match(addr)) NetPermissions::AddFlag(flags, subnet.m_flags);
574+
if (addr.has_value() && subnet.m_subnet.Match(addr.value())) NetPermissions::AddFlag(flags, subnet.m_flags);
575575
}
576576
}
577577

@@ -1179,7 +1179,10 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
11791179
int nInbound = 0;
11801180
int nMaxInbound = nMaxConnections - m_max_outbound;
11811181

1182-
AddWhitelistPermissionFlags(permissionFlags, addr);
1182+
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
1183+
// Tor inbound connections do not reveal the peer's actual network address.
1184+
// Therefore do not apply address-based whitelist permissions to them.
1185+
AddWhitelistPermissionFlags(permissionFlags, inbound_onion ? std::optional<CNetAddr>{} : addr);
11831186
if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::Implicit)) {
11841187
NetPermissions::ClearFlag(permissionFlags, NetPermissionFlags::Implicit);
11851188
if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) NetPermissions::AddFlag(permissionFlags, NetPermissionFlags::ForceRelay);
@@ -1243,7 +1246,6 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
12431246
nodeServices = static_cast<ServiceFlags>(nodeServices | NODE_BLOOM);
12441247
}
12451248

1246-
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
12471249
CNode* pnode = new CNode(id,
12481250
nodeServices,
12491251
std::move(sock),

src/net.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,7 @@ class CConnman
10771077

10781078
bool AttemptToEvictConnection();
10791079
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type);
1080-
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
1080+
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr) const;
10811081

10821082
void DeleteNode(CNode* pnode);
10831083

src/net_processing.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3772,13 +3772,27 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
37723772
}
37733773

37743774
PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock;
3775+
3776+
if (partialBlock.header.IsNull()) {
3777+
// It is possible for the header to be empty if a previous call to FillBlock wiped the header, but left
3778+
// the PartiallyDownloadedBlock pointer around (i.e. did not call RemoveBlockRequest). In this case, we
3779+
// should not call LookupBlockIndex below.
3780+
RemoveBlockRequest(resp.blockhash, pfrom.GetId());
3781+
Misbehaving(pfrom.GetId(), 100, "previous compact block reconstruction attempt failed");
3782+
LogPrint(BCLog::NET, "Peer %d sent compact block transactions multiple times\n", pfrom.GetId());
3783+
return;
3784+
}
3785+
37753786
ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn);
37763787
if (status == READ_STATUS_INVALID) {
37773788
RemoveBlockRequest(resp.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
37783789
Misbehaving(pfrom.GetId(), 100, "invalid compact block/non-matching block transactions");
37793790
return;
37803791
} else if (status == READ_STATUS_FAILED) {
37813792
// Might have collided, fall back to getdata now :(
3793+
// We keep the failed partialBlock to disallow processing another compact block announcement from the same
3794+
// peer for the same block. We let the full block download below continue under the same m_downloading_since
3795+
// timer.
37823796
std::vector<CInv> invs;
37833797
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom), resp.blockhash));
37843798
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));

test/functional/feature_bip68_sequence.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,10 @@ def test_sequence_lock_confirmed_inputs(self):
161161
# between height/time locking). Small random chance of making the locks
162162
# all pass.
163163
for _ in range(400):
164+
available_utxos = len(utxos)
165+
164166
# Randomly choose up to 10 inputs
165-
num_inputs = random.randint(1, 10)
167+
num_inputs = random.randint(1, min(10, available_utxos))
166168
random.shuffle(utxos)
167169

168170
# Track whether any sequence locks used should fail

test/functional/p2p_compactblocks.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ def test_invalid_cmpctblock_message(self):
285285
# This index will be too high
286286
prefilled_txn = PrefilledTransaction(1, block.vtx[0])
287287
cmpct_block.prefilled_txn = [prefilled_txn]
288-
self.segwit_node.send_await_disconnect(msg_cmpctblock(cmpct_block))
288+
self.additional_segwit_node.send_await_disconnect(msg_cmpctblock(cmpct_block))
289289
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.hashPrevBlock)
290290

291291
# Compare the generated shortids to what we expect based on BIP 152, given
@@ -603,6 +603,42 @@ def test_incorrect_blocktxn_response(self, test_node):
603603
test_node.send_and_ping(msg_no_witness_block(block))
604604
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
605605

606+
# Multiple blocktxn responses will cause a node to get disconnected.
607+
def test_multiple_blocktxn_response(self, test_node):
608+
node = self.nodes[0]
609+
utxo = self.utxos[0]
610+
611+
block = self.build_block_with_transactions(node, utxo, 2)
612+
613+
# Send compact block
614+
comp_block = HeaderAndShortIDs()
615+
comp_block.initialize_from_block(block, prefill_list=[0], use_witness=True)
616+
test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
617+
absolute_indexes = []
618+
with p2p_lock:
619+
assert "getblocktxn" in test_node.last_message
620+
absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute()
621+
assert_equal(absolute_indexes, [1, 2])
622+
623+
# Send a blocktxn that does not succeed in reconstruction, triggering
624+
# getdata fallback.
625+
msg = msg_blocktxn()
626+
msg.block_transactions = BlockTransactions(block.sha256, [block.vtx[2]] + [block.vtx[1]])
627+
test_node.send_and_ping(msg)
628+
629+
# Tip should not have updated
630+
assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
631+
632+
# We should receive a getdata request
633+
test_node.wait_for_getdata([block.sha256], timeout=10)
634+
assert test_node.last_message["getdata"].inv[0].type == MSG_BLOCK or \
635+
test_node.last_message["getdata"].inv[0].type == MSG_BLOCK | MSG_WITNESS_FLAG
636+
637+
# Send the same blocktxn and assert the sender gets disconnected.
638+
with node.assert_debug_log(['previous compact block reconstruction attempt failed']):
639+
test_node.send_message(msg)
640+
test_node.wait_for_disconnect()
641+
606642
def test_getblocktxn_handler(self, test_node):
607643
version = test_node.cmpct_version
608644
node = self.nodes[0]
@@ -897,12 +933,16 @@ def run_test(self):
897933
self.test_invalid_tx_in_compactblock(self.segwit_node)
898934
self.test_invalid_tx_in_compactblock(self.old_node)
899935

936+
self.log.info("Testing handling of multiple blocktxn responses...")
937+
self.test_multiple_blocktxn_response(self.segwit_node)
938+
939+
self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=2))
940+
900941
self.log.info("Testing invalid index in cmpctblock message...")
901942
self.test_invalid_cmpctblock_message()
902943

903944
self.log.info("Testing high-bandwidth mode states via getpeerinfo...")
904945
self.test_highbandwidth_mode_states_via_getpeerinfo()
905946

906-
907947
if __name__ == '__main__':
908948
CompactBlocksTest().main()

test/functional/test_framework/test_framework.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -130,26 +130,14 @@ def main(self):
130130
try:
131131
self.setup()
132132
self.run_test()
133-
except JSONRPCException:
134-
self.log.exception("JSONRPC error")
135-
self.success = TestStatus.FAILED
136133
except SkipTest as e:
137134
self.log.warning("Test Skipped: %s" % e.message)
138135
self.success = TestStatus.SKIPPED
139-
except AssertionError:
140-
self.log.exception("Assertion failed")
141-
self.success = TestStatus.FAILED
142-
except KeyError:
143-
self.log.exception("Key error")
144-
self.success = TestStatus.FAILED
145136
except subprocess.CalledProcessError as e:
146-
self.log.exception("Called Process failed with '{}'".format(e.output))
147-
self.success = TestStatus.FAILED
148-
except Exception:
149-
self.log.exception("Unexpected exception caught during testing")
137+
self.log.exception(f"Called Process failed with stdout='{e.stdout}'; stderr='{e.stderr}';")
150138
self.success = TestStatus.FAILED
151-
except KeyboardInterrupt:
152-
self.log.warning("Exiting after keyboard interrupt")
139+
except BaseException:
140+
self.log.exception("Unexpected exception")
153141
self.success = TestStatus.FAILED
154142
finally:
155143
exit_code = self.shutdown()

0 commit comments

Comments
 (0)