mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-19 13:27:35 +02:00
Merge ElementsProject/elements#1515: v30 patches
b7ee5fb8a5Merge bitcoin/bitcoin#33001: test: Do not pass tests on unhandled exceptions (merge-script)1ac1f75ec0Merge bitcoin/bitcoin#32765: test: Fix list index out of range error in feature_bip68_sequence.py (merge-script)0f06cebc61Merge bitcoin/bitcoin#33395: net: do not apply whitelist permissions to onion inbounds (merge-script)53a5bd0790Merge 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 https://github.com/bitcoin/bitcoin/pull/33296 net: do not apply whitelist permissions to onion inbounds https://github.com/bitcoin/bitcoin/pull/33395 test: Fix list index out of range error in feature_bip68_sequence.py https://github.com/bitcoin/bitcoin/pull/32765 test: Do not pass tests on unhandled exceptions https://github.com/bitcoin/bitcoin/pull/33001 ACKs for top commit: delta1: ACKb7ee5fb8a5Tree-SHA512: 7fee367e549a0a5f8b2461be317dc8469feb0f907993f86638e9ca8ca333f9643fa90ecec4dd4edeba2d7e9098aa953f047dbaa0d35a9fc75a68fb62391c7616
This commit is contained in:
commit
6664587c2f
6 changed files with 69 additions and 23 deletions
10
src/net.cpp
10
src/net.cpp
|
|
@ -569,9 +569,9 @@ void CNode::CloseSocketDisconnect()
|
|||
}
|
||||
}
|
||||
|
||||
void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const {
|
||||
void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr) const {
|
||||
for (const auto& subnet : vWhitelistedRange) {
|
||||
if (subnet.m_subnet.Match(addr)) NetPermissions::AddFlag(flags, subnet.m_flags);
|
||||
if (addr.has_value() && subnet.m_subnet.Match(addr.value())) NetPermissions::AddFlag(flags, subnet.m_flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1179,7 +1179,10 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
|||
int nInbound = 0;
|
||||
int nMaxInbound = nMaxConnections - m_max_outbound;
|
||||
|
||||
AddWhitelistPermissionFlags(permissionFlags, addr);
|
||||
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
|
||||
// Tor inbound connections do not reveal the peer's actual network address.
|
||||
// Therefore do not apply address-based whitelist permissions to them.
|
||||
AddWhitelistPermissionFlags(permissionFlags, inbound_onion ? std::optional<CNetAddr>{} : addr);
|
||||
if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::Implicit)) {
|
||||
NetPermissions::ClearFlag(permissionFlags, NetPermissionFlags::Implicit);
|
||||
if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) NetPermissions::AddFlag(permissionFlags, NetPermissionFlags::ForceRelay);
|
||||
|
|
@ -1243,7 +1246,6 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
|||
nodeServices = static_cast<ServiceFlags>(nodeServices | NODE_BLOOM);
|
||||
}
|
||||
|
||||
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
|
||||
CNode* pnode = new CNode(id,
|
||||
nodeServices,
|
||||
std::move(sock),
|
||||
|
|
|
|||
|
|
@ -1077,7 +1077,7 @@ private:
|
|||
|
||||
bool AttemptToEvictConnection();
|
||||
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type);
|
||||
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
|
||||
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr) const;
|
||||
|
||||
void DeleteNode(CNode* pnode);
|
||||
|
||||
|
|
|
|||
|
|
@ -3772,6 +3772,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
|||
}
|
||||
|
||||
PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock;
|
||||
|
||||
if (partialBlock.header.IsNull()) {
|
||||
// It is possible for the header to be empty if a previous call to FillBlock wiped the header, but left
|
||||
// the PartiallyDownloadedBlock pointer around (i.e. did not call RemoveBlockRequest). In this case, we
|
||||
// should not call LookupBlockIndex below.
|
||||
RemoveBlockRequest(resp.blockhash, pfrom.GetId());
|
||||
Misbehaving(pfrom.GetId(), 100, "previous compact block reconstruction attempt failed");
|
||||
LogPrint(BCLog::NET, "Peer %d sent compact block transactions multiple times\n", pfrom.GetId());
|
||||
return;
|
||||
}
|
||||
|
||||
ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn);
|
||||
if (status == READ_STATUS_INVALID) {
|
||||
RemoveBlockRequest(resp.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
|
||||
|
|
@ -3779,6 +3790,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
|||
return;
|
||||
} else if (status == READ_STATUS_FAILED) {
|
||||
// Might have collided, fall back to getdata now :(
|
||||
// We keep the failed partialBlock to disallow processing another compact block announcement from the same
|
||||
// peer for the same block. We let the full block download below continue under the same m_downloading_since
|
||||
// timer.
|
||||
std::vector<CInv> invs;
|
||||
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom), resp.blockhash));
|
||||
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
|
||||
|
|
|
|||
|
|
@ -161,8 +161,10 @@ class BIP68Test(BitcoinTestFramework):
|
|||
# between height/time locking). Small random chance of making the locks
|
||||
# all pass.
|
||||
for _ in range(400):
|
||||
available_utxos = len(utxos)
|
||||
|
||||
# Randomly choose up to 10 inputs
|
||||
num_inputs = random.randint(1, 10)
|
||||
num_inputs = random.randint(1, min(10, available_utxos))
|
||||
random.shuffle(utxos)
|
||||
|
||||
# Track whether any sequence locks used should fail
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||
# This index will be too high
|
||||
prefilled_txn = PrefilledTransaction(1, block.vtx[0])
|
||||
cmpct_block.prefilled_txn = [prefilled_txn]
|
||||
self.segwit_node.send_await_disconnect(msg_cmpctblock(cmpct_block))
|
||||
self.additional_segwit_node.send_await_disconnect(msg_cmpctblock(cmpct_block))
|
||||
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.hashPrevBlock)
|
||||
|
||||
# Compare the generated shortids to what we expect based on BIP 152, given
|
||||
|
|
@ -603,6 +603,42 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||
test_node.send_and_ping(msg_no_witness_block(block))
|
||||
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
|
||||
|
||||
# Multiple blocktxn responses will cause a node to get disconnected.
|
||||
def test_multiple_blocktxn_response(self, test_node):
|
||||
node = self.nodes[0]
|
||||
utxo = self.utxos[0]
|
||||
|
||||
block = self.build_block_with_transactions(node, utxo, 2)
|
||||
|
||||
# Send compact block
|
||||
comp_block = HeaderAndShortIDs()
|
||||
comp_block.initialize_from_block(block, prefill_list=[0], use_witness=True)
|
||||
test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
|
||||
absolute_indexes = []
|
||||
with p2p_lock:
|
||||
assert "getblocktxn" in test_node.last_message
|
||||
absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute()
|
||||
assert_equal(absolute_indexes, [1, 2])
|
||||
|
||||
# Send a blocktxn that does not succeed in reconstruction, triggering
|
||||
# getdata fallback.
|
||||
msg = msg_blocktxn()
|
||||
msg.block_transactions = BlockTransactions(block.sha256, [block.vtx[2]] + [block.vtx[1]])
|
||||
test_node.send_and_ping(msg)
|
||||
|
||||
# Tip should not have updated
|
||||
assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
|
||||
|
||||
# We should receive a getdata request
|
||||
test_node.wait_for_getdata([block.sha256], timeout=10)
|
||||
assert test_node.last_message["getdata"].inv[0].type == MSG_BLOCK or \
|
||||
test_node.last_message["getdata"].inv[0].type == MSG_BLOCK | MSG_WITNESS_FLAG
|
||||
|
||||
# Send the same blocktxn and assert the sender gets disconnected.
|
||||
with node.assert_debug_log(['previous compact block reconstruction attempt failed']):
|
||||
test_node.send_message(msg)
|
||||
test_node.wait_for_disconnect()
|
||||
|
||||
def test_getblocktxn_handler(self, test_node):
|
||||
version = test_node.cmpct_version
|
||||
node = self.nodes[0]
|
||||
|
|
@ -897,12 +933,16 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||
self.test_invalid_tx_in_compactblock(self.segwit_node)
|
||||
self.test_invalid_tx_in_compactblock(self.old_node)
|
||||
|
||||
self.log.info("Testing handling of multiple blocktxn responses...")
|
||||
self.test_multiple_blocktxn_response(self.segwit_node)
|
||||
|
||||
self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=2))
|
||||
|
||||
self.log.info("Testing invalid index in cmpctblock message...")
|
||||
self.test_invalid_cmpctblock_message()
|
||||
|
||||
self.log.info("Testing high-bandwidth mode states via getpeerinfo...")
|
||||
self.test_highbandwidth_mode_states_via_getpeerinfo()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
CompactBlocksTest().main()
|
||||
|
|
|
|||
|
|
@ -130,26 +130,14 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
|||
try:
|
||||
self.setup()
|
||||
self.run_test()
|
||||
except JSONRPCException:
|
||||
self.log.exception("JSONRPC error")
|
||||
self.success = TestStatus.FAILED
|
||||
except SkipTest as e:
|
||||
self.log.warning("Test Skipped: %s" % e.message)
|
||||
self.success = TestStatus.SKIPPED
|
||||
except AssertionError:
|
||||
self.log.exception("Assertion failed")
|
||||
self.success = TestStatus.FAILED
|
||||
except KeyError:
|
||||
self.log.exception("Key error")
|
||||
self.success = TestStatus.FAILED
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.log.exception("Called Process failed with '{}'".format(e.output))
|
||||
self.log.exception(f"Called Process failed with stdout='{e.stdout}'; stderr='{e.stderr}';")
|
||||
self.success = TestStatus.FAILED
|
||||
except Exception:
|
||||
self.log.exception("Unexpected exception caught during testing")
|
||||
self.success = TestStatus.FAILED
|
||||
except KeyboardInterrupt:
|
||||
self.log.warning("Exiting after keyboard interrupt")
|
||||
except BaseException:
|
||||
self.log.exception("Unexpected exception")
|
||||
self.success = TestStatus.FAILED
|
||||
finally:
|
||||
exit_code = self.shutdown()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue