2019-06-21 06:15:26 +02:00
#!/usr/bin/env python3
2021-07-28 13:57:16 +02:00
# Copyright (c) 2015-2021 The Bitcoin Core developers
2019-06-21 06:15:26 +02:00
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
""" Test p2p permission message.
Test that permissions are correctly calculated and applied
"""
2020-01-22 21:27:14 +01:00
from test_framework . address import ADDRESS_BCRT1_P2WSH_OP_TRUE
from test_framework . messages import (
CTxInWitness ,
2021-06-15 23:02:28 +02:00
tx_from_hex ,
2020-01-22 21:27:14 +01:00
)
2020-07-19 09:47:05 +02:00
from test_framework . p2p import P2PDataStore
2020-01-22 21:27:14 +01:00
from test_framework . script import (
CScript ,
OP_TRUE ,
)
2019-06-21 06:15:26 +02:00
from test_framework . test_node import ErrorMatch
from test_framework . test_framework import BitcoinTestFramework
from test_framework . util import (
assert_equal ,
p2p_port ,
)
2020-01-22 21:27:14 +01:00
2019-06-21 06:15:26 +02:00
class P2PPermissionsTests ( BitcoinTestFramework ) :
def set_test_params ( self ) :
self . num_nodes = 2
self . setup_clean_chain = True
def run_test ( self ) :
2020-01-22 21:27:14 +01:00
self . check_tx_relay ( )
2019-06-21 06:15:26 +02:00
self . checkpermission (
2019-08-16 15:56:56 +02:00
# default permissions (no specific permissions)
[ " -whitelist=127.0.0.1 " ] ,
2020-06-06 17:07:25 +02:00
# Make sure the default values in the command line documentation match the ones here
2020-12-23 01:54:18 +01:00
[ " relay " , " noban " , " mempool " , " download " ] )
2020-08-20 20:42:54 +02:00
2020-06-07 15:24:18 +02:00
self . checkpermission (
# no permission (even with forcerelay)
[ " -whitelist=@127.0.0.1 " , " -whitelistforcerelay=1 " ] ,
2020-12-23 01:54:18 +01:00
[ ] )
2020-06-07 15:24:18 +02:00
2019-08-16 10:45:13 +02:00
self . checkpermission (
2019-08-16 15:56:56 +02:00
# relay permission removed (no specific permissions)
[ " -whitelist=127.0.0.1 " , " -whitelistrelay=0 " ] ,
2020-12-23 01:54:18 +01:00
[ " noban " , " mempool " , " download " ] )
2019-08-16 10:45:13 +02:00
2019-06-21 06:15:26 +02:00
self . checkpermission (
2019-08-16 15:56:56 +02:00
# forcerelay and relay permission added
# Legacy parameter interaction which set whitelistrelay to true
# if whitelistforcerelay is true
[ " -whitelist=127.0.0.1 " , " -whitelistforcerelay " ] ,
2020-12-23 01:54:18 +01:00
[ " forcerelay " , " relay " , " noban " , " mempool " , " download " ] )
2019-06-21 06:15:26 +02:00
# Let's make sure permissions are merged correctly
# For this, we need to use whitebind instead of bind
# by modifying the configuration file.
ip_port = " 127.0.0.1: {} " . format ( p2p_port ( 1 ) )
self . replaceinconfig ( 1 , " bind=127.0.0.1 " , " whitebind=bloomfilter,forcerelay@ " + ip_port )
self . checkpermission (
2020-01-22 21:36:44 +01:00
[ " -whitelist=noban@127.0.0.1 " ] ,
2019-08-16 15:56:56 +02:00
# Check parameter interaction forcerelay should activate relay
2020-12-23 01:54:18 +01:00
[ " noban " , " bloomfilter " , " forcerelay " , " relay " , " download " ] )
2019-06-21 06:15:26 +02:00
self . replaceinconfig ( 1 , " whitebind=bloomfilter,forcerelay@ " + ip_port , " bind=127.0.0.1 " )
self . checkpermission (
2019-08-16 15:56:56 +02:00
# legacy whitelistrelay should be ignored
[ " -whitelist=noban,mempool@127.0.0.1 " , " -whitelistrelay " ] ,
2020-12-23 01:54:18 +01:00
[ " noban " , " mempool " , " download " ] )
2020-08-20 20:42:54 +02:00
2019-06-21 06:15:26 +02:00
self . checkpermission (
2019-08-16 15:56:56 +02:00
# legacy whitelistforcerelay should be ignored
[ " -whitelist=noban,mempool@127.0.0.1 " , " -whitelistforcerelay " ] ,
2020-12-23 01:54:18 +01:00
[ " noban " , " mempool " , " download " ] )
2019-06-21 06:15:26 +02:00
self . checkpermission (
2019-08-16 15:56:56 +02:00
# missing mempool permission to be considered legacy whitelisted
[ " -whitelist=noban@127.0.0.1 " ] ,
2020-12-23 01:54:18 +01:00
[ " noban " , " download " ] )
2019-06-21 06:15:26 +02:00
self . checkpermission (
2019-08-16 15:56:56 +02:00
# all permission added
[ " -whitelist=all@127.0.0.1 " ] ,
2020-12-23 01:54:18 +01:00
[ " forcerelay " , " noban " , " mempool " , " bloomfilter " , " relay " , " download " , " addr " ] )
2019-06-21 06:15:26 +02:00
self . stop_node ( 1 )
self . nodes [ 1 ] . assert_start_raises_init_error ( [ " -whitelist=oopsie@127.0.0.1 " ] , " Invalid P2P permission " , match = ErrorMatch . PARTIAL_REGEX )
self . nodes [ 1 ] . assert_start_raises_init_error ( [ " -whitelist=noban@127.0.0.1:230 " ] , " Invalid netmask specified in " , match = ErrorMatch . PARTIAL_REGEX )
self . nodes [ 1 ] . assert_start_raises_init_error ( [ " -whitebind=noban@127.0.0.1/10 " ] , " Cannot resolve -whitebind address " , match = ErrorMatch . PARTIAL_REGEX )
2022-06-22 20:22:25 +02:00
self . nodes [ 1 ] . assert_start_raises_init_error ( [ " -whitebind=noban@127.0.0.1 " , " -bind=127.0.0.1 " , " -listen=0 " ] , " Cannot set -bind or -whitebind together with -listen=0 " , match = ErrorMatch . PARTIAL_REGEX )
2019-06-21 06:15:26 +02:00
2020-01-22 21:27:14 +01:00
def check_tx_relay ( self ) :
2021-08-19 17:10:24 +02:00
block_op_true = self . nodes [ 0 ] . getblock ( self . generatetoaddress ( self . nodes [ 0 ] , 100 , ADDRESS_BCRT1_P2WSH_OP_TRUE ) [ 0 ] )
2020-01-22 21:27:14 +01:00
2020-07-09 17:59:54 +02:00
self . log . debug ( " Create a connection from a forcerelay peer that rebroadcasts raw txs " )
2020-08-17 11:10:44 +02:00
# A test framework p2p connection is needed to send the raw transaction directly. If a full node was used, it could only
2020-07-09 17:59:54 +02:00
# rebroadcast via the inv-getdata mechanism. However, even for forcerelay connections, a full node would
2020-01-22 21:27:14 +01:00
# currently not request a txid that is already in the mempool.
self . restart_node ( 1 , extra_args = [ " -whitelist=forcerelay@127.0.0.1 " ] )
p2p_rebroadcast_wallet = self . nodes [ 1 ] . add_p2p_connection ( P2PDataStore ( ) )
self . log . debug ( " Send a tx from the wallet initially " )
2021-06-15 23:02:28 +02:00
tx = tx_from_hex (
2020-01-22 21:27:14 +01:00
self . nodes [ 0 ] . createrawtransaction (
inputs = [ {
' txid ' : block_op_true [ ' tx ' ] [ 0 ] ,
' vout ' : 0 ,
} ] , outputs = [ {
ADDRESS_BCRT1_P2WSH_OP_TRUE : 5 ,
2022-07-13 22:29:27 +02:00
} ] ,
replaceable = False ) ,
2020-01-22 21:27:14 +01:00
)
tx . wit . vtxinwit = [ CTxInWitness ( ) ]
tx . wit . vtxinwit [ 0 ] . scriptWitness . stack = [ CScript ( [ OP_TRUE ] ) ]
txid = tx . rehash ( )
self . log . debug ( " Wait until tx is in node[1] ' s mempool " )
p2p_rebroadcast_wallet . send_txs_and_test ( [ tx ] , self . nodes [ 1 ] )
self . log . debug ( " Check that node[1] will send the tx to node[0] even though it is already in the mempool " )
2020-09-17 09:46:07 +02:00
self . connect_nodes ( 1 , 0 )
2020-07-09 17:59:54 +02:00
with self . nodes [ 1 ] . assert_debug_log ( [ " Force relaying tx {} from peer=0 " . format ( txid ) ] ) :
2020-01-22 21:27:14 +01:00
p2p_rebroadcast_wallet . send_txs_and_test ( [ tx ] , self . nodes [ 1 ] )
2020-08-17 17:50:47 +02:00
self . wait_until ( lambda : txid in self . nodes [ 0 ] . getrawmempool ( ) )
2020-01-22 21:27:14 +01:00
2020-01-22 22:02:24 +01:00
self . log . debug ( " Check that node[1] will not send an invalid tx to node[0] " )
tx . vout [ 0 ] . nValue + = 1
txid = tx . rehash ( )
2020-08-12 17:04:29 +02:00
# Send the transaction twice. The first time, it'll be rejected by ATMP because it conflicts
2021-03-31 19:44:18 +02:00
# with a mempool transaction. The second time, it'll be in the m_recent_rejects filter.
2020-01-22 22:02:24 +01:00
p2p_rebroadcast_wallet . send_txs_and_test (
[ tx ] ,
self . nodes [ 1 ] ,
success = False ,
2020-08-12 17:04:29 +02:00
reject_reason = ' {} from peer=0 was not accepted: txn-mempool-conflict ' . format ( txid )
)
p2p_rebroadcast_wallet . send_txs_and_test (
[ tx ] ,
self . nodes [ 1 ] ,
success = False ,
reject_reason = ' Not relaying non-mempool transaction {} from forcerelay peer=0 ' . format ( txid )
2020-01-22 22:02:24 +01:00
)
2020-12-23 01:54:18 +01:00
def checkpermission ( self , args , expectedPermissions ) :
2019-06-21 06:15:26 +02:00
self . restart_node ( 1 , args )
2020-09-17 09:46:07 +02:00
self . connect_nodes ( 0 , 1 )
2019-06-21 06:15:26 +02:00
peerinfo = self . nodes [ 1 ] . getpeerinfo ( ) [ 0 ]
assert_equal ( len ( expectedPermissions ) , len ( peerinfo [ ' permissions ' ] ) )
for p in expectedPermissions :
2020-12-23 01:54:18 +01:00
if p not in peerinfo [ ' permissions ' ] :
2019-06-21 06:15:26 +02:00
raise AssertionError ( " Expected permissions %r is not granted. " % p )
def replaceinconfig ( self , nodeid , old , new ) :
with open ( self . nodes [ nodeid ] . bitcoinconf , encoding = " utf8 " ) as f :
2020-01-22 21:36:44 +01:00
newText = f . read ( ) . replace ( old , new )
2019-06-21 06:15:26 +02:00
with open ( self . nodes [ nodeid ] . bitcoinconf , ' w ' , encoding = " utf8 " ) as f :
f . write ( newText )
2020-01-22 21:36:44 +01:00
2019-06-21 06:15:26 +02:00
if __name__ == ' __main__ ' :
P2PPermissionsTests ( ) . main ( )