Changeset View
Changeset View
Standalone View
Standalone View
test/functional/p2p_permissions.py
Show First 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
["forcerelay", "relay", "noban", "mempool", "download"], | ["forcerelay", "relay", "noban", "mempool", "download"], | ||||
) | ) | ||||
# Let's make sure permissions are merged correctly | # Let's make sure permissions are merged correctly | ||||
# For this, we need to use whitebind instead of bind | # For this, we need to use whitebind instead of bind | ||||
# by modifying the configuration file. | # by modifying the configuration file. | ||||
ip_port = f"127.0.0.1:{p2p_port(1)}" | ip_port = f"127.0.0.1:{p2p_port(1)}" | ||||
self.replaceinconfig( | self.replaceinconfig( | ||||
1, | 1, "bind=127.0.0.1", f"whitebind=bloomfilter,forcerelay@{ip_port}" | ||||
"bind=127.0.0.1", | ) | ||||
f"whitebind=bloomfilter,forcerelay@{ip_port}") | |||||
self.checkpermission( | self.checkpermission( | ||||
["-whitelist=noban@127.0.0.1"], | ["-whitelist=noban@127.0.0.1"], | ||||
# Check parameter interaction forcerelay should activate relay | # Check parameter interaction forcerelay should activate relay | ||||
["noban", "bloomfilter", "forcerelay", "relay", "download"], | ["noban", "bloomfilter", "forcerelay", "relay", "download"], | ||||
) | ) | ||||
self.replaceinconfig( | self.replaceinconfig( | ||||
1, | 1, f"whitebind=bloomfilter,forcerelay@{ip_port}", "bind=127.0.0.1" | ||||
f"whitebind=bloomfilter,forcerelay@{ip_port}", | ) | ||||
"bind=127.0.0.1") | |||||
self.checkpermission( | self.checkpermission( | ||||
# legacy whitelistrelay should be ignored | # legacy whitelistrelay should be ignored | ||||
["-whitelist=noban,mempool@127.0.0.1", "-whitelistrelay"], | ["-whitelist=noban,mempool@127.0.0.1", "-whitelistrelay"], | ||||
["noban", "mempool", "download"], | ["noban", "mempool", "download"], | ||||
) | ) | ||||
self.checkpermission( | self.checkpermission( | ||||
Show All 12 Lines | def run_test(self): | ||||
# missing mempool permission to be considered legacy whitelisted | # missing mempool permission to be considered legacy whitelisted | ||||
["-whitelist=noban@127.0.0.1"], | ["-whitelist=noban@127.0.0.1"], | ||||
["noban", "download"], | ["noban", "download"], | ||||
) | ) | ||||
self.checkpermission( | self.checkpermission( | ||||
# all permission added | # all permission added | ||||
["-whitelist=all@127.0.0.1"], | ["-whitelist=all@127.0.0.1"], | ||||
["forcerelay", "noban", "mempool", "bloomfilter", | [ | ||||
"relay", "download", "bypass_proof_request_limits", "addr"], | "forcerelay", | ||||
"noban", | |||||
"mempool", | |||||
"bloomfilter", | |||||
"relay", | |||||
"download", | |||||
"bypass_proof_request_limits", | |||||
"addr", | |||||
], | |||||
) | ) | ||||
self.checkpermission( | self.checkpermission( | ||||
# bypass_proof_request_limits permission | # bypass_proof_request_limits permission | ||||
["-whitelist=bypass_proof_request_limits@127.0.0.1"], | ["-whitelist=bypass_proof_request_limits@127.0.0.1"], | ||||
["bypass_proof_request_limits"], | ["bypass_proof_request_limits"], | ||||
) | ) | ||||
self.stop_node(1) | self.stop_node(1) | ||||
self.nodes[1].assert_start_raises_init_error( | self.nodes[1].assert_start_raises_init_error( | ||||
["-whitelist=oopsie@127.0.0.1"], | ["-whitelist=oopsie@127.0.0.1"], | ||||
"Invalid P2P permission", | "Invalid P2P permission", | ||||
match=ErrorMatch.PARTIAL_REGEX) | match=ErrorMatch.PARTIAL_REGEX, | ||||
) | |||||
self.nodes[1].assert_start_raises_init_error( | self.nodes[1].assert_start_raises_init_error( | ||||
["-whitelist=noban@127.0.0.1:230"], | ["-whitelist=noban@127.0.0.1:230"], | ||||
"Invalid netmask specified in", | "Invalid netmask specified in", | ||||
match=ErrorMatch.PARTIAL_REGEX) | match=ErrorMatch.PARTIAL_REGEX, | ||||
) | |||||
self.nodes[1].assert_start_raises_init_error( | self.nodes[1].assert_start_raises_init_error( | ||||
["-whitebind=noban@127.0.0.1/10"], | ["-whitebind=noban@127.0.0.1/10"], | ||||
"Cannot resolve -whitebind address", | "Cannot resolve -whitebind address", | ||||
match=ErrorMatch.PARTIAL_REGEX) | match=ErrorMatch.PARTIAL_REGEX, | ||||
) | |||||
def check_tx_relay(self): | def check_tx_relay(self): | ||||
block_op_true = self.nodes[0].getblock( | block_op_true = self.nodes[0].getblock( | ||||
self.generatetoaddress(self.nodes[0], 100, ADDRESS_ECREG_P2SH_OP_TRUE)[0]) | self.generatetoaddress(self.nodes[0], 100, ADDRESS_ECREG_P2SH_OP_TRUE)[0] | ||||
) | |||||
self.log.debug( | self.log.debug( | ||||
"Create a connection from a forcerelay peer that rebroadcasts raw txs") | "Create a connection from a forcerelay peer that rebroadcasts raw txs" | ||||
) | |||||
# A python mininode is needed to send the raw transaction directly. | # A python mininode is needed to send the raw transaction directly. | ||||
# If a full node was used, it could only rebroadcast via the inv-getdata | # If a full node was used, it could only rebroadcast via the inv-getdata | ||||
# mechanism. However, even for forcerelay connections, a full node would | # mechanism. However, even for forcerelay connections, a full node would | ||||
# currently not request a txid that is already in the mempool. | # currently not request a txid that is already in the mempool. | ||||
self.restart_node(1, extra_args=["-whitelist=forcerelay@127.0.0.1"]) | self.restart_node(1, extra_args=["-whitelist=forcerelay@127.0.0.1"]) | ||||
p2p_rebroadcast_wallet = self.nodes[1].add_p2p_connection( | p2p_rebroadcast_wallet = self.nodes[1].add_p2p_connection(P2PDataStore()) | ||||
P2PDataStore()) | |||||
self.log.debug("Send a tx from the wallet initially") | self.log.debug("Send a tx from the wallet initially") | ||||
tx = FromHex(CTransaction(), | tx = FromHex( | ||||
CTransaction(), | |||||
self.nodes[0].createrawtransaction( | self.nodes[0].createrawtransaction( | ||||
inputs=[{'txid': block_op_true['tx'][0], 'vout': 0}], | inputs=[{"txid": block_op_true["tx"][0], "vout": 0}], | ||||
outputs=[{ADDRESS_ECREG_P2SH_OP_TRUE: 50}])) | outputs=[{ADDRESS_ECREG_P2SH_OP_TRUE: 50}], | ||||
), | |||||
) | |||||
# push the one byte script to the stack | # push the one byte script to the stack | ||||
tx.vin[0].scriptSig = SCRIPTSIG_OP_TRUE | tx.vin[0].scriptSig = SCRIPTSIG_OP_TRUE | ||||
pad_tx(tx) | pad_tx(tx) | ||||
txid = tx.rehash() | txid = tx.rehash() | ||||
self.log.debug("Wait until tx is in node[1]'s mempool") | self.log.debug("Wait until tx is in node[1]'s mempool") | ||||
p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1]) | p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1]) | ||||
self.log.debug( | self.log.debug( | ||||
"Check that node[1] will send the tx to node[0] even though it" | "Check that node[1] will send the tx to node[0] even though it" | ||||
" is already in the mempool") | " is already in the mempool" | ||||
) | |||||
self.connect_nodes(1, 0) | self.connect_nodes(1, 0) | ||||
with self.nodes[1].assert_debug_log( | with self.nodes[1].assert_debug_log([f"Force relaying tx {txid} from peer=0"]): | ||||
[f"Force relaying tx {txid} from peer=0"]): | |||||
p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1]) | p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1]) | ||||
self.wait_until(lambda: txid in self.nodes[0].getrawmempool()) | self.wait_until(lambda: txid in self.nodes[0].getrawmempool()) | ||||
self.log.debug( | self.log.debug("Check that node[1] will not send an invalid tx to node[0]") | ||||
"Check that node[1] will not send an invalid tx to node[0]") | |||||
tx.vout[0].nValue += 1 | tx.vout[0].nValue += 1 | ||||
txid = tx.rehash() | txid = tx.rehash() | ||||
# Send the transaction twice. The first time, it'll be rejected by ATMP | # Send the transaction twice. The first time, it'll be rejected by ATMP | ||||
# because it conflicts with a mempool transaction. The second time, | # because it conflicts with a mempool transaction. The second time, | ||||
# it'll be in the m_recent_rejects filter. | # it'll be in the m_recent_rejects filter. | ||||
p2p_rebroadcast_wallet.send_txs_and_test( | p2p_rebroadcast_wallet.send_txs_and_test( | ||||
[tx], | [tx], | ||||
self.nodes[1], | self.nodes[1], | ||||
success=False, | success=False, | ||||
reject_reason=f'{txid} from peer=0 was not accepted: ' | reject_reason=f"{txid} from peer=0 was not accepted: txn-mempool-conflict", | ||||
f'txn-mempool-conflict', | |||||
) | ) | ||||
p2p_rebroadcast_wallet.send_txs_and_test( | p2p_rebroadcast_wallet.send_txs_and_test( | ||||
[tx], | [tx], | ||||
self.nodes[1], | self.nodes[1], | ||||
success=False, | success=False, | ||||
reject_reason=f'Not relaying non-mempool transaction {txid} from ' | reject_reason=( | ||||
f'forcerelay peer=0', | f"Not relaying non-mempool transaction {txid} from forcerelay peer=0" | ||||
), | |||||
) | ) | ||||
def checkpermission(self, args, expectedPermissions): | def checkpermission(self, args, expectedPermissions): | ||||
self.restart_node(1, args) | self.restart_node(1, args) | ||||
self.connect_nodes(0, 1) | self.connect_nodes(0, 1) | ||||
peerinfo = self.nodes[1].getpeerinfo()[0] | peerinfo = self.nodes[1].getpeerinfo()[0] | ||||
assert_equal(len(expectedPermissions), len(peerinfo['permissions'])) | assert_equal(len(expectedPermissions), len(peerinfo["permissions"])) | ||||
for p in expectedPermissions: | for p in expectedPermissions: | ||||
if p not in peerinfo['permissions']: | if p not in peerinfo["permissions"]: | ||||
raise AssertionError( | raise AssertionError(f"Expected permissions {p!r} is not granted.") | ||||
f"Expected permissions {p!r} is not granted.") | |||||
def replaceinconfig(self, nodeid, old, new): | def replaceinconfig(self, nodeid, old, new): | ||||
with open(self.nodes[nodeid].bitcoinconf, encoding="utf8") as f: | with open(self.nodes[nodeid].bitcoinconf, encoding="utf8") as f: | ||||
newText = f.read().replace(old, new) | newText = f.read().replace(old, new) | ||||
with open(self.nodes[nodeid].bitcoinconf, 'w', encoding="utf8") as f: | with open(self.nodes[nodeid].bitcoinconf, "w", encoding="utf8") as f: | ||||
f.write(newText) | f.write(newText) | ||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
P2PPermissionsTests().main() | P2PPermissionsTests().main() |