diff --git a/.arclint b/.arclint --- a/.arclint +++ b/.arclint @@ -23,7 +23,7 @@ "exclude": [ "(^contrib/gitian-builder/)", "(^contrib/apple-sdk-tools/)", - "(^test/functional/abc-.*\\.py$)" + "(^test/functional/abc.*\\.py$)" ], "flags": [ "--aggressive", @@ -35,7 +35,7 @@ "type": "black", "version": ">=23.0.0", "include": [ - "(^test/functional/abc-.*\\.py$)" + "(^test/functional/abc.*\\.py$)" ], "flags": [ "--experimental-string-processing" diff --git a/test/functional/abc_feature_minerfund.py b/test/functional/abc_feature_minerfund.py --- a/test/functional/abc_feature_minerfund.py +++ b/test/functional/abc_feature_minerfund.py @@ -15,49 +15,52 @@ WELLINGTON_ACTIVATION_TIME = 2100000600 MINER_FUND_RATIO = 8 -MINER_FUND_ADDR = 'ecregtest:prfhcnyqnl5cgrnmlfmms675w93ld7mvvq9jcw0zsn' -MINER_FUND_ADDR_AXION = 'ecregtest:pqnqv9lt7e5vjyp0w88zf2af0l92l8rxdgz0wv9ltl' +MINER_FUND_ADDR = "ecregtest:prfhcnyqnl5cgrnmlfmms675w93ld7mvvq9jcw0zsn" +MINER_FUND_ADDR_AXION = "ecregtest:pqnqv9lt7e5vjyp0w88zf2af0l92l8rxdgz0wv9ltl" class MinerFundTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 - self.extra_args = [[ - '-enableminerfund', - f'-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}', - ], [ - f'-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}', - ]] + self.extra_args = [ + [ + "-enableminerfund", + f"-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}", + ], + [ + f"-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}", + ], + ] def run_test(self): node = self.nodes[0] - self.log.info('Create some history') + self.log.info("Create some history") self.generate(node, 10) def get_best_coinbase(n): - return n.getblock(n.getbestblockhash(), 2)['tx'][0] + return n.getblock(n.getbestblockhash(), 2)["tx"][0] coinbase = get_best_coinbase(node) - assert_greater_than_or_equal(len(coinbase['vout']), 2) - block_reward = sum([vout['value'] for vout in coinbase['vout']]) + assert_greater_than_or_equal(len(coinbase["vout"]), 2) + block_reward = sum([vout["value"] for vout in coinbase["vout"]]) def check_miner_fund_output(expected_address): coinbase = get_best_coinbase(node) - assert_equal(len(coinbase['vout']), 2) + assert_equal(len(coinbase["vout"]), 2) assert_equal( - coinbase['vout'][1]['scriptPubKey']['addresses'][0], - expected_address) + coinbase["vout"][1]["scriptPubKey"]["addresses"][0], expected_address + ) total = Decimal() - for o in coinbase['vout']: - total += o['value'] + for o in coinbase["vout"]: + total += o["value"] assert_equal(total, block_reward) assert_greater_than_or_equal( - coinbase['vout'][1]['value'], - (MINER_FUND_RATIO * total) / 100) + coinbase["vout"][1]["value"], (MINER_FUND_RATIO * total) / 100 + ) # The coinbase has an output to the miner fund address. # Now we send part of the coinbase to the fund. @@ -67,12 +70,11 @@ if coinbase is None: coinbase = create_coinbase(node.getblockcount() + 1) - block_time = node.getblock(prev_hash)['time'] + 1 - block = create_block(int(prev_hash, 16), - coinbase, block_time, version=4) + block_time = node.getblock(prev_hash)["time"] + 1 + block = create_block(int(prev_hash, 16), coinbase, block_time, version=4) block.solve() - assert_equal(node.submitblock(ToHex(block)), 'bad-cb-minerfund') + assert_equal(node.submitblock(ToHex(block)), "bad-cb-minerfund") # A block with no miner fund coinbase should be rejected. tip = node.getbestblockhash() @@ -81,8 +83,7 @@ def create_cb_pay_to_address(address): _, _, script_hash = decode(address) - miner_fund_amount = int( - block_reward * XEC * MINER_FUND_RATIO / 100) + miner_fund_amount = int(block_reward * XEC * MINER_FUND_RATIO / 100) # Build a coinbase with no miner fund cb = create_coinbase(node.getblockcount() + 1) @@ -91,8 +92,12 @@ # Change the block reward to account for the miner fund cb.vout[0].nValue = int(block_reward * XEC - miner_fund_amount) # Add the miner fund output - cb.vout.append(CTxOut(nValue=miner_fund_amount, scriptPubKey=CScript( - [OP_HASH160, script_hash, OP_EQUAL]))) + cb.vout.append( + CTxOut( + nValue=miner_fund_amount, + scriptPubKey=CScript([OP_HASH160, script_hash, OP_EQUAL]), + ) + ) pad_tx(cb) cb.calc_sha256() @@ -101,17 +106,16 @@ # Build a custom coinbase that spend to the legacy miner fund address # and check it is rejected. - check_bad_miner_fund( - tip, - create_cb_pay_to_address(MINER_FUND_ADDR_AXION)) + check_bad_miner_fund(tip, create_cb_pay_to_address(MINER_FUND_ADDR_AXION)) # Build a custom coinbase that spend to the new miner fund address # and check it is accepted. good_block = create_block( int(tip, 16), create_cb_pay_to_address(MINER_FUND_ADDR), - node.getblock(tip)['time'] + 1, - version=4) + node.getblock(tip)["time"] + 1, + version=4, + ) good_block.solve() node.submitblock(ToHex(good_block)) @@ -123,14 +127,13 @@ for n in self.nodes: n.setmocktime(WELLINGTON_ACTIVATION_TIME) self.generatetoaddress(node, nblocks=6, address=address) - assert_equal( - node.getblockchaininfo()['mediantime'], - WELLINGTON_ACTIVATION_TIME) + assert_equal(node.getblockchaininfo()["mediantime"], WELLINGTON_ACTIVATION_TIME) # First block that does not have miner fund as a consensus requirement. # node0 still mines a block with a coinbase output to the miner fund. first_block_has_miner_fund = self.generatetoaddress( - node, nblocks=1, address=address)[0] + node, nblocks=1, address=address + )[0] check_miner_fund_output(MINER_FUND_ADDR) # Invalidate it @@ -138,15 +141,13 @@ n.invalidateblock(first_block_has_miner_fund) # node1 mines a block without a coinbase output to the miner fund. - with node.assert_debug_log(expected_msgs=['policy-bad-miner-fund']): + with node.assert_debug_log(expected_msgs=["policy-bad-miner-fund"]): first_block_no_miner_fund = self.generatetoaddress( - self.nodes[1], - nblocks=1, - address=address, - sync_fun=self.no_op)[0] + self.nodes[1], nblocks=1, address=address, sync_fun=self.no_op + )[0] coinbase = get_best_coinbase(self.nodes[1]) - assert_equal(len(coinbase['vout']), 1) + assert_equal(len(coinbase["vout"]), 1) # node0 parks the block since the miner fund is enforced by policy. def parked_block(blockhash): @@ -155,6 +156,7 @@ assert tip["status"] != "active" return tip["status"] == "parked" return False + self.wait_until(lambda: parked_block(first_block_no_miner_fund)) # Unpark the block @@ -171,5 +173,5 @@ assert_equal(n.getbestblockhash(), first_block_no_miner_fund) -if __name__ == '__main__': +if __name__ == "__main__": MinerFundTest().main() diff --git a/test/functional/abc_feature_proof_cleanup.py b/test/functional/abc_feature_proof_cleanup.py --- a/test/functional/abc_feature_proof_cleanup.py +++ b/test/functional/abc_feature_proof_cleanup.py @@ -29,22 +29,28 @@ class ProofsCleanupTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.extra_args = [[ - '-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=1', - # Get rid of the getdata delay penalty for inbounds - '-whitelist=noban@127.0.0.1', - ]] * self.num_nodes + self.extra_args = [ + [ + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=1", + # Get rid of the getdata delay penalty for inbounds + "-whitelist=noban@127.0.0.1", + ] + ] * self.num_nodes def run_test(self): node = self.nodes[0] master_key, local_proof = gen_proof(self, node) - self.restart_node(0, self.extra_args[0] + [ - f"-avaproof={local_proof.serialize().hex()}", - f"-avamasterkey={bytes_to_wif(master_key.get_bytes())}", - ]) + self.restart_node( + 0, + self.extra_args[0] + + [ + f"-avaproof={local_proof.serialize().hex()}", + f"-avamasterkey={bytes_to_wif(master_key.get_bytes())}", + ], + ) # Add an inbound so the node proof can be registered and advertised node.add_p2p_connection(P2PInterface()) @@ -72,8 +78,7 @@ peer_info = node.getavalanchepeerinfo() assert_equal(len(peer_info), 11) - assert_equal(set(get_proof_ids(node)), - {proof.proofid for proof in proofs}) + assert_equal(set(get_proof_ids(node)), {proof.proofid for proof in proofs}) self.log.info("No proof is cleaned before the timeout expires") @@ -87,19 +92,27 @@ # Run the cleanup, the proofs with no node are cleaned excepted our # local proof - with node.assert_debug_log([f"Proof dropped for dangling too long (no connected node): {uint256_hex(p.proofid)}" for p in proofs[6:]]): + with node.assert_debug_log( + [ + "Proof dropped for dangling too long (no connected node):" + f" {uint256_hex(p.proofid)}" + for p in proofs[6:] + ] + ): # Expire the dangling proof timeout mocktime += 1 node.setmocktime(mocktime) node.mockscheduler(AVALANCHE_CLEANUP_INTERVAL) self.wait_until( - lambda: set(get_proof_ids(node)) == { - proof.proofid for proof in proofs[:6]}, - timeout=5) + lambda: set(get_proof_ids(node)) + == {proof.proofid for proof in proofs[:6]}, + timeout=5, + ) self.log.info( - "Check the proofs are cleaned on next cleanup after the nodes disconnected") + "Check the proofs are cleaned on next cleanup after the nodes disconnected" + ) for peer in peers: peer.peer_disconnect() @@ -114,8 +127,9 @@ for proof in proofs[1:]: with node.assert_debug_log(["dangling-proof"]): sender.send_avaproof(proof) - assert_raises_rpc_error(-8, "dangling-proof", - node.sendavalancheproof, proof.serialize().hex()) + assert_raises_rpc_error( + -8, "dangling-proof", node.sendavalancheproof, proof.serialize().hex() + ) assert_equal(get_proof_ids(node), [local_proof.proofid]) @@ -125,12 +139,14 @@ assert_equal(len(node.p2ps), 0) avanode = get_ava_p2p_interface(self, node) - avanode.wait_until(lambda: avanode.last_message.get( - "getdata") and avanode.last_message["getdata"].inv[-1].hash == avanode.proof.proofid) + avanode.wait_until( + lambda: avanode.last_message.get("getdata") + and avanode.last_message["getdata"].inv[-1].hash == avanode.proof.proofid + ) avanode.send_avaproof(avanode.proof) self.wait_until(lambda: avanode.proof.proofid in get_proof_ids(node)) -if __name__ == '__main__': +if __name__ == "__main__": ProofsCleanupTest().main() diff --git a/test/functional/abc_mempool_chainedtx.py b/test/functional/abc_mempool_chainedtx.py --- a/test/functional/abc_mempool_chainedtx.py +++ b/test/functional/abc_mempool_chainedtx.py @@ -17,16 +17,17 @@ class ChainedTxTest(BitcoinTestFramework): - def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True - self.extra_args = [[ - f"-replayprotectionactivationtime={WELLINGTON_ACTIVATION_TIME + 1000}", - f"-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}", - f"-limitancestorcount={MAX_CHAINED_TX}", - f"-limitdescendantcount={MAX_CHAINED_TX + 1}", - ]] + self.extra_args = [ + [ + f"-replayprotectionactivationtime={WELLINGTON_ACTIVATION_TIME + 1000}", + f"-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}", + f"-limitancestorcount={MAX_CHAINED_TX}", + f"-limitdescendantcount={MAX_CHAINED_TX + 1}", + ] + ] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -41,20 +42,27 @@ # The last 100 coinbase transactions are premature for b in self.generatetoaddress(node, 102, self.address)[:2]: coinbase = node.getblock(blockhash=b, verbosity=2)["tx"][0] - self.coins.append({ - "txid": coinbase["txid"], - "amount": coinbase["vout"][0]["value"], - "scriptPubKey": coinbase["vout"][0]["scriptPubKey"], - }) + self.coins.append( + { + "txid": coinbase["txid"], + "amount": coinbase["vout"][0]["value"], + "scriptPubKey": coinbase["vout"][0]["scriptPubKey"], + } + ) self.log.info("Before Wellington, the chained-tx limit applies") assert_greater_than( - WELLINGTON_ACTIVATION_TIME, - node.getblockchaininfo()['mediantime']) + WELLINGTON_ACTIVATION_TIME, node.getblockchaininfo()["mediantime"] + ) chain_hex, _ = create_raw_chain( - node, self.coins.pop(), self.address, self.privkeys, chain_length=MAX_CHAINED_TX + 1) + node, + self.coins.pop(), + self.address, + self.privkeys, + chain_length=MAX_CHAINED_TX + 1, + ) for i in range(MAX_CHAINED_TX): txid = node.sendrawtransaction(chain_hex[i]) @@ -64,23 +72,29 @@ assert_raises_rpc_error( -26, - f"too-long-mempool-chain, too many unconfirmed ancestors [limit: {MAX_CHAINED_TX}]", + ( + "too-long-mempool-chain, too many unconfirmed ancestors [limit:" + f" {MAX_CHAINED_TX}]" + ), node.sendrawtransaction, - chain_hex[-1]) + chain_hex[-1], + ) self.log.info("Activate Wellington") node.setmocktime(WELLINGTON_ACTIVATION_TIME) self.generate(node, 6) - assert_equal( - node.getblockchaininfo()['mediantime'], - WELLINGTON_ACTIVATION_TIME) + assert_equal(node.getblockchaininfo()["mediantime"], WELLINGTON_ACTIVATION_TIME) - self.log.info( - "After Wellington, the chained-tx limit no longer applies") + self.log.info("After Wellington, the chained-tx limit no longer applies") chain_hex, _ = create_raw_chain( - node, self.coins.pop(), self.address, self.privkeys, chain_length=MAX_CHAINED_TX * 2) + node, + self.coins.pop(), + self.address, + self.privkeys, + chain_length=MAX_CHAINED_TX * 2, + ) for i in range(MAX_CHAINED_TX * 2): txid = node.sendrawtransaction(chain_hex[i]) @@ -92,8 +106,8 @@ node.invalidateblock(node.getbestblockhash()) assert_greater_than( - WELLINGTON_ACTIVATION_TIME, - node.getblockchaininfo()['mediantime']) + WELLINGTON_ACTIVATION_TIME, node.getblockchaininfo()["mediantime"] + ) # Mempool size should be limited again assert_equal(len(node.getrawmempool()), MAX_CHAINED_TX * 2) @@ -106,10 +120,10 @@ # mempool node.invalidateblock(node.getbestblockhash()) assert_greater_than( - WELLINGTON_ACTIVATION_TIME, - node.getblockchaininfo()['mediantime']) + WELLINGTON_ACTIVATION_TIME, node.getblockchaininfo()["mediantime"] + ) assert_equal(len(node.getrawmempool()), MAX_CHAINED_TX * 2) -if __name__ == '__main__': +if __name__ == "__main__": ChainedTxTest().main() diff --git a/test/functional/abc_mining_basic.py b/test/functional/abc_mining_basic.py --- a/test/functional/abc_mining_basic.py +++ b/test/functional/abc_mining_basic.py @@ -15,8 +15,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_greater_than_or_equal -MINER_FUND_ADDR = 'ecregtest:prfhcnyqnl5cgrnmlfmms675w93ld7mvvq9jcw0zsn' -MINER_FUND_LEGACY_ADDR = '2NCXTUCFd1Q3EteVpVVDTrBBoKqvMPAoeEn' +MINER_FUND_ADDR = "ecregtest:prfhcnyqnl5cgrnmlfmms675w93ld7mvvq9jcw0zsn" +MINER_FUND_LEGACY_ADDR = "2NCXTUCFd1Q3EteVpVVDTrBBoKqvMPAoeEn" WELLINGTON_ACTIVATION_TIME = 2100000600 @@ -25,12 +25,13 @@ self.num_nodes = 2 self.extra_args = [ [ - '-enableminerfund', - f'-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}', - ], [ - '-enableminerfund', - '-usecashaddr=0', - f'-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}', + "-enableminerfund", + f"-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}", + ], + [ + "-enableminerfund", + "-usecashaddr=0", + f"-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}", ], ] @@ -48,35 +49,41 @@ # in 'expected' are not checked. def assert_getblocktemplate(expected): # Always test these values in addition to those passed in - expected = {**expected, **{ - 'sigchecklimit': DEFAULT_MAX_BLOCK_SIZE // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO, - }} + expected = { + **expected, + **{ + "sigchecklimit": DEFAULT_MAX_BLOCK_SIZE + // BLOCK_MAXBYTES_MAXSIGCHECKS_RATIO, + }, + } blockTemplate = node.getblocktemplate() for key, value in expected.items(): assert_equal(blockTemplate[key], value) def get_best_coinbase(): - return node.getblock(node.getbestblockhash(), 2)['tx'][0] + return node.getblock(node.getbestblockhash(), 2)["tx"][0] coinbase = get_best_coinbase() - assert_greater_than_or_equal(len(coinbase['vout']), 2) - block_reward = sum([vout['value'] for vout in coinbase['vout']]) - - assert_equal(node.getmempoolinfo()['size'], 0) - assert_getblocktemplate({ - 'coinbasetxn': { - 'minerfund': { - 'addresses': [minerFundAddress], - 'minimumvalue': block_reward * 8 // 100 * XEC, + assert_greater_than_or_equal(len(coinbase["vout"]), 2) + block_reward = sum([vout["value"] for vout in coinbase["vout"]]) + + assert_equal(node.getmempoolinfo()["size"], 0) + assert_getblocktemplate( + { + "coinbasetxn": { + "minerfund": { + "addresses": [minerFundAddress], + "minimumvalue": block_reward * 8 // 100 * XEC, + }, }, - }, - # Although the coinbase value need not necessarily be the same as - # the last block due to halvings and fees, we know this to be true - # since we are not crossing a halving boundary and there are no - # transactions in the mempool. - 'coinbasevalue': block_reward * XEC, - }) + # Although the coinbase value need not necessarily be the same as + # the last block due to halvings and fees, we know this to be true + # since we are not crossing a halving boundary and there are no + # transactions in the mempool. + "coinbasevalue": block_reward * XEC, + } + ) def run_test(self): self.run_for_node( @@ -117,5 +124,5 @@ ) -if __name__ == '__main__': +if __name__ == "__main__": AbcMiningRPCTest().main() diff --git a/test/functional/abc_p2p_avalanche_peer_discovery.py b/test/functional/abc_p2p_avalanche_peer_discovery.py --- a/test/functional/abc_p2p_avalanche_peer_discovery.py +++ b/test/functional/abc_p2p_avalanche_peer_discovery.py @@ -53,8 +53,12 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - self.extra_args = [['-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=3']] + self.extra_args = [ + [ + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=3", + ] + ] self.supports_cli = False def run_test(self): @@ -62,26 +66,34 @@ # duplicate the deterministic sig test from src/test/key_tests.cpp privkey = ECKey() - privkey.set(bytes.fromhex( - "12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747"), True) + privkey.set( + bytes.fromhex( + "12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747" + ), + True, + ) wif_privkey = bytes_to_wif(privkey.get_bytes()) self.log.info( - "Check the node is signalling the avalanche service bit only if there is a proof.") + "Check the node is signalling the avalanche service bit only if there is a" + " proof." + ) assert_equal( - int(node.getnetworkinfo()['localservices'], 16) & NODE_AVALANCHE, - 0) + int(node.getnetworkinfo()["localservices"], 16) & NODE_AVALANCHE, 0 + ) # Create stakes by mining blocks addrkey0 = node.get_deterministic_priv_key() blockhashes = self.generatetoaddress( - node, 4, addrkey0.address, sync_fun=self.no_op) + node, 4, addrkey0.address, sync_fun=self.no_op + ) stakes = create_coinbase_stakes(node, [blockhashes[0]], addrkey0.key) proof_sequence = 11 proof_expiration = 0 proof = node.buildavalancheproof( - proof_sequence, proof_expiration, wif_privkey, stakes) + proof_sequence, proof_expiration, wif_privkey, stakes + ) master_key = ECKey() master_key.generate() @@ -100,7 +112,8 @@ assert_equal(avahello.delegation.limited_proofid, 0) self.log.info( - "A delegation with all zero limited id indicates that the peer has no proof") + "A delegation with all zero limited id indicates that the peer has no proof" + ) no_proof_peer = GetProofDataCountingInterface() node.add_p2p_connection(no_proof_peer, wait_for_verack=True) @@ -113,13 +126,14 @@ assert_equal(len(node.getavalanchepeerinfo()), 0) self.log.info( - "A peer can send another hello containing a proof, only if the previous delegation was empty") + "A peer can send another hello containing a proof, only if the previous" + " delegation was empty" + ) # Send another hello, with a non-null delegation no_proof_peer.send_avahello(delegation, master_key) # Check the associated proof gets requested by the node - no_proof_peer.wait_until( - lambda: no_proof_peer.get_proof_data_count > 0) + no_proof_peer.wait_until(lambda: no_proof_peer.get_proof_data_count > 0) # Send the proof proofobj = avalanche_proof_from_hex(proof) @@ -135,18 +149,25 @@ # Subsequent avahello get ignored for _ in range(3): - with node.assert_debug_log([f"Ignoring avahello from peer {nodeid}: already in our node set"]): + with node.assert_debug_log( + [f"Ignoring avahello from peer {nodeid}: already in our node set"] + ): no_proof_peer.send_avahello(delegation, master_key) # Restart the node - self.restart_node(0, self.extra_args[0] + [ - f"-avaproof={proof}", - "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", - ]) + self.restart_node( + 0, + self.extra_args[0] + + [ + f"-avaproof={proof}", + "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", + ], + ) assert_equal( - int(node.getnetworkinfo()['localservices'], 16) & NODE_AVALANCHE, - NODE_AVALANCHE) + int(node.getnetworkinfo()["localservices"], 16) & NODE_AVALANCHE, + NODE_AVALANCHE, + ) def check_avahello(args): # Restart the node with the given args @@ -158,28 +179,30 @@ avakey = ECPubKey() avakey.set(bytes.fromhex(node.getavalanchekey())) - assert avakey.verify_schnorr( - avahello.sig, avahello.get_sighash(peer)) - - self.log.info( - "Test the avahello signature with a generated delegation") - check_avahello([ - f"-avaproof={proof}", - "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN" - ]) + assert avakey.verify_schnorr(avahello.sig, avahello.get_sighash(peer)) + + self.log.info("Test the avahello signature with a generated delegation") + check_avahello( + [ + f"-avaproof={proof}", + "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", + ] + ) self.log.info("Test the avahello signature with a supplied delegation") - check_avahello([ - f"-avaproof={proof}", - f"-avadelegation={delegation}", - f"-avamasterkey={bytes_to_wif(master_key.get_bytes())}", - ]) + check_avahello( + [ + f"-avaproof={proof}", + f"-avadelegation={delegation}", + f"-avamasterkey={bytes_to_wif(master_key.get_bytes())}", + ] + ) stakes = create_coinbase_stakes(node, [blockhashes[1]], addrkey0.key) interface_proof_hex = node.buildavalancheproof( - proof_sequence, proof_expiration, wif_privkey, stakes) - limited_id = avalanche_proof_from_hex( - interface_proof_hex).limited_proofid + proof_sequence, proof_expiration, wif_privkey, stakes + ) + limited_id = avalanche_proof_from_hex(interface_proof_hex).limited_proofid # delegate delegated_key = ECKey() @@ -188,39 +211,47 @@ uint256_hex(limited_id), bytes_to_wif(privkey.get_bytes()), delegated_key.get_pubkey().get_bytes().hex(), - None) + None, + ) self.log.info("Test that wrong avahello signature causes a ban") bad_interface = get_ava_p2p_interface_no_handshake(node) wrong_key = ECKey() wrong_key.generate() with node.assert_debug_log( - ["Misbehaving", - "peer=1 (0 -> 100) DISCOURAGE THRESHOLD EXCEEDED: " - "invalid-avahello-signature"]): + [ + "Misbehaving", + ( + "peer=1 (0 -> 100) DISCOURAGE THRESHOLD EXCEEDED: " + "invalid-avahello-signature" + ), + ] + ): bad_interface.send_avahello(interface_delegation_hex, wrong_key) bad_interface.wait_for_disconnect() self.log.info( - 'Check that receiving a valid avahello triggers a proof getdata request') + "Check that receiving a valid avahello triggers a proof getdata request" + ) good_interface = get_ava_p2p_interface_no_handshake(node) - proofid = good_interface.send_avahello( - interface_delegation_hex, delegated_key) + proofid = good_interface.send_avahello(interface_delegation_hex, delegated_key) def getdata_found(peer, proofid): with p2p_lock: - return good_interface.last_message.get( - "getdata") and good_interface.last_message["getdata"].inv[-1].hash == proofid + return ( + good_interface.last_message.get("getdata") + and good_interface.last_message["getdata"].inv[-1].hash == proofid + ) + self.wait_until(lambda: getdata_found(good_interface, proofid)) - self.log.info('Check that we can download the proof from our peer') + self.log.info("Check that we can download the proof from our peer") node_proofid = avalanche_proof_from_hex(proof).proofid getdata = msg_getdata([CInv(MSG_AVA_PROOF, node_proofid)]) - self.log.info( - "Proof has been inv'ed recently, check it can be requested") + self.log.info("Proof has been inv'ed recently, check it can be requested") good_interface.send_message(getdata) # This is our local proof so if it was announced it can be requested @@ -229,15 +260,22 @@ def proof_received(peer, proofid): with p2p_lock: - return peer.last_message.get( - "avaproof") and peer.last_message["avaproof"].proof.proofid == proofid + return ( + peer.last_message.get("avaproof") + and peer.last_message["avaproof"].proof.proofid == proofid + ) + self.wait_until(lambda: proof_received(good_interface, node_proofid)) # Restart the node - self.restart_node(0, self.extra_args[0] + [ - f"-avaproof={proof}", - "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", - ]) + self.restart_node( + 0, + self.extra_args[0] + + [ + f"-avaproof={proof}", + "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", + ], + ) def wait_for_proof_validation(): # Add an inbound so the node proof can be registered and advertised @@ -248,8 +286,7 @@ wait_for_proof_validation() - self.log.info( - "The proof has not been announced, it cannot be requested") + self.log.info("The proof has not been announced, it cannot be requested") peer = get_ava_p2p_interface_no_handshake(node, services=NODE_NETWORK) # Build a new proof and only announce this one @@ -265,7 +302,8 @@ # Request both our local proof and the new proof getdata = msg_getdata( - [CInv(MSG_AVA_PROOF, node_proofid), CInv(MSG_AVA_PROOF, new_proofid)]) + [CInv(MSG_AVA_PROOF, node_proofid), CInv(MSG_AVA_PROOF, new_proofid)] + ) peer.send_message(getdata) self.wait_until(lambda: proof_received(peer, new_proofid)) @@ -280,36 +318,44 @@ self.wait_until(lambda: proof_received(peer, node_proofid)) # Restart the node - self.restart_node(0, self.extra_args[0] + [ - f"-avaproof={proof}", - "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", - ]) + self.restart_node( + 0, + self.extra_args[0] + + [ + f"-avaproof={proof}", + "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", + ], + ) wait_for_proof_validation() # The only peer is the node itself assert_equal(len(node.getavalanchepeerinfo()), 1) assert_equal(node.getavalanchepeerinfo()[0]["proof"], proof) peer = get_ava_p2p_interface_no_handshake(node) - peer_proofid = peer.send_avahello( - interface_delegation_hex, delegated_key) + peer_proofid = peer.send_avahello(interface_delegation_hex, delegated_key) self.wait_until(lambda: getdata_found(peer, peer_proofid)) assert peer_proofid not in get_proof_ids(node) self.log.info( - "Check that the peer gets added as an avalanche node as soon as the node knows about the proof") + "Check that the peer gets added as an avalanche node as soon as the node" + " knows about the proof" + ) node.sendavalancheproof(interface_proof_hex) def has_node_count(count): peerinfo = node.getavalanchepeerinfo() - return (len(peerinfo) == 2 and - peerinfo[-1]["proof"] == interface_proof_hex and - peerinfo[-1]["nodecount"] == count) + return ( + len(peerinfo) == 2 + and peerinfo[-1]["proof"] == interface_proof_hex + and peerinfo[-1]["nodecount"] == count + ) self.wait_until(lambda: has_node_count(1)) self.log.info( - "Check that the peer gets added immediately if the proof is already known") + "Check that the peer gets added immediately if the proof is already known" + ) # Connect another peer using the same proof peer_proof_known = get_ava_p2p_interface_no_handshake(node) @@ -319,9 +365,8 @@ self.log.info("Check that repeated avahello messages are ignored") for i in range(3): - with node.assert_debug_log(['Ignoring avahello from peer']): - peer_proof_known.send_avahello( - interface_delegation_hex, delegated_key) + with node.assert_debug_log(["Ignoring avahello from peer"]): + peer_proof_known.send_avahello(interface_delegation_hex, delegated_key) self.log.info("Invalidate the proof and check the nodes are removed") tip = node.getbestblockhash() @@ -331,7 +376,8 @@ # to the one we just invalidated. Can be generate(1) after D9694 or # D9697 is landed. forked_tip = self.generatetoaddress( - node, 1, ADDRESS_ECREG_UNSPENDABLE, sync_fun=self.no_op)[0] + node, 1, ADDRESS_ECREG_UNSPENDABLE, sync_fun=self.no_op + )[0] self.wait_until(lambda: len(node.getavalanchepeerinfo()) == 1) assert peer_proofid not in get_proof_ids(node) @@ -342,20 +388,26 @@ self.wait_until(lambda: has_node_count(2), timeout=2) self.log.info( - "Check the node sends an avahello message to all peers even if the avalanche service bit is not advertised") + "Check the node sends an avahello message to all peers even if the" + " avalanche service bit is not advertised" + ) for _ in range(3): - nonavapeer = get_ava_p2p_interface_no_handshake( - node, services=NODE_NETWORK) + nonavapeer = get_ava_p2p_interface_no_handshake(node, services=NODE_NETWORK) nonavapeer.wait_for_avahello() self.log.info( - "Check the node waits for inbound connection to advertise its proof") + "Check the node waits for inbound connection to advertise its proof" + ) - self.restart_node(0, self.extra_args[0] + [ - f"-avaproof={proof}", - f"-avadelegation={delegation}", - f"-avamasterkey={bytes_to_wif(master_key.get_bytes())}", - ]) + self.restart_node( + 0, + self.extra_args[0] + + [ + f"-avaproof={proof}", + f"-avadelegation={delegation}", + f"-avamasterkey={bytes_to_wif(master_key.get_bytes())}", + ], + ) outbound = AvaP2PInterface() outbound.master_privkey, outbound.proof = gen_proof(self, node) @@ -385,9 +437,7 @@ # Check we got an avahello with the expected proof hello = outbound.wait_for_avahello().hello - assert_equal( - hello.delegation.limited_proofid, - proofobj.limited_proofid) + assert_equal(hello.delegation.limited_proofid, proofobj.limited_proofid) outbound.avahello = None # Check we don't get any avahello message anymore @@ -402,8 +452,7 @@ # Add another outbound peer other_outbound = AvaP2PInterface() - other_outbound.master_privkey, other_outbound.proof = gen_proof( - self, node) + other_outbound.master_privkey, other_outbound.proof = gen_proof(self, node) node.add_outbound_p2p_connection( other_outbound, p2p_idx=2, @@ -414,10 +463,8 @@ # Check we got an avahello with the expected proof, because the inbound # capability has been latched hello = other_outbound.wait_for_avahello().hello - assert_equal( - hello.delegation.limited_proofid, - proofobj.limited_proofid) + assert_equal(hello.delegation.limited_proofid, proofobj.limited_proofid) -if __name__ == '__main__': +if __name__ == "__main__": AvalanchePeerDiscoveryTest().main() diff --git a/test/functional/abc_p2p_avalanche_policy_minerfund.py b/test/functional/abc_p2p_avalanche_policy_minerfund.py --- a/test/functional/abc_p2p_avalanche_policy_minerfund.py +++ b/test/functional/abc_p2p_avalanche_policy_minerfund.py @@ -21,8 +21,8 @@ from test_framework.util import assert_equal MINER_FUND_RATIO = 8 -MINER_FUND_ADDR = 'ecregtest:prfhcnyqnl5cgrnmlfmms675w93ld7mvvq9jcw0zsn' -OTHER_MINER_FUND_ADDR = 'ecregtest:pqv2r67sgz3qumufap3h2uuj0zfmnzuv8v38gtrh5v' +MINER_FUND_ADDR = "ecregtest:prfhcnyqnl5cgrnmlfmms675w93ld7mvvq9jcw0zsn" +OTHER_MINER_FUND_ADDR = "ecregtest:pqv2r67sgz3qumufap3h2uuj0zfmnzuv8v38gtrh5v" QUORUM_NODE_COUNT = 16 WELLINGTON_ACTIVATION_TIME = 2100000600 @@ -33,14 +33,14 @@ self.num_nodes = 1 self.extra_args = [ [ - '-enableminerfund', - '-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=1', - '-avacooldown=0', - '-avaminquorumstake=0', - '-avaminavaproofsnodecount=0', - '-whitelist=noban@127.0.0.1', - f'-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}', + "-enableminerfund", + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=1", + "-avacooldown=0", + "-avaminquorumstake=0", + "-avaminavaproofsnodecount=0", + "-whitelist=noban@127.0.0.1", + f"-wellingtonactivationtime={WELLINGTON_ACTIVATION_TIME}", ], ] @@ -49,28 +49,26 @@ # Build a fake quorum of nodes. def get_quorum(): - return [get_ava_p2p_interface(self, node) - for _ in range(0, QUORUM_NODE_COUNT)] + return [ + get_ava_p2p_interface(self, node) for _ in range(0, QUORUM_NODE_COUNT) + ] # Pick one node from the quorum for polling. quorum = get_quorum() poll_node = quorum[0] - assert node.getavalancheinfo()['ready_to_poll'] is True + assert node.getavalancheinfo()["ready_to_poll"] is True # Activate Wellington address = node.get_deterministic_priv_key().address node.setmocktime(WELLINGTON_ACTIVATION_TIME) self.generatetoaddress(node, nblocks=6, address=address) - assert_equal( - node.getblockchaininfo()['mediantime'], - WELLINGTON_ACTIVATION_TIME) + assert_equal(node.getblockchaininfo()["mediantime"], WELLINGTON_ACTIVATION_TIME) # Get block reward - coinbase = node.getblock(node.getbestblockhash(), 2)['tx'][0] - block_reward = sum([vout['value'] for vout in coinbase['vout']]) - policy_miner_fund_amount = int( - block_reward * XEC * MINER_FUND_RATIO / 100) + coinbase = node.getblock(node.getbestblockhash(), 2)["tx"][0] + block_reward = sum([vout["value"] for vout in coinbase["vout"]]) + policy_miner_fund_amount = int(block_reward * XEC * MINER_FUND_RATIO / 100) def has_accepted_tip(tip_expected): hash_tip_final = int(tip_expected, 16) @@ -92,8 +90,12 @@ # Add the miner fund output if address and miner_fund_amount > 0: _, _, script_hash = decode(address) - cb.vout.append(CTxOut(nValue=miner_fund_amount, scriptPubKey=CScript( - [OP_HASH160, script_hash, OP_EQUAL]))) + cb.vout.append( + CTxOut( + nValue=miner_fund_amount, + scriptPubKey=CScript([OP_HASH160, script_hash, OP_EQUAL]), + ) + ) pad_tx(cb) cb.calc_sha256() @@ -112,19 +114,27 @@ def new_block(tip, miner_fund_addr, miner_fund_amount): # Create a new block paying to the specified miner fund cb = create_cb_pay_to_address(miner_fund_addr, miner_fund_amount) - block = create_block(int(tip, 16), cb, node.getblock(tip)[ - 'time'] + 1, version=4) + block = create_block( + int(tip, 16), cb, node.getblock(tip)["time"] + 1, version=4 + ) block.solve() node.submitblock(ToHex(block)) # Check the current tip is what we expect - matches_policy = miner_fund_addr == MINER_FUND_ADDR and miner_fund_amount >= policy_miner_fund_amount + matches_policy = ( + miner_fund_addr == MINER_FUND_ADDR + and miner_fund_amount >= policy_miner_fund_amount + ) expected_tip = block.hash if matches_policy else tip assert_equal(node.getbestblockhash(), expected_tip) # Poll and check the node votes what we expect poll_node.send_poll([block.sha256]) - expected_vote = AvalancheVoteError.ACCEPTED if matches_policy else AvalancheVoteError.PARKED + expected_vote = ( + AvalancheVoteError.ACCEPTED + if matches_policy + else AvalancheVoteError.PARKED + ) assert_response([AvalancheVote(expected_vote, block.sha256)]) # Vote yes on this block until the node accepts it @@ -132,8 +142,7 @@ assert_equal(node.getbestblockhash(), block.hash) poll_node.send_poll([block.sha256]) - assert_response( - [AvalancheVote(AvalancheVoteError.ACCEPTED, block.sha256)]) + assert_response([AvalancheVote(AvalancheVoteError.ACCEPTED, block.sha256)]) return block @@ -149,8 +158,7 @@ # Add some more random cases for _ in range(0, 10): - addr = MINER_FUND_ADDR if random.randrange( - 0, 2) else OTHER_MINER_FUND_ADDR + addr = MINER_FUND_ADDR if random.randrange(0, 2) else OTHER_MINER_FUND_ADDR amount = random.randrange(0, policy_miner_fund_amount * 2) cases.append((addr, amount)) @@ -159,20 +167,21 @@ random.shuffle(cases) for addr, amount in cases: self.log.info( - f"Miner fund test case: address: {addr}, fund amount: {amount}") + f"Miner fund test case: address: {addr}, fund amount: {amount}" + ) new_block(node.getbestblockhash(), addr, amount) # Check a rejection case tip = node.getbestblockhash() self.log.info("Miner fund rejection test case") - reject = new_block( - tip, - OTHER_MINER_FUND_ADDR, - policy_miner_fund_amount).hash + reject = new_block(tip, OTHER_MINER_FUND_ADDR, policy_miner_fund_amount).hash reject_hash = int(reject, 16) with node.wait_for_debug_log( [f"Avalanche invalidated block {reject}".encode()], - chatty_callable=lambda: can_find_inv_in_poll(quorum, reject_hash, AvalancheVoteError.PARKED)): + chatty_callable=lambda: can_find_inv_in_poll( + quorum, reject_hash, AvalancheVoteError.PARKED + ), + ): pass # Build a block on the accepted tip and the chain continues as normal @@ -183,13 +192,8 @@ self.wait_until(lambda: has_finalized_tip(tip)) # Check tip height for sanity - assert_equal( - node.getblockcount(), - QUORUM_NODE_COUNT + - 6 + - len(cases) + - 1) + assert_equal(node.getblockcount(), QUORUM_NODE_COUNT + 6 + len(cases) + 1) -if __name__ == '__main__': +if __name__ == "__main__": AvalancheMinerFundTest().main() diff --git a/test/functional/abc_p2p_avalanche_proof_voting.py b/test/functional/abc_p2p_avalanche_proof_voting.py --- a/test/functional/abc_p2p_avalanche_proof_voting.py +++ b/test/functional/abc_p2p_avalanche_proof_voting.py @@ -40,24 +40,30 @@ self.peer_replacement_cooldown = 2000 self.extra_args = [ [ - '-avaproofstakeutxodustthreshold=1000000', - f'-avaproofstakeutxoconfirmations={self.avaproof_stake_utxo_confirmations}', - f'-avalancheconflictingproofcooldown={self.conflicting_proof_cooldown}', - f'-avalanchepeerreplacementcooldown={self.peer_replacement_cooldown}', - '-avacooldown=0', - '-avastalevotethreshold=140', - '-avastalevotefactor=1', - '-avaminquorumstake=0', - '-avaminavaproofsnodecount=0', - '-whitelist=noban@127.0.0.1', + "-avaproofstakeutxodustthreshold=1000000", + f"-avaproofstakeutxoconfirmations={self.avaproof_stake_utxo_confirmations}", + f"-avalancheconflictingproofcooldown={self.conflicting_proof_cooldown}", + f"-avalanchepeerreplacementcooldown={self.peer_replacement_cooldown}", + "-avacooldown=0", + "-avastalevotethreshold=140", + "-avastalevotefactor=1", + "-avaminquorumstake=0", + "-avaminavaproofsnodecount=0", + "-whitelist=noban@127.0.0.1", ], ] self.supports_cli = False # Build a fake quorum of nodes. def get_quorum(self, node): - return [get_ava_p2p_interface(self, node, stake_utxo_confirmations=self.avaproof_stake_utxo_confirmations) - for _ in range(0, QUORUM_NODE_COUNT)] + return [ + get_ava_p2p_interface( + self, + node, + stake_utxo_confirmations=self.avaproof_stake_utxo_confirmations, + ) + for _ in range(0, QUORUM_NODE_COUNT) + ] @staticmethod def send_proof(from_peer, proof_hex): @@ -65,37 +71,46 @@ from_peer.send_avaproof(proof) return proof.proofid - def send_and_check_for_polling(self, peer, - proof_hex, response=AvalancheProofVoteResponse.ACTIVE): + def send_and_check_for_polling( + self, peer, proof_hex, response=AvalancheProofVoteResponse.ACTIVE + ): proofid = self.send_proof(peer, proof_hex) self.wait_until(lambda: can_find_inv_in_poll(self.quorum, proofid, response)) def build_conflicting_proof(self, node, sequence): return node.buildavalancheproof( - sequence, 0, self.privkey_wif, self.conflicting_stakes) + sequence, 0, self.privkey_wif, self.conflicting_stakes + ) def wait_for_invalidated_proof(self, node, proofid): def invalidate_proof(proofid): self.wait_until( - lambda: can_find_inv_in_poll(self.quorum, - proofid, response=AvalancheProofVoteResponse.REJECTED)) - return try_rpc(-8, "Proof not found", - node.getrawavalancheproof, uint256_hex(proofid)) + lambda: can_find_inv_in_poll( + self.quorum, proofid, response=AvalancheProofVoteResponse.REJECTED + ) + ) + return try_rpc( + -8, "Proof not found", node.getrawavalancheproof, uint256_hex(proofid) + ) with node.assert_debug_log( [f"Avalanche invalidated proof {uint256_hex(proofid)}"], - ["Failed to reject proof"] + ["Failed to reject proof"], ): self.wait_until(lambda: invalidate_proof(proofid)) def wait_for_finalized_proof(self, node, proofid): def finalize_proof(proofid): - can_find_inv_in_poll(self.quorum, - proofid, response=AvalancheProofVoteResponse.ACTIVE) - return node.getrawavalancheproof( - uint256_hex(proofid)).get("finalized", False) + can_find_inv_in_poll( + self.quorum, proofid, response=AvalancheProofVoteResponse.ACTIVE + ) + return node.getrawavalancheproof(uint256_hex(proofid)).get( + "finalized", False + ) - with node.assert_debug_log([f"Avalanche finalized proof {uint256_hex(proofid)}"]): + with node.assert_debug_log( + [f"Avalanche finalized proof {uint256_hex(proofid)}"] + ): self.wait_until(lambda: finalize_proof(proofid)) def run_test(self): @@ -109,9 +124,11 @@ addrkey0 = node.get_deterministic_priv_key() blockhash = self.generatetoaddress( - node, 9, addrkey0.address, sync_fun=self.no_op) + node, 9, addrkey0.address, sync_fun=self.no_op + ) self.conflicting_stakes = create_coinbase_stakes( - node, blockhash[5:9], addrkey0.key) + node, blockhash[5:9], addrkey0.key + ) self.poll_tests(node) self.update_tests(node) @@ -122,9 +139,8 @@ def poll_tests(self, node): # Disable the peer replacement cooldown for this test self.restart_node( - 0, - extra_args=self.extra_args[0] + - ['-avalanchepeerreplacementcooldown=0']) + 0, extra_args=self.extra_args[0] + ["-avalanchepeerreplacementcooldown=0"] + ) self.quorum = self.get_quorum(node) proof_seq10 = self.build_conflicting_proof(node, 10) @@ -132,9 +148,7 @@ proof_seq30 = self.build_conflicting_proof(node, 30) proof_seq40 = self.build_conflicting_proof(node, 40) - no_stake = node.buildavalancheproof( - 200, 2000000000, self.privkey_wif, [] - ) + no_stake = node.buildavalancheproof(200, 2000000000, self.privkey_wif, []) # Get the key so we can verify signatures. avakey = ECPubKey() @@ -154,28 +168,39 @@ self.wait_for_finalized_proof(node, proofid_seq30) self.log.info( - "Check we don't poll for subsequent proofs if the cooldown is not elapsed, proof not the favorite") - with node.assert_debug_log(["Not polling the avalanche proof (cooldown-not-elapsed)"]): + "Check we don't poll for subsequent proofs if the cooldown is not elapsed," + " proof not the favorite" + ) + with node.assert_debug_log( + ["Not polling the avalanche proof (cooldown-not-elapsed)"] + ): peer.send_avaproof(avalanche_proof_from_hex(proof_seq20)) self.log.info( - "Check we don't poll for subsequent proofs if the cooldown is not elapsed, proof is the favorite") - with node.assert_debug_log(["Not polling the avalanche proof (cooldown-not-elapsed)"]): + "Check we don't poll for subsequent proofs if the cooldown is not elapsed," + " proof is the favorite" + ) + with node.assert_debug_log( + ["Not polling the avalanche proof (cooldown-not-elapsed)"] + ): peer.send_avaproof(avalanche_proof_from_hex(proof_seq40)) self.log.info( - "Check we poll for conflicting proof if the proof is not the favorite") + "Check we poll for conflicting proof if the proof is not the favorite" + ) mock_time += self.conflicting_proof_cooldown node.setmocktime(mock_time) self.send_and_check_for_polling( - peer, proof_seq20, response=AvalancheProofVoteResponse.REJECTED) + peer, proof_seq20, response=AvalancheProofVoteResponse.REJECTED + ) # Continue to vote until the proof is invalidated proofid_seq20 = avalanche_proof_from_hex(proof_seq20).proofid self.wait_for_invalidated_proof(node, proofid_seq20) self.log.info( - "Check we poll for conflicting proof if the proof is the favorite") + "Check we poll for conflicting proof if the proof is the favorite" + ) mock_time += self.conflicting_proof_cooldown node.setmocktime(mock_time) self.send_and_check_for_polling(peer, proof_seq40) @@ -184,7 +209,9 @@ node.setmocktime(mock_time) self.log.info("Check we don't poll for proofs that get rejected") - with node.assert_debug_log(["Not polling the avalanche proof (rejected-proof)"]): + with node.assert_debug_log( + ["Not polling the avalanche proof (rejected-proof)"] + ): peer.send_avaproof(avalanche_proof_from_hex(proof_seq10)) self.log.info("Check we don't poll for invalid proofs and get banned") @@ -217,8 +244,11 @@ self.log.info("Test proof acceptance") def accept_proof(proofid): - self.wait_until(lambda: can_find_inv_in_poll(self.quorum, - proofid, response=AvalancheProofVoteResponse.ACTIVE)) + self.wait_until( + lambda: can_find_inv_in_poll( + self.quorum, proofid, response=AvalancheProofVoteResponse.ACTIVE + ) + ) return proofid in get_proof_ids(node) mock_time += self.conflicting_proof_cooldown @@ -238,7 +268,9 @@ mock_time += self.conflicting_proof_cooldown node.setmocktime(mock_time) - with node.assert_debug_log(["Not polling the avalanche proof (cooldown-not-elapsed)"]): + with node.assert_debug_log( + ["Not polling the avalanche proof (cooldown-not-elapsed)"] + ): self.send_proof(peer, proof_seq50) mock_time += self.peer_replacement_cooldown @@ -252,13 +284,15 @@ def reject_proof(proofid): self.wait_until( - lambda: can_find_inv_in_poll(self.quorum, - proofid, response=AvalancheProofVoteResponse.REJECTED)) + lambda: can_find_inv_in_poll( + self.quorum, proofid, response=AvalancheProofVoteResponse.REJECTED + ) + ) return proofid not in get_proof_ids(node) with node.assert_debug_log( [f"Avalanche rejected proof {uint256_hex(proofid_seq50)}"], - ["Failed to reject proof"] + ["Failed to reject proof"], ): self.wait_until(lambda: reject_proof(proofid_seq50)) @@ -273,39 +307,47 @@ for i in range(5): with node.assert_debug_log(["received: avaproof"]): self.send_proof(peer, proof_seq50) - assert_raises_rpc_error(-8, - "Proof not found", - node.getrawavalancheproof, - uint256_hex(proofid_seq50)) + assert_raises_rpc_error( + -8, + "Proof not found", + node.getrawavalancheproof, + uint256_hex(proofid_seq50), + ) node.setmocktime(0) def vote_tests(self, node): self.avaproof_stake_utxo_confirmations = 2 - self.restart_node(0, extra_args=['-avaproofstakeutxodustthreshold=1000000', - f'-avaproofstakeutxoconfirmations={self.avaproof_stake_utxo_confirmations}', - '-avacooldown=0', - '-avalancheconflictingproofcooldown=0', - '-avaminquorumstake=0', - '-avaminavaproofsnodecount=0', - '-whitelist=noban@127.0.0.1', ]) + self.restart_node( + 0, + extra_args=[ + "-avaproofstakeutxodustthreshold=1000000", + f"-avaproofstakeutxoconfirmations={self.avaproof_stake_utxo_confirmations}", + "-avacooldown=0", + "-avalancheconflictingproofcooldown=0", + "-avaminquorumstake=0", + "-avaminavaproofsnodecount=0", + "-whitelist=noban@127.0.0.1", + ], + ) self.get_quorum(node) ava_node = get_ava_p2p_interface( - self, node, stake_utxo_confirmations=self.avaproof_stake_utxo_confirmations) + self, node, stake_utxo_confirmations=self.avaproof_stake_utxo_confirmations + ) # Generate coinbases to use for stakes stakes_key = node.get_deterministic_priv_key() blocks = self.generatetoaddress( - node, 4, stakes_key.address, sync_fun=self.no_op) + node, 4, stakes_key.address, sync_fun=self.no_op + ) # Get the ava key so we can verify signatures. ava_key = ECPubKey() ava_key.set(bytes.fromhex(node.getavalanchekey())) def create_proof(stakes, sequence=10): - proof = node.buildavalancheproof( - sequence, 0, self.privkey_wif, stakes) + proof = node.buildavalancheproof(sequence, 0, self.privkey_wif, stakes) proof_id = avalanche_proof_from_hex(proof).proofid return proof, proof_id @@ -322,13 +364,12 @@ proof_2, proof_2_id = create_proof(stakes_2) # proof_3 conflicts with proof_0 and proof_1, but has a lower sequence - stakes_3 = create_coinbase_stakes( - node, [blocks[0], blocks[1]], stakes_key.key) + stakes_3 = create_coinbase_stakes(node, [blocks[0], blocks[1]], stakes_key.key) proof_3, proof_3_id = create_proof(stakes_3, sequence=1) # proof_4 is invalid and should be rejected stakes_4 = create_coinbase_stakes(node, [blocks[2]], stakes_key.key) - stakes_4[0]['amount'] -= 100000 + stakes_4[0]["amount"] -= 100000 proof_4, proof_4_id = create_proof(stakes_4) # Create a helper to issue a poll and validate the responses @@ -337,7 +378,8 @@ self.log.info("Trigger polling from the node...") ava_node.send_poll( [proof_0_id, proof_1_id, proof_2_id, proof_3_id, proof_4_id], - MSG_AVA_PROOF) + MSG_AVA_PROOF, + ) response = ava_node.wait_for_avaresponse() r = response.response @@ -351,60 +393,79 @@ assert_equal(repr(votes[i]), repr(expected[i])) # Check that all proofs start unknown - poll_assert_response([ - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_0_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_1_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_2_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_3_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_4_id)]) + poll_assert_response( + [ + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_0_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_1_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_2_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_3_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_4_id), + ] + ) # Send the first proof. Nodes should now respond that it's accepted node.sendavalancheproof(proof_0) - poll_assert_response([ - AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_1_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_2_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_3_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_4_id)]) + poll_assert_response( + [ + AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_1_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_2_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_3_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_4_id), + ] + ) # Send and check the 2nd proof. Nodes should now respond that it's # accepted node.sendavalancheproof(proof_1) - poll_assert_response([ - AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), - AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_1_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_2_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_3_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_4_id)]) + poll_assert_response( + [ + AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), + AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_1_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_2_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_3_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_4_id), + ] + ) # The next proof should be rejected/put in the immature pool ava_node.send_proof(avalanche_proof_from_hex(proof_2)) - poll_assert_response([ - AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), - AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_1_id), - AvalancheVote(AvalancheProofVoteResponse.IMMATURE, proof_2_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_3_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_4_id)]) + poll_assert_response( + [ + AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), + AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_1_id), + AvalancheVote(AvalancheProofVoteResponse.IMMATURE, proof_2_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_3_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_4_id), + ] + ) # The next proof should be rejected and marked as a conflicting proof - assert_raises_rpc_error(-8, "conflicting-utxos", - node.sendavalancheproof, proof_3) - poll_assert_response([ - AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), - AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_1_id), - AvalancheVote(AvalancheProofVoteResponse.IMMATURE, proof_2_id), - AvalancheVote(AvalancheProofVoteResponse.CONFLICT, proof_3_id), - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_4_id)]) + assert_raises_rpc_error( + -8, "conflicting-utxos", node.sendavalancheproof, proof_3 + ) + poll_assert_response( + [ + AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), + AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_1_id), + AvalancheVote(AvalancheProofVoteResponse.IMMATURE, proof_2_id), + AvalancheVote(AvalancheProofVoteResponse.CONFLICT, proof_3_id), + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proof_4_id), + ] + ) # The final proof should be permanently rejected for being completely # invalid ava_node.send_proof(avalanche_proof_from_hex(proof_4)) - poll_assert_response([ - AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), - AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_1_id), - AvalancheVote(AvalancheProofVoteResponse.IMMATURE, proof_2_id), - AvalancheVote(AvalancheProofVoteResponse.CONFLICT, proof_3_id), - AvalancheVote(AvalancheProofVoteResponse.REJECTED, proof_4_id)]) + poll_assert_response( + [ + AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), + AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_1_id), + AvalancheVote(AvalancheProofVoteResponse.IMMATURE, proof_2_id), + AvalancheVote(AvalancheProofVoteResponse.CONFLICT, proof_3_id), + AvalancheVote(AvalancheProofVoteResponse.REJECTED, proof_4_id), + ] + ) def stale_proof_tests(self, node): # Restart the node to get rid of in-flight requests @@ -431,15 +492,20 @@ node.setmocktime(mock_time) self.send_and_check_for_polling( - peer, proof_seq1, response=AvalancheProofVoteResponse.UNKNOWN) + peer, proof_seq1, response=AvalancheProofVoteResponse.UNKNOWN + ) def vote_until_dropped(proofid): - can_find_inv_in_poll(self.quorum, - proofid, response=AvalancheProofVoteResponse.UNKNOWN) - return try_rpc(-8, "Proof not found", - node.getrawavalancheproof, uint256_hex(proofid)) + can_find_inv_in_poll( + self.quorum, proofid, response=AvalancheProofVoteResponse.UNKNOWN + ) + return try_rpc( + -8, "Proof not found", node.getrawavalancheproof, uint256_hex(proofid) + ) - with node.assert_debug_log([f"Avalanche stalled proof {uint256_hex(proofid_seq1)}"]): + with node.assert_debug_log( + [f"Avalanche stalled proof {uint256_hex(proofid_seq1)}"] + ): self.wait_until(lambda: vote_until_dropped(proofid_seq1)) # Verify that proof_seq2 was not replaced @@ -449,34 +515,43 @@ # When polled, peer responds with expected votes for both proofs peer.send_poll([proofid_seq1, proofid_seq2], MSG_AVA_PROOF) response = peer.wait_for_avaresponse() - assert repr(response.response.votes) == repr([ - AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proofid_seq1), - AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proofid_seq2)]) + assert repr(response.response.votes) == repr( + [ + AvalancheVote(AvalancheProofVoteResponse.UNKNOWN, proofid_seq1), + AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proofid_seq2), + ] + ) node.setmocktime(0) def maturity_poll_tests(self, node): # Restart the node with appropriate flags for this test self.avaproof_stake_utxo_confirmations = 2 - self.restart_node(0, extra_args=[ - '-avaproofstakeutxodustthreshold=1000000', - f'-avaproofstakeutxoconfirmations={self.avaproof_stake_utxo_confirmations}', - '-avalancheconflictingproofcooldown=0', - '-avacooldown=0', - '-avaminquorumstake=0', - '-avaminavaproofsnodecount=0', - '-whitelist=noban@127.0.0.1', - ]) + self.restart_node( + 0, + extra_args=[ + "-avaproofstakeutxodustthreshold=1000000", + f"-avaproofstakeutxoconfirmations={self.avaproof_stake_utxo_confirmations}", + "-avalancheconflictingproofcooldown=0", + "-avacooldown=0", + "-avaminquorumstake=0", + "-avaminavaproofsnodecount=0", + "-whitelist=noban@127.0.0.1", + ], + ) self.quorum = self.get_quorum(node) peer = get_ava_p2p_interface( - self, node, stake_utxo_confirmations=self.avaproof_stake_utxo_confirmations) + self, node, stake_utxo_confirmations=self.avaproof_stake_utxo_confirmations + ) _, immature_proof = gen_proof(self, node) self.log.info("Immature proofs are not polled") - with node.assert_debug_log(["Not polling the avalanche proof (immature-proof)"]): + with node.assert_debug_log( + ["Not polling the avalanche proof (immature-proof)"] + ): peer.send_avaproof(immature_proof) self.log.info("Newly mature proofs are polled") @@ -485,5 +560,5 @@ self.send_and_check_for_polling(peer, immature_proof.serialize().hex()) -if __name__ == '__main__': +if __name__ == "__main__": AvalancheProofVotingTest().main() diff --git a/test/functional/abc_p2p_avalanche_quorum.py b/test/functional/abc_p2p_avalanche_quorum.py --- a/test/functional/abc_p2p_avalanche_quorum.py +++ b/test/functional/abc_p2p_avalanche_quorum.py @@ -29,21 +29,24 @@ self.setup_clean_chain = True self.num_nodes = 3 self.min_avaproofs_node_count = 8 - self.extra_args = [[ - '-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=1', - '-avacooldown=0', - '-avatimeout=0', - '-avaminquorumstake=150000000', - '-avaminquorumconnectedstakeratio=0.8', - '-minimumchainwork=0', - ]] * self.num_nodes - self.extra_args[0] = self.extra_args[0] + \ - ['-avaminavaproofsnodecount=0'] - self.extra_args[1] = self.extra_args[1] + \ - [f'-avaminavaproofsnodecount={self.min_avaproofs_node_count}'] - self.extra_args[2] = self.extra_args[2] + \ - [f'-avaminavaproofsnodecount={self.min_avaproofs_node_count}'] + self.extra_args = [ + [ + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=1", + "-avacooldown=0", + "-avatimeout=0", + "-avaminquorumstake=150000000", + "-avaminquorumconnectedstakeratio=0.8", + "-minimumchainwork=0", + ] + ] * self.num_nodes + self.extra_args[0] = self.extra_args[0] + ["-avaminavaproofsnodecount=0"] + self.extra_args[1] = self.extra_args[1] + [ + f"-avaminavaproofsnodecount={self.min_avaproofs_node_count}" + ] + self.extra_args[2] = self.extra_args[2] + [ + f"-avaminavaproofsnodecount={self.min_avaproofs_node_count}" + ] def run_test(self): # Initially all nodes start with 8 nodes attached to a single proof @@ -63,7 +66,7 @@ peers = [] for i in range(0, self.min_avaproofs_node_count + 1): key, proof = gen_proof(self, self.nodes[0]) - peers.append({'key': key, 'proof': proof}) + peers.append({"key": key, "proof": proof}) # Let the nodes known about all the blocks then disconnect them so we're # sure they won't exchange proofs when we start connecting peers. @@ -72,16 +75,14 @@ # Restart node 2 to apply the minimum chainwork and make sure it's still # in IBD state. - chainwork = int(self.nodes[2].getblockchaininfo()['chainwork'], 16) + chainwork = int(self.nodes[2].getblockchaininfo()["chainwork"], 16) self.restart_node( - 2, - extra_args=self.extra_args[2] + - [f'-minimumchainwork={chainwork + 2:#x}']) - assert self.nodes[2].getblockchaininfo()['initialblockdownload'] + 2, extra_args=self.extra_args[2] + [f"-minimumchainwork={chainwork + 2:#x}"] + ) + assert self.nodes[2].getblockchaininfo()["initialblockdownload"] # Build polling nodes - pollers = [get_ava_p2p_interface_no_handshake( - node) for node in self.nodes] + pollers = [get_ava_p2p_interface_no_handshake(node) for node in self.nodes] def poll_and_assert_response(node, expected): pubkey = ECPubKey() @@ -109,8 +110,8 @@ nonlocal p2p_idx avapeer = AvaP2PInterface() - avapeer.proof = peer['proof'] - avapeer.master_privkey = peer['key'] + avapeer.proof = peer["proof"] + avapeer.master_privkey = peer["key"] node.add_outbound_p2p_connection( avapeer, p2p_idx=p2p_idx, @@ -118,90 +119,97 @@ services=NODE_NETWORK | NODE_AVALANCHE, ) p2p_idx += 1 - avapeer.nodeid = node.getpeerinfo()[-1]['id'] + avapeer.nodeid = node.getpeerinfo()[-1]["id"] - peer['node'] = avapeer + peer["node"] = avapeer # There is no compact proof request if the node is in IBD state - if not node.getblockchaininfo()['initialblockdownload']: - avapeer.wait_until( - lambda: avapeer.last_message.get("getavaproofs")) + if not node.getblockchaininfo()["initialblockdownload"]: + avapeer.wait_until(lambda: avapeer.last_message.get("getavaproofs")) if empty_avaproof: avapeer.send_message(build_msg_avaproofs([])) avapeer.sync_send_with_ping() with p2p_lock: - assert_equal( - avapeer.message_count.get( - "avaproofsreq", 0), 0) + assert_equal(avapeer.message_count.get("avaproofsreq", 0), 0) else: - avapeer.send_and_ping(build_msg_avaproofs([peer['proof']])) - avapeer.wait_until( - lambda: avapeer.last_message.get("avaproofsreq")) + avapeer.send_and_ping(build_msg_avaproofs([peer["proof"]])) + avapeer.wait_until(lambda: avapeer.last_message.get("avaproofsreq")) return avapeer - def add_avapeer_and_check_status( - peer, expected_status, empty_avaproof=False): + def add_avapeer_and_check_status(peer, expected_status, empty_avaproof=False): for i, node in enumerate(self.nodes): get_ava_outbound(node, peer, empty_avaproof) poll_and_assert_response(node, expected_status[i]) # Start polling. The response should be UNKNOWN because there's not # enough stake - [poll_and_assert_response(node, AvalancheVoteError.UNKNOWN) - for node in self.nodes] + [ + poll_and_assert_response(node, AvalancheVoteError.UNKNOWN) + for node in self.nodes + ] # Create one peer with half the remaining missing stake and add one # node add_avapeer_and_check_status( - peers[0], [ + peers[0], + [ AvalancheVoteError.UNKNOWN, AvalancheVoteError.UNKNOWN, AvalancheVoteError.UNKNOWN, - ]) + ], + ) # Create a second peer with the other half and add one node. # This is enough for node0 but not node1 add_avapeer_and_check_status( - peers[1], [ + peers[1], + [ AvalancheVoteError.ACCEPTED, AvalancheVoteError.UNKNOWN, AvalancheVoteError.UNKNOWN, - ]) + ], + ) # Add more peers for triggering the avaproofs messaging for i in range(2, self.min_avaproofs_node_count - 1): add_avapeer_and_check_status( - peers[i], [ + peers[i], + [ AvalancheVoteError.ACCEPTED, AvalancheVoteError.UNKNOWN, AvalancheVoteError.UNKNOWN, - ]) + ], + ) add_avapeer_and_check_status( - peers[self.min_avaproofs_node_count - 1], [ + peers[self.min_avaproofs_node_count - 1], + [ AvalancheVoteError.ACCEPTED, AvalancheVoteError.ACCEPTED, AvalancheVoteError.UNKNOWN, - ]) + ], + ) # The proofs are not requested during IBD, so node 2 has no proof yet. assert_equal(len(get_proof_ids(self.nodes[2])), 0) # And all the nodes are pending assert_equal( - self.nodes[2].getavalancheinfo()['network']['pending_node_count'], - self.min_avaproofs_node_count) + self.nodes[2].getavalancheinfo()["network"]["pending_node_count"], + self.min_avaproofs_node_count, + ) self.generate(self.nodes[2], 1, sync_fun=self.no_op) - assert not self.nodes[2].getblockchaininfo()['initialblockdownload'] + assert not self.nodes[2].getblockchaininfo()["initialblockdownload"] # Connect the pending nodes so the next compact proofs requests can get # accounted for for i in range(self.min_avaproofs_node_count): - node.sendavalancheproof(peers[i]['proof'].serialize().hex()) - assert_equal(self.nodes[2].getavalancheinfo()[ - 'network']['pending_node_count'], 0) + node.sendavalancheproof(peers[i]["proof"].serialize().hex()) + assert_equal( + self.nodes[2].getavalancheinfo()["network"]["pending_node_count"], 0 + ) # The avaproofs message are not accounted during IBD, so this is not # enough. @@ -211,27 +219,34 @@ # of IBD. for i in range(self.min_avaproofs_node_count - 1): add_avapeer_and_check_status( - peers[i], [ + peers[i], + [ AvalancheVoteError.ACCEPTED, AvalancheVoteError.ACCEPTED, AvalancheVoteError.UNKNOWN, - ]) + ], + ) # The messages is not accounted when there is no shortid add_avapeer_and_check_status( - peers[self.min_avaproofs_node_count - 1], [ + peers[self.min_avaproofs_node_count - 1], + [ AvalancheVoteError.ACCEPTED, AvalancheVoteError.ACCEPTED, AvalancheVoteError.UNKNOWN, - ], empty_avaproof=True) + ], + empty_avaproof=True, + ) # The messages are accounted and the node quorum finally valid add_avapeer_and_check_status( - peers[self.min_avaproofs_node_count], [ + peers[self.min_avaproofs_node_count], + [ AvalancheVoteError.ACCEPTED, AvalancheVoteError.ACCEPTED, AvalancheVoteError.ACCEPTED, - ]) + ], + ) # Unless there is not enough nodes to poll for node in self.nodes: @@ -248,5 +263,5 @@ poll_and_assert_response(node, AvalancheVoteError.ACCEPTED) -if __name__ == '__main__': +if __name__ == "__main__": AvalancheQuorumTest().main() diff --git a/test/functional/abc_p2p_avalanche_transaction_voting.py b/test/functional/abc_p2p_avalanche_transaction_voting.py --- a/test/functional/abc_p2p_avalanche_transaction_voting.py +++ b/test/functional/abc_p2p_avalanche_transaction_voting.py @@ -28,16 +28,18 @@ class AvalancheTransactionVotingTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.extra_args = [[ - '-avalanchepreconsensus=1', - '-avacooldown=0', - '-avaproofstakeutxoconfirmations=1', - # Low enough for coinbase transactions to be staked in valid proofs - '-avaproofstakeutxodustthreshold=1000000', - '-avaminquorumstake=0', - '-avaminavaproofsnodecount=0', - '-whitelist=noban@127.0.0.1', - ]] + self.extra_args = [ + [ + "-avalanchepreconsensus=1", + "-avacooldown=0", + "-avaproofstakeutxoconfirmations=1", + # Low enough for coinbase transactions to be staked in valid proofs + "-avaproofstakeutxodustthreshold=1000000", + "-avaminquorumstake=0", + "-avaminavaproofsnodecount=0", + "-whitelist=noban@127.0.0.1", + ] + ] def run_test(self): node = self.nodes[0] @@ -68,43 +70,50 @@ # Mature the coinbases self.generate(node, 100, sync_fun=self.no_op) - assert_equal(node.getmempoolinfo()['size'], 0) - tx_ids = [int(wallet.send_self_transfer(from_node=node) - ['txid'], 16) for _ in range(num_txs)] - assert_equal(node.getmempoolinfo()['size'], num_txs) + assert_equal(node.getmempoolinfo()["size"], 0) + tx_ids = [ + int(wallet.send_self_transfer(from_node=node)["txid"], 16) + for _ in range(num_txs) + ] + assert_equal(node.getmempoolinfo()["size"], num_txs) - self.log.info( - "Check the votes are unknown while the quorum is not established") + self.log.info("Check the votes are unknown while the quorum is not established") poll_node.send_poll(tx_ids, MSG_TX) assert_response( - [AvalancheVote(AvalancheTxVoteError.UNKNOWN, txid) for txid in tx_ids]) + [AvalancheVote(AvalancheTxVoteError.UNKNOWN, txid) for txid in tx_ids] + ) self.log.info("Check the votes on valid mempool transactions") def get_quorum(): - return [get_ava_p2p_interface(self, node) - for _ in range(0, QUORUM_NODE_COUNT)] + return [ + get_ava_p2p_interface(self, node) for _ in range(0, QUORUM_NODE_COUNT) + ] + _ = get_quorum() poll_node.send_poll(tx_ids, MSG_TX) assert_response( - [AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids]) + [AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids] + ) self.log.info("Check the votes on recently mined transactions") self.generate(node, 1, sync_fun=self.no_op) - assert_equal(node.getmempoolinfo()['size'], 0) + assert_equal(node.getmempoolinfo()["size"], 0) poll_node.send_poll(tx_ids, MSG_TX) assert_response( - [AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids]) + [AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids] + ) for _ in range(10): self.generate(node, 1, sync_fun=self.no_op) poll_node.send_poll(tx_ids, MSG_TX) assert_response( - [AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids]) + [AvalancheVote(AvalancheTxVoteError.ACCEPTED, txid) for txid in tx_ids] + ) self.log.info("Check the votes on unknown transactions") @@ -112,7 +121,8 @@ poll_node.send_poll(tx_ids, MSG_TX) assert_response( - [AvalancheVote(AvalancheTxVoteError.UNKNOWN, txid) for txid in tx_ids]) + [AvalancheVote(AvalancheTxVoteError.UNKNOWN, txid) for txid in tx_ids] + ) self.log.info("Check the votes on invalid transactions") @@ -124,18 +134,15 @@ poll_node.send_message(msg_tx(invalid_tx)) poll_node.send_poll([invalid_txid], MSG_TX) - assert_response( - [AvalancheVote(AvalancheTxVoteError.INVALID, invalid_txid)]) + assert_response([AvalancheVote(AvalancheTxVoteError.INVALID, invalid_txid)]) self.log.info("Check the votes on orphan transactions") orphan_tx = CTransaction() - orphan_tx.vin.append( - CTxIn(outpoint=COutPoint(random.randint(0, 2**256), 0))) + orphan_tx.vin.append(CTxIn(outpoint=COutPoint(random.randint(0, 2**256), 0))) orphan_tx.vout = [ - CTxOut( - nValue=1_000_000, - scriptPubKey=wallet.get_scriptPubKey())] + CTxOut(nValue=1_000_000, scriptPubKey=wallet.get_scriptPubKey()) + ] pad_tx(orphan_tx) orphan_txid = int(orphan_tx.get_id(), 16) @@ -143,9 +150,8 @@ poll_node.send_message(msg_tx(orphan_tx)) poll_node.send_poll([orphan_txid], MSG_TX) - assert_response( - [AvalancheVote(AvalancheTxVoteError.ORPHAN, orphan_txid)]) + assert_response([AvalancheVote(AvalancheTxVoteError.ORPHAN, orphan_txid)]) -if __name__ == '__main__': +if __name__ == "__main__": AvalancheTransactionVotingTest().main() diff --git a/test/functional/abc_p2p_avalanche_voting.py b/test/functional/abc_p2p_avalanche_voting.py --- a/test/functional/abc_p2p_avalanche_voting.py +++ b/test/functional/abc_p2p_avalanche_voting.py @@ -29,21 +29,21 @@ self.num_nodes = 2 self.extra_args = [ [ - '-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=1', - '-avacooldown=0', - '-avaminquorumstake=0', - '-avaminavaproofsnodecount=0', - '-whitelist=noban@127.0.0.1', + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=1", + "-avacooldown=0", + "-avaminquorumstake=0", + "-avaminavaproofsnodecount=0", + "-whitelist=noban@127.0.0.1", ], [ - '-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=1', - '-avacooldown=0', - '-avaminquorumstake=0', - '-avaminavaproofsnodecount=0', - '-noparkdeepreorg', - '-whitelist=noban@127.0.0.1', + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=1", + "-avacooldown=0", + "-avaminquorumstake=0", + "-avaminavaproofsnodecount=0", + "-noparkdeepreorg", + "-whitelist=noban@127.0.0.1", ], ] self.supports_cli = False @@ -54,14 +54,15 @@ # Build a fake quorum of nodes. def get_quorum(): - return [get_ava_p2p_interface(self, node) - for _ in range(0, QUORUM_NODE_COUNT)] + return [ + get_ava_p2p_interface(self, node) for _ in range(0, QUORUM_NODE_COUNT) + ] # Pick one node from the quorum for polling. quorum = get_quorum() poll_node = quorum[0] - assert node.getavalancheinfo()['ready_to_poll'] is True + assert node.getavalancheinfo()["ready_to_poll"] is True # Generate many block and poll for them. self.generate(node, 100 - node.getblockcount()) @@ -89,8 +90,7 @@ for i in range(0, len(votes)): assert_equal(repr(votes[i]), repr(expected[i])) - assert_response( - [AvalancheVote(AvalancheVoteError.ACCEPTED, best_block_hash)]) + assert_response([AvalancheVote(AvalancheVoteError.ACCEPTED, best_block_hash)]) self.log.info("Poll for a selection of blocks...") various_block_hashes = [ @@ -105,11 +105,14 @@ ] poll_node.send_poll(various_block_hashes) - assert_response([AvalancheVote(AvalancheVoteError.ACCEPTED, h) - for h in various_block_hashes]) + assert_response( + [ + AvalancheVote(AvalancheVoteError.ACCEPTED, h) + for h in various_block_hashes + ] + ) - self.log.info( - "Poll for a selection of blocks, but some are now invalid...") + self.log.info("Poll for a selection of blocks, but some are now invalid...") invalidated_block = node.getblockhash(76) node.invalidateblock(invalidated_block) # We need to send the coin to a new address in order to make sure we do @@ -118,8 +121,16 @@ node.reconsiderblock(invalidated_block) poll_node.send_poll(various_block_hashes) - assert_response([AvalancheVote(AvalancheVoteError.ACCEPTED, h) for h in various_block_hashes[:5]] + - [AvalancheVote(AvalancheVoteError.FORK, h) for h in various_block_hashes[-3:]]) + assert_response( + [ + AvalancheVote(AvalancheVoteError.ACCEPTED, h) + for h in various_block_hashes[:5] + ] + + [ + AvalancheVote(AvalancheVoteError.FORK, h) + for h in various_block_hashes[-3:] + ] + ) self.log.info("Poll for unknown blocks...") various_block_hashes = [ @@ -134,9 +145,20 @@ random.randrange(1 << 255, (1 << 256) - 1), ] poll_node.send_poll(various_block_hashes) - assert_response([AvalancheVote(AvalancheVoteError.ACCEPTED, h) for h in various_block_hashes[:3]] + - [AvalancheVote(AvalancheVoteError.FORK, h) for h in various_block_hashes[3:6]] + - [AvalancheVote(AvalancheVoteError.UNKNOWN, h) for h in various_block_hashes[-3:]]) + assert_response( + [ + AvalancheVote(AvalancheVoteError.ACCEPTED, h) + for h in various_block_hashes[:3] + ] + + [ + AvalancheVote(AvalancheVoteError.FORK, h) + for h in various_block_hashes[3:6] + ] + + [ + AvalancheVote(AvalancheVoteError.UNKNOWN, h) + for h in various_block_hashes[-3:] + ] + ) self.log.info("Trigger polling from the node...") @@ -192,8 +214,7 @@ def has_parked_tip(tip_park): hash_tip_park = int(tip_park, 16) - can_find_inv_in_poll(quorum, - hash_tip_park, AvalancheVoteError.PARKED) + can_find_inv_in_poll(quorum, hash_tip_park, AvalancheVoteError.PARKED) for tip in node.getchaintips(): if tip["hash"] == tip_park: @@ -218,8 +239,9 @@ hash_tip_park = int(tip_to_park, 16) with node.wait_for_debug_log( [f"Avalanche invalidated block {tip_to_park}".encode()], - chatty_callable=lambda: can_find_inv_in_poll(quorum, - hash_tip_park, AvalancheVoteError.PARKED) + chatty_callable=lambda: can_find_inv_in_poll( + quorum, hash_tip_park, AvalancheVoteError.PARKED + ), ): pass @@ -254,8 +276,7 @@ fork_node.invalidateblock(chain_head) # We need to send the coin to a new address in order to make sure we do # not regenerate the same block. - blocks = self.generatetoaddress( - fork_node, 1, ADDRS[1], sync_fun=self.no_op) + blocks = self.generatetoaddress(fork_node, 1, ADDRS[1], sync_fun=self.no_op) chain_head = blocks[0] fork_tip = blocks[0] @@ -267,6 +288,7 @@ assert tip["status"] != "active" return tip["status"] == "valid-headers" return False + self.wait_until(lambda: valid_headers_block(fork_tip)) # sanity check @@ -283,7 +305,8 @@ # We need to send the coin to a new address in order to make sure we do # not regenerate the same block. blocks = self.generatetoaddress( - fork_node, numblocks, ADDRS[numblocks], sync_fun=self.no_op) + fork_node, numblocks, ADDRS[numblocks], sync_fun=self.no_op + ) chain_head = blocks[0] fork_tip = blocks[-1] @@ -294,17 +317,17 @@ # sanity check hash_to_find = int(fork_tip, 16) poll_node.send_poll([hash_to_find]) - assert_response( - [AvalancheVote(AvalancheVoteError.PARKED, hash_to_find)]) + assert_response([AvalancheVote(AvalancheVoteError.PARKED, hash_to_find)]) - self.log.info( - "Check the node is discouraging unexpected avaresponses.") + self.log.info("Check the node is discouraging unexpected avaresponses.") with node.assert_debug_log( - ['Misbehaving', 'peer=1', 'unexpected-ava-response']): + ["Misbehaving", "peer=1", "unexpected-ava-response"] + ): # unknown voting round poll_node.send_avaresponse( - avaround=2**32 - 1, votes=[], privkey=poll_node.delegated_privkey) + avaround=2**32 - 1, votes=[], privkey=poll_node.delegated_privkey + ) -if __name__ == '__main__': +if __name__ == "__main__": AvalancheTest().main() diff --git a/test/functional/abc_p2p_compactblocks.py b/test/functional/abc_p2p_compactblocks.py --- a/test/functional/abc_p2p_compactblocks.py +++ b/test/functional/abc_p2p_compactblocks.py @@ -39,7 +39,6 @@ class PreviousSpendableOutput: - def __init__(self, tx=CTransaction(), n=-1): self.tx = tx # the output we're spending @@ -48,7 +47,6 @@ # TestP2PConn: A peer we use to send messages to bitcoind, and store responses. class TestP2PConn(P2PInterface): - def __init__(self): self.last_sendcmpct = None self.last_cmpctblock = None @@ -78,7 +76,6 @@ class FullBlockTest(BitcoinTestFramework): - def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True @@ -86,14 +83,18 @@ self.tip = None self.blocks = {} self.excessive_block_size = 16 * ONE_MEGABYTE - self.extra_args = [['-whitelist=noban@127.0.0.1', - '-limitancestorcount=999999', - '-limitancestorsize=999999', - '-limitdescendantcount=999999', - '-limitdescendantsize=999999', - '-maxmempool=99999', - f'-excessiveblocksize={self.excessive_block_size}', - '-acceptnonstdtxn=1']] + self.extra_args = [ + [ + "-whitelist=noban@127.0.0.1", + "-limitancestorcount=999999", + "-limitancestorsize=999999", + "-limitdescendantcount=999999", + "-limitdescendantsize=999999", + "-maxmempool=99999", + f"-excessiveblocksize={self.excessive_block_size}", + "-acceptnonstdtxn=1", + ] + ] # UBSAN will cause this test to timeout without this. self.rpc_timeout = 180 @@ -101,8 +102,9 @@ [tx.rehash() for tx in tx_list] block.vtx.extend(tx_list) - def next_block(self, number, spend=None, script=CScript( - [OP_TRUE]), block_size=0, extra_txns=0): + def next_block( + self, number, spend=None, script=CScript([OP_TRUE]), block_size=0, extra_txns=0 + ): if self.tip is None: base_block_hash = self.genesis_hash block_time = int(time.time()) + 1 @@ -151,8 +153,7 @@ # Put some random data into the first transaction of the chain to # randomize ids. - tx.vout.append( - CTxOut(0, CScript([random.randint(0, 256), OP_RETURN]))) + tx.vout.append(CTxOut(0, CScript([random.randint(0, 256), OP_RETURN]))) # Add the transaction to the block self.add_transactions_to_block(block, [tx]) @@ -259,14 +260,16 @@ # Check that compact block also work for big blocks # Wait for SENDCMPCT def received_sendcmpct(): - return (test_p2p.last_sendcmpct is not None) + return test_p2p.last_sendcmpct is not None + self.wait_until(received_sendcmpct, timeout=30) test_p2p.send_and_ping(msg_sendcmpct(announce=True, version=1)) # Exchange headers def received_getheaders(): - return (test_p2p.last_getheaders is not None) + return test_p2p.last_getheaders is not None + self.wait_until(received_getheaders, timeout=30) # Return the favor @@ -274,7 +277,8 @@ # Wait for the header list def received_headers(): - return (test_p2p.last_headers is not None) + return test_p2p.last_headers is not None + self.wait_until(received_headers, timeout=30) # It's like we know about the same headers ! @@ -286,7 +290,8 @@ # Checks the node to forward it via compact block def received_block(): - return (test_p2p.last_cmpctblock is not None) + return test_p2p.last_cmpctblock is not None + self.wait_until(received_block, timeout=30) # Was it our block ? @@ -296,8 +301,12 @@ # Send a large block with numerous transactions. test_p2p.clear_block_data() - b2 = block(2, spend=out[1], extra_txns=70000, - block_size=self.excessive_block_size - 1000) + b2 = block( + 2, + spend=out[1], + extra_txns=70000, + block_size=self.excessive_block_size - 1000, + ) default_p2p.send_blocks_and_test([self.tip], node) # Checks the node forwards it via compact block @@ -332,5 +341,5 @@ assert int(node.getbestblockhash(), 16) == b2.sha256 -if __name__ == '__main__': +if __name__ == "__main__": FullBlockTest().main() diff --git a/test/functional/abc_p2p_compactproofs.py b/test/functional/abc_p2p_compactproofs.py --- a/test/functional/abc_p2p_compactproofs.py +++ b/test/functional/abc_p2p_compactproofs.py @@ -52,11 +52,13 @@ class CompactProofsTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 - self.extra_args = [[ - '-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=1', - '-avacooldown=0', - ]] * self.num_nodes + self.extra_args = [ + [ + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=1", + "-avacooldown=0", + ] + ] * self.num_nodes def setup_network(self): # Don't connect the nodes @@ -69,7 +71,8 @@ def test_send_outbound_getavaproofs(self): self.log.info( - "Check we send a getavaproofs message to our avalanche outbound peers") + "Check we send a getavaproofs message to our avalanche outbound peers" + ) node = self.nodes[0] p2p_idx = 0 @@ -86,8 +89,8 @@ p2p_idx += 1 inbound_avapeers = [ - node.add_p2p_connection( - NoHandshakeAvaP2PInterface()) for _ in range(4)] + node.add_p2p_connection(NoHandshakeAvaP2PInterface()) for _ in range(4) + ] outbound_avapeers = [] # With a proof and the service bit set @@ -116,40 +119,52 @@ def all_peers_received_getavaproofs(): with p2p_lock: - return all(p.last_message.get("getavaproofs") - for p in outbound_avapeers) + return all( + p.last_message.get("getavaproofs") for p in outbound_avapeers + ) + self.wait_until(all_peers_received_getavaproofs) with p2p_lock: - assert all(p.message_count.get( - "getavaproofs", 0) >= 1 for p in outbound_avapeers) - assert all(p.message_count.get( - "getavaproofs", 0) == 0 for p in non_avapeers) - assert all(p.message_count.get( - "getavaproofs", 0) == 0 for p in inbound_avapeers) + assert all( + p.message_count.get("getavaproofs", 0) >= 1 for p in outbound_avapeers + ) + assert all( + p.message_count.get("getavaproofs", 0) == 0 for p in non_avapeers + ) + assert all( + p.message_count.get("getavaproofs", 0) == 0 for p in inbound_avapeers + ) self.log.info( - "Check we send periodic getavaproofs message to some of our peers") + "Check we send periodic getavaproofs message to some of our peers" + ) def count_outbounds_getavaproofs(): with p2p_lock: - return sum([p.message_count.get("getavaproofs", 0) - for p in outbound_avapeers]) + return sum( + [p.message_count.get("getavaproofs", 0) for p in outbound_avapeers] + ) outbounds_getavaproofs = count_outbounds_getavaproofs() node.mockscheduler(AVALANCHE_MAX_PERIODIC_NETWORKING_INTERVAL) - self.wait_until(lambda: count_outbounds_getavaproofs() - == outbounds_getavaproofs + 3) + self.wait_until( + lambda: count_outbounds_getavaproofs() == outbounds_getavaproofs + 3 + ) outbounds_getavaproofs += 3 with p2p_lock: - assert all(p.message_count.get( - "getavaproofs", 0) == 0 for p in non_avapeers) - assert all(p.message_count.get( - "getavaproofs", 0) == 0 for p in inbound_avapeers) + assert all( + p.message_count.get("getavaproofs", 0) == 0 for p in non_avapeers + ) + assert all( + p.message_count.get("getavaproofs", 0) == 0 for p in inbound_avapeers + ) self.log.info( - "After the first avaproofs has been received, all the peers are requested periodically") + "After the first avaproofs has been received, all the peers are requested" + " periodically" + ) responding_outbound_avapeer = AvaP2PInterface(self, node) node.add_outbound_p2p_connection( @@ -173,8 +188,10 @@ outbounds_getavaproofs = count_outbounds_getavaproofs() num_outbound_avapeers = len(outbound_avapeers) node.mockscheduler(AVALANCHE_MAX_PERIODIC_NETWORKING_INTERVAL) - self.wait_until(lambda: count_outbounds_getavaproofs() - == outbounds_getavaproofs + num_outbound_avapeers) + self.wait_until( + lambda: count_outbounds_getavaproofs() + == outbounds_getavaproofs + num_outbound_avapeers + ) outbounds_getavaproofs += num_outbound_avapeers self.log.info("Empty avaproofs will not trigger any request") @@ -184,20 +201,28 @@ with p2p_lock: # Only this peer actually sent a proof assert_equal( - responding_outbound_avapeer.message_count.get( - "avaproofsreq", 0), 1) - assert_equal(sum([p.message_count.get("avaproofsreq", 0) - for p in outbound_avapeers]), 1) + responding_outbound_avapeer.message_count.get("avaproofsreq", 0), 1 + ) + assert_equal( + sum( + [p.message_count.get("avaproofsreq", 0) for p in outbound_avapeers] + ), + 1, + ) # Sanity checks - assert all(p.message_count.get( - "getavaproofs", 0) == 0 for p in non_avapeers) - assert all(p.message_count.get( - "getavaproofs", 0) == 0 for p in inbound_avapeers) + assert all( + p.message_count.get("getavaproofs", 0) == 0 for p in non_avapeers + ) + assert all( + p.message_count.get("getavaproofs", 0) == 0 for p in inbound_avapeers + ) def test_send_manual_getavaproofs(self): self.log.info( - "Check we send a getavaproofs message to our manually connected peers that support avalanche") + "Check we send a getavaproofs message to our manually connected peers that" + " support avalanche" + ) node = self.nodes[0] # Get rid of previously connected nodes @@ -205,8 +230,7 @@ def added_node_connected(ip_port): added_node_info = node.getaddednodeinfo(ip_port) - return len( - added_node_info) == 1 and added_node_info[0]['connected'] + return len(added_node_info) == 1 and added_node_info[0]["connected"] def connect_callback(address, port): self.log.debug(f"Connecting to {address}:{port}") @@ -225,8 +249,8 @@ node.addnode(node=ip_port, command="add") self.wait_until(lambda: added_node_connected(ip_port)) - assert_equal(node.getpeerinfo()[-1]['addr'], ip_port) - assert_equal(node.getpeerinfo()[-1]['connection_type'], 'manual') + assert_equal(node.getpeerinfo()[-1]["addr"], ip_port) + assert_equal(node.getpeerinfo()[-1]["connection_type"], "manual") # Make sure p.is_connected is set, otherwise the last_message check # below will assert. @@ -267,10 +291,9 @@ avaproofs = self.received_avaproofs(receiving_peer) expected_shortids = [ - calculate_shortid( - avaproofs.key0, - avaproofs.key1, - proofid) for proofid in sorted(proofids)] + calculate_shortid(avaproofs.key0, avaproofs.key1, proofid) + for proofid in sorted(proofids) + ] assert_equal(expected_shortids, avaproofs.shortids) # Don't expect any prefilled proof for now @@ -278,7 +301,9 @@ def test_request_missing_proofs(self): self.log.info( - "Check the node requests the missing proofs after receiving an avaproofs message") + "Check the node requests the missing proofs after receiving an avaproofs" + " message" + ) node = self.nodes[0] @@ -299,9 +324,7 @@ spam_peer = get_ava_p2p_interface(self, node) - msg = build_msg_avaproofs( - proofs, prefilled_proofs=[], key_pair=[ - key0, key1]) + msg = build_msg_avaproofs(proofs, prefilled_proofs=[], key_pair=[key0, key1]) with node.assert_debug_log(["Ignoring unsollicited avaproofs"]): spam_peer.send_message(msg) @@ -332,8 +355,8 @@ nonlocal p2p_idx msg = build_msg_avaproofs( - [], prefilled_proofs=prefilled_proofs, key_pair=[ - key0, key1]) + [], prefilled_proofs=prefilled_proofs, key_pair=[key0, key1] + ) msg.shortids = shortids peer = add_avalanche_p2p_outbound() @@ -354,28 +377,23 @@ with p2p_lock: assert_equal(sender.message_count.get("avaproofsreq", 0), 0) - self.log.info( - "Check the node requests all the proofs if it known none") + self.log.info("Check the node requests all the proofs if it known none") - expect_indices( - list(shortid_map.values()), - list(range(len(shortid_map))) - ) + expect_indices(list(shortid_map.values()), list(range(len(shortid_map)))) - self.log.info( - "Check the node requests only the missing proofs") + self.log.info("Check the node requests only the missing proofs") known_proofids = [] for proof in proofs[:5]: node.sendavalancheproof(proof.serialize().hex()) known_proofids.append(proof.proofid) - expected_indices = [i for i, proofid in enumerate( - shortid_map) if proofid not in known_proofids] + expected_indices = [ + i for i, proofid in enumerate(shortid_map) if proofid not in known_proofids + ] expect_indices(list(shortid_map.values()), expected_indices) - self.log.info( - "Check the node don't request prefilled proofs") + self.log.info("Check the node don't request prefilled proofs") # Get the indices for a couple of proofs indice_proof5 = list(shortid_map.keys()).index(proofids[5]) @@ -385,20 +403,22 @@ AvalanchePrefilledProof(indice_proof6, proofs[6]), ] prefilled_proofs = sorted( - prefilled_proofs, - key=lambda prefilled_proof: prefilled_proof.index) - remaining_shortids = [shortid for proofid, shortid in shortid_map.items( - ) if proofid not in proofids[5:7]] + prefilled_proofs, key=lambda prefilled_proof: prefilled_proof.index + ) + remaining_shortids = [ + shortid + for proofid, shortid in shortid_map.items() + if proofid not in proofids[5:7] + ] known_proofids.extend(proofids[5:7]) - expected_indices = [i for i, proofid in enumerate( - shortid_map) if proofid not in known_proofids] + expected_indices = [ + i for i, proofid in enumerate(shortid_map) if proofid not in known_proofids + ] expect_indices( - remaining_shortids, - expected_indices, - prefilled_proofs=prefilled_proofs) + remaining_shortids, expected_indices, prefilled_proofs=prefilled_proofs + ) - self.log.info( - "Check the node requests no proof if it knows all of them") + self.log.info("Check the node requests no proof if it knows all of them") for proof in proofs[5:]: node.sendavalancheproof(proof.serialize().hex()) @@ -410,10 +430,13 @@ bad_peer = add_avalanche_p2p_outbound() - msg = build_msg_avaproofs([], prefilled_proofs=[ - AvalanchePrefilledProof( - len(shortid_map) + 1, - gen_proof(self, node)[1])], key_pair=[key0, key1]) + msg = build_msg_avaproofs( + [], + prefilled_proofs=[ + AvalanchePrefilledProof(len(shortid_map) + 1, gen_proof(self, node)[1]) + ], + key_pair=[key0, key1], + ) msg.shortids = list(shortid_map.values()) with node.assert_debug_log(["Misbehaving", "avaproofs-bad-indexes"]): @@ -427,9 +450,13 @@ bad_peer = add_avalanche_p2p_outbound() - msg = build_msg_avaproofs([], prefilled_proofs=[ - AvalanchePrefilledProof(len(shortid_map), no_stake), - ], key_pair=[key0, key1]) + msg = build_msg_avaproofs( + [], + prefilled_proofs=[ + AvalanchePrefilledProof(len(shortid_map), no_stake), + ], + key_pair=[key0, key1], + ) msg.shortids = list(shortid_map.values()) with node.assert_debug_log(["Misbehaving", "invalid-proof"]): @@ -484,18 +511,16 @@ requester.send_message(req) # Check we got the expected number of proofs - self.wait_until( - lambda: len( - requester.get_proofs()) == len(indices)) + self.wait_until(lambda: len(requester.get_proofs()) == len(indices)) # Check we got the expected proofs received_shortids = [ - calculate_shortid( - avaproofs.key0, - avaproofs.key1, - proof.proofid) for proof in requester.get_proofs()] - assert_equal(set(received_shortids), - {avaproofs.shortids[i] for i in indices}) + calculate_shortid(avaproofs.key0, avaproofs.key1, proof.proofid) + for proof in requester.get_proofs() + ] + assert_equal( + set(received_shortids), {avaproofs.shortids[i] for i in indices} + ) # Only the first proof check_received_proofs([0]) @@ -513,7 +538,9 @@ check_received_proofs(range(numof_proof)) self.log.info( - "Check the node will not send the proofs if not requested before the timeout elapsed") + "Check the node will not send the proofs if not requested before the" + " timeout elapsed" + ) # Disconnect the peers for peer in node.p2ps: @@ -530,10 +557,9 @@ connection_type="avalanche", services=NODE_NETWORK | NODE_AVALANCHE, ) - slow_peer.wait_until( - lambda: slow_peer.last_message.get("getavaproofs")) + slow_peer.wait_until(lambda: slow_peer.last_message.get("getavaproofs")) - slow_peer.nodeid = node.getpeerinfo()[-1]['id'] + slow_peer.nodeid = node.getpeerinfo()[-1]["id"] _ = request_proofs(slow_peer) # Elapse the timeout @@ -545,8 +571,7 @@ # Periodic compact proofs requests are sent in the same loop than the # cleanup, so when such a request is made we are sure the cleanup did # happen. - slow_peer.wait_until( - lambda: slow_peer.message_count.get("getavaproofs") > 1) + slow_peer.wait_until(lambda: slow_peer.message_count.get("getavaproofs") > 1) req = msg_avaproofsreq() req.indices = range(numof_proof) @@ -557,7 +582,8 @@ def test_compact_proofs_download_on_connect(self): self.log.info( - "Check the node get compact proofs upon avalanche outbound discovery") + "Check the node get compact proofs upon avalanche outbound discovery" + ) requestee = self.nodes[0] requester = self.nodes[1] @@ -576,22 +602,20 @@ self.start_node(1) self.connect_nodes(0, 1) self.wait_until( - lambda: all( - proof.proofid in proofids for proof in get_proof_ids(requester))) + lambda: all(proof.proofid in proofids for proof in get_proof_ids(requester)) + ) def test_no_compactproofs_during_ibs(self): - self.log.info( - "Check the node don't request compact proofs during IBD") + self.log.info("Check the node don't request compact proofs during IBD") node = self.nodes[0] - chainwork = int(node.getblockchaininfo()['chainwork'], 16) + chainwork = int(node.getblockchaininfo()["chainwork"], 16) self.restart_node( - 0, - extra_args=self.extra_args[0] + - [f'-minimumchainwork={chainwork + 2:#x}']) + 0, extra_args=self.extra_args[0] + [f"-minimumchainwork={chainwork + 2:#x}"] + ) - assert node.getblockchaininfo()['initialblockdownload'] + assert node.getblockchaininfo()["initialblockdownload"] peer = P2PInterface() node.add_outbound_p2p_connection( @@ -615,28 +639,31 @@ def test_send_inbound_getavaproofs_until_quorum_is_established(self): self.log.info( - "Check we also request the inbounds until the quorum is established") + "Check we also request the inbounds until the quorum is established" + ) node = self.nodes[0] self.restart_node( 0, - extra_args=self.extra_args[0] + - ['-avaminquorumstake=1000000', '-avaminavaproofsnodecount=0']) + extra_args=self.extra_args[0] + + ["-avaminquorumstake=1000000", "-avaminavaproofsnodecount=0"], + ) - assert_equal(node.getavalancheinfo()['ready_to_poll'], False) + assert_equal(node.getavalancheinfo()["ready_to_poll"], False) outbound = AvaP2PInterface() node.add_outbound_p2p_connection(outbound, p2p_idx=0) inbound = AvaP2PInterface() node.add_p2p_connection(inbound) - inbound.nodeid = node.getpeerinfo()[-1]['id'] + inbound.nodeid = node.getpeerinfo()[-1]["id"] def count_getavaproofs(peers): with p2p_lock: - return sum([peer.message_count.get("getavaproofs", 0) - for peer in peers]) + return sum( + [peer.message_count.get("getavaproofs", 0) for peer in peers] + ) # Upon connection only the outbound gets a compact proofs message assert_equal(count_getavaproofs([inbound]), 0) @@ -646,15 +673,15 @@ current_total = count_getavaproofs([inbound, outbound]) while count_getavaproofs([inbound]) == 0: node.mockscheduler(AVALANCHE_MAX_PERIODIC_NETWORKING_INTERVAL) - self.wait_until(lambda: count_getavaproofs( - [inbound, outbound]) > current_total) + self.wait_until( + lambda: count_getavaproofs([inbound, outbound]) > current_total + ) current_total = count_getavaproofs([inbound, outbound]) # Connect the minimum amount of stake and nodes for _ in range(8): node.add_p2p_connection(AvaP2PInterface(self, node)) - self.wait_until(lambda: node.getavalancheinfo() - ['ready_to_poll'] is True) + self.wait_until(lambda: node.getavalancheinfo()["ready_to_poll"] is True) # From now only the outbound is requested count_inbound = count_getavaproofs([inbound]) @@ -680,5 +707,5 @@ self.test_send_inbound_getavaproofs_until_quorum_is_established() -if __name__ == '__main__': +if __name__ == "__main__": CompactProofsTest().main() diff --git a/test/functional/abc_p2p_fullblocktest.py b/test/functional/abc_p2p_fullblocktest.py --- a/test/functional/abc_p2p_fullblocktest.py +++ b/test/functional/abc_p2p_fullblocktest.py @@ -36,7 +36,6 @@ class PreviousSpendableOutput: - def __init__(self, tx=CTransaction(), n=-1): self.tx = tx # the output we're spending @@ -44,7 +43,6 @@ class FullBlockTest(BitcoinTestFramework): - def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True @@ -52,8 +50,12 @@ self.tip = None self.blocks = {} self.excessive_block_size = 100 * ONE_MEGABYTE - self.extra_args = [['-whitelist=noban@127.0.0.1', - f"-excessiveblocksize={self.excessive_block_size}"]] + self.extra_args = [ + [ + "-whitelist=noban@127.0.0.1", + f"-excessiveblocksize={self.excessive_block_size}", + ] + ] self.supports_cli = False # The default timeout is not enough when submitting large blocks with # TSAN enabled @@ -63,8 +65,7 @@ [tx.rehash() for tx in tx_list] block.vtx.extend(tx_list) - def next_block(self, number, spend=None, - script=CScript([OP_TRUE]), block_size=0): + def next_block(self, number, spend=None, script=CScript([OP_TRUE]), block_size=0): if self.tip is None: base_block_hash = self.genesis_hash block_time = int(time.time()) + 1 @@ -113,8 +114,7 @@ # Put some random data into the first transaction of the chain to # randomize ids. - tx.vout.append( - CTxOut(0, CScript([random.randint(0, 256), OP_RETURN]))) + tx.vout.append(CTxOut(0, CScript([random.randint(0, 256), OP_RETURN]))) # Add the transaction to the block self.add_transactions_to_block(block, [tx]) @@ -143,7 +143,7 @@ else: script_length = 500000 script_pad_len = script_length - script_output = CScript([b'\x00' * script_pad_len]) + script_output = CScript([b"\x00" * script_pad_len]) tx.vout.append(CTxOut(0, script_output)) # Add the tx to the list of transactions to be included @@ -218,7 +218,8 @@ # Reject oversized blocks with bad-blk-length error block(18, spend=out[17], block_size=self.excessive_block_size + 1) peer.send_blocks_and_test( - [self.tip], node, success=False, reject_reason='bad-blk-length', timeout=360) + [self.tip], node, success=False, reject_reason="bad-blk-length", timeout=360 + ) # Disconnect all the peers now so our node doesn't try to relay the next # large block, which could cause a timeout during the test shutdown. @@ -228,10 +229,9 @@ self.tip = self.blocks[17] # Submit a very large block via RPC - large_block = block( - 33, spend=out[17], block_size=self.excessive_block_size) + large_block = block(33, spend=out[17], block_size=self.excessive_block_size) assert_equal(node.submitblock(ToHex(large_block)), None) -if __name__ == '__main__': +if __name__ == "__main__": FullBlockTest().main() diff --git a/test/functional/abc_p2p_getavaaddr.py b/test/functional/abc_p2p_getavaaddr.py --- a/test/functional/abc_p2p_getavaaddr.py +++ b/test/functional/abc_p2p_getavaaddr.py @@ -76,10 +76,13 @@ def on_avapoll(self, message): self.send_avaresponse( - message.poll.round, [ - AvalancheVote( - AvalancheVoteError.ACCEPTED, inv.hash) for inv in message.poll.invs], - self.master_privkey if self.delegation is None else self.delegated_privkey) + message.poll.round, + [ + AvalancheVote(AvalancheVoteError.ACCEPTED, inv.hash) + for inv in message.poll.invs + ], + self.master_privkey if self.delegation is None else self.delegated_privkey, + ) super().on_avapoll(message) @@ -98,25 +101,24 @@ self.num_nodes = 1 self.extra_args = [ [ - '-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=1', - '-avacooldown=0', - '-avaminquorumstake=0', - '-avaminavaproofsnodecount=0', - '-whitelist=noban@127.0.0.1', + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=1", + "-avacooldown=0", + "-avaminquorumstake=0", + "-avaminavaproofsnodecount=0", + "-whitelist=noban@127.0.0.1", ] ] def check_all_peers_received_getavaaddr_once(self, avapeers): def received_all_getavaaddr(avapeers): with p2p_lock: - return all(p.last_message.get("getavaaddr") - for p in avapeers) + return all(p.last_message.get("getavaaddr") for p in avapeers) + self.wait_until(lambda: received_all_getavaaddr(avapeers)) with p2p_lock: - assert all(p.message_count.get( - "getavaaddr", 0) == 1 for p in avapeers) + assert all(p.message_count.get("getavaaddr", 0) == 1 for p in avapeers) def getavaaddr_interval_test(self): node = self.nodes[0] @@ -132,8 +134,8 @@ # Build some statistics to ensure some addresses will be returned def all_peers_received_poll(): with p2p_lock: - return all(avanode.poll_received > - 0 for avanode in node.p2ps) + return all(avanode.poll_received > 0 for avanode in node.p2ps) + self.wait_until(all_peers_received_poll) node.mockscheduler(AVALANCHE_STATISTICS_INTERVAL) @@ -145,8 +147,8 @@ # Spamming more get getavaaddr has no effect for _ in range(2): with node.assert_debug_log( - ["Ignoring repeated getavaaddr from peer"], - timeout=10): + ["Ignoring repeated getavaaddr from peer"], timeout=10 + ): requester.send_message(msg_getavaaddr()) # Move the time so we get an addr response @@ -166,9 +168,8 @@ def address_test(self, maxaddrtosend, num_proof, num_avanode): self.restart_node( - 0, - extra_args=self.extra_args[0] + - [f'-maxaddrtosend={maxaddrtosend}']) + 0, extra_args=self.extra_args[0] + [f"-maxaddrtosend={maxaddrtosend}"] + ) node = self.nodes[0] # Init mock time @@ -191,7 +192,8 @@ avanodes.append(avanode) responding_addresses = [ - avanode.addr for avanode in avanodes if avanode.is_responding] + avanode.addr for avanode in avanodes if avanode.is_responding + ] assert_equal(len(responding_addresses), num_proof * num_avanode // 2) # Check we have what we expect @@ -201,7 +203,7 @@ return False for avapeer in avapeers: - if avapeer['nodecount'] != num_avanode: + if avapeer["nodecount"] != num_avanode: return False return True @@ -214,8 +216,11 @@ def poll_all_for_block(): with p2p_lock: - return all(avanode.poll_received > ( - 10 if avanode.is_responding else 0) for avanode in avanodes) + return all( + avanode.poll_received > (10 if avanode.is_responding else 0) + for avanode in avanodes + ) + self.wait_until(poll_all_for_block) # Move the scheduler time 10 minutes forward so that so that our peers @@ -228,29 +233,36 @@ # Sanity check that the availability score is set up as expected peerinfo = node.getpeerinfo() muted_addresses = [ - avanode.addr for avanode in avanodes if not avanode.is_responding] - assert all(p['availability_score'] < 0 - for p in peerinfo if p["addr"] in muted_addresses) - assert all(p['availability_score'] > 0 - for p in peerinfo if p["addr"] in responding_addresses) + avanode.addr for avanode in avanodes if not avanode.is_responding + ] + assert all( + p["availability_score"] < 0 + for p in peerinfo + if p["addr"] in muted_addresses + ) + assert all( + p["availability_score"] > 0 + for p in peerinfo + if p["addr"] in responding_addresses + ) # Requester has no availability_score because it's not an avalanche # peer - assert 'availability_score' not in peerinfo[-1].keys() + assert "availability_score" not in peerinfo[-1].keys() mock_time += MAX_ADDR_SEND_DELAY node.setmocktime(mock_time) requester.wait_until(requester.addr_received) addresses = requester.get_received_addrs() - assert_equal(len(addresses), - min(maxaddrtosend, len(responding_addresses))) + assert_equal(len(addresses), min(maxaddrtosend, len(responding_addresses))) # Check all the addresses belong to responding peer assert all(address in responding_addresses for address in addresses) def getavaaddr_outbound_test(self): self.log.info( - "Check we send a getavaaddr message to our avalanche outbound peers") + "Check we send a getavaaddr message to our avalanche outbound peers" + ) node = self.nodes[0] # Get rid of previously connected nodes @@ -278,11 +290,14 @@ def all_peers_received_getavaaddr(): with p2p_lock: return all(p.message_count.get("getavaaddr", 0) > 1 for p in avapeers) + self.wait_until(all_peers_received_getavaaddr) def getavaaddr_manual_test(self): self.log.info( - "Check we send a getavaaddr message to our manually connected peers that support avalanche") + "Check we send a getavaaddr message to our manually connected peers that" + " support avalanche" + ) node = self.nodes[0] # Get rid of previously connected nodes @@ -290,8 +305,7 @@ def added_node_connected(ip_port): added_node_info = node.getaddednodeinfo(ip_port) - return len( - added_node_info) == 1 and added_node_info[0]['connected'] + return len(added_node_info) == 1 and added_node_info[0]["connected"] def connect_callback(address, port): self.log.debug(f"Connecting to {address}:{port}") @@ -309,8 +323,8 @@ node.addnode(node=ip_port, command="add") self.wait_until(lambda: added_node_connected(ip_port)) - assert_equal(node.getpeerinfo()[-1]['addr'], ip_port) - assert_equal(node.getpeerinfo()[-1]['connection_type'], 'manual') + assert_equal(node.getpeerinfo()[-1]["addr"], ip_port) + assert_equal(node.getpeerinfo()[-1]["connection_type"], "manual") # Make sure p.is_connected is set, otherwise the last_message check # below will assert. @@ -327,13 +341,18 @@ def getavaaddr_noquorum(self): self.log.info( - "Check we send a getavaaddr message while our quorum is not established") + "Check we send a getavaaddr message while our quorum is not established" + ) node = self.nodes[0] - self.restart_node(0, extra_args=self.extra_args[0] + [ - '-avaminquorumstake=500000000', - '-avaminquorumconnectedstakeratio=0.8', - ]) + self.restart_node( + 0, + extra_args=self.extra_args[0] + + [ + "-avaminquorumstake=500000000", + "-avaminquorumconnectedstakeratio=0.8", + ], + ) avapeers = [] for i in range(16): @@ -353,15 +372,15 @@ def total_getavaaddr_msg(): with p2p_lock: - return sum([p.message_count.get("getavaaddr", 0) - for p in avapeers]) + return sum([p.message_count.get("getavaaddr", 0) for p in avapeers]) # Because we have not enough stake to start polling, we keep requesting # more addresses from all our peers total_getavaaddr = total_getavaaddr_msg() node.mockscheduler(MAX_GETAVAADDR_DELAY) - self.wait_until(lambda: total_getavaaddr_msg() == - total_getavaaddr + len(avapeers)) + self.wait_until( + lambda: total_getavaaddr_msg() == total_getavaaddr + len(avapeers) + ) # Move the schedulter time forward to make sure we get statistics # computed. But since we did not start polling yet it should remain all @@ -370,8 +389,10 @@ def wait_for_availability_score(): peerinfo = node.getpeerinfo() - return all(p.get('availability_score', None) == Decimal(0) - for p in peerinfo) + return all( + p.get("availability_score", None) == Decimal(0) for p in peerinfo + ) + self.wait_until(wait_for_availability_score) requester = node.add_p2p_connection(AddrReceiver()) @@ -390,16 +411,21 @@ for _ in range(4): avapeer = AllYesAvaP2PInterface(self, node) node.add_p2p_connection(avapeer) - self.wait_until(lambda: node.getavalancheinfo() - ['ready_to_poll'] is True) + self.wait_until(lambda: node.getavalancheinfo()["ready_to_poll"] is True) def is_vote_finalized(proof): - return node.getrawavalancheproof( - uint256_hex(proof.proofid)).get("finalized", False) + return node.getrawavalancheproof(uint256_hex(proof.proofid)).get( + "finalized", False + ) # Wait until all proofs are finalized - self.wait_until(lambda: all(is_vote_finalized(p.proof) - for p in node.p2ps if isinstance(p, AvaP2PInterface))) + self.wait_until( + lambda: all( + is_vote_finalized(p.proof) + for p in node.p2ps + if isinstance(p, AvaP2PInterface) + ) + ) # Go through several rounds of getavaaddr requests. We don't know for # sure how many will be sent as it depends on whether the peers @@ -408,8 +434,7 @@ def sent_single_getavaaddr(): total_getavaaddr = total_getavaaddr_msg() node.mockscheduler(MAX_GETAVAADDR_DELAY) - self.wait_until(lambda: total_getavaaddr_msg() - >= total_getavaaddr + 1) + self.wait_until(lambda: total_getavaaddr_msg() >= total_getavaaddr + 1) for p in avapeers: p.sync_send_with_ping() return total_getavaaddr_msg() == total_getavaaddr + 1 @@ -418,28 +443,27 @@ def test_send_inbound_getavaaddr_until_quorum_is_established(self): self.log.info( - "Check we also request the inbounds until the quorum is established") + "Check we also request the inbounds until the quorum is established" + ) node = self.nodes[0] self.restart_node( - 0, - extra_args=self.extra_args[0] + - ['-avaminquorumstake=1000000']) + 0, extra_args=self.extra_args[0] + ["-avaminquorumstake=1000000"] + ) - assert_equal(node.getavalancheinfo()['ready_to_poll'], False) + assert_equal(node.getavalancheinfo()["ready_to_poll"], False) outbound = MutedAvaP2PInterface() node.add_outbound_p2p_connection(outbound, p2p_idx=0) inbound = MutedAvaP2PInterface() node.add_p2p_connection(inbound) - inbound.nodeid = node.getpeerinfo()[-1]['id'] + inbound.nodeid = node.getpeerinfo()[-1]["id"] def count_getavaaddr(peers): with p2p_lock: - return sum([peer.message_count.get("getavaaddr", 0) - for peer in peers]) + return sum([peer.message_count.get("getavaaddr", 0) for peer in peers]) # Upon connection only the outbound gets a getavaaddr message assert_equal(count_getavaaddr([inbound]), 0) @@ -449,15 +473,15 @@ current_total = count_getavaaddr([inbound, outbound]) while count_getavaaddr([inbound]) == 0: node.mockscheduler(MAX_GETAVAADDR_DELAY) - self.wait_until(lambda: count_getavaaddr( - [inbound, outbound]) > current_total) + self.wait_until( + lambda: count_getavaaddr([inbound, outbound]) > current_total + ) current_total = count_getavaaddr([inbound, outbound]) # Connect the minimum amount of stake and nodes for _ in range(8): node.add_p2p_connection(AvaP2PInterface(self, node)) - self.wait_until(lambda: node.getavalancheinfo() - ['ready_to_poll'] is True) + self.wait_until(lambda: node.getavalancheinfo()["ready_to_poll"] is True) # From now only the outbound is requested count_inbound = count_getavaaddr([inbound]) @@ -467,8 +491,9 @@ inbound.sync_send_with_ping() node.mockscheduler(MAX_GETAVAADDR_DELAY) - self.wait_until(lambda: count_getavaaddr( - [inbound, outbound]) > current_total) + self.wait_until( + lambda: count_getavaaddr([inbound, outbound]) > current_total + ) current_total = count_getavaaddr([inbound, outbound]) assert_equal(count_getavaaddr([inbound]), count_inbound) @@ -486,15 +511,13 @@ p.wait_until(lambda: p.message_count.get("getaddr", 0) == 1) # Test getaddr is sent first - requester1 = node.add_outbound_p2p_connection( - AvaHelloInterface(), p2p_idx=0) + requester1 = node.add_outbound_p2p_connection(AvaHelloInterface(), p2p_idx=0) requester1.send_message(msg_getaddr()) requester1.send_message(msg_getavaaddr()) check_addr_requests(requester1) # Test getavaaddr is sent first - requester2 = node.add_outbound_p2p_connection( - AvaHelloInterface(), p2p_idx=1) + requester2 = node.add_outbound_p2p_connection(AvaHelloInterface(), p2p_idx=1) requester2.send_message(msg_getavaaddr()) requester2.send_message(msg_getaddr()) check_addr_requests(requester2) @@ -514,5 +537,5 @@ self.test_addr_requests_order() -if __name__ == '__main__': +if __name__ == "__main__": AvaAddrTest().main() diff --git a/test/functional/abc_p2p_proof_inventory.py b/test/functional/abc_p2p_proof_inventory.py --- a/test/functional/abc_p2p_proof_inventory.py +++ b/test/functional/abc_p2p_proof_inventory.py @@ -55,12 +55,14 @@ class ProofInventoryTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 5 - self.extra_args = [[ - '-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=2', - '-avacooldown=0', - '-whitelist=noban@127.0.0.1', - ]] * self.num_nodes + self.extra_args = [ + [ + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=2", + "-avacooldown=0", + "-whitelist=noban@127.0.0.1", + ] + ] * self.num_nodes def generate_proof(self, node, mature=True): privkey, proof = gen_proof(self, node) @@ -138,18 +140,22 @@ privkey = node.get_deterministic_priv_key().key missing_stake = node.buildavalancheproof( - 1, 0, privkey, [{ - 'txid': '0' * 64, - 'vout': 0, - 'amount': 10000000, - 'height': 42, - 'iscoinbase': False, - 'privatekey': privkey, - }] + 1, + 0, + privkey, + [ + { + "txid": "0" * 64, + "vout": 0, + "amount": 10000000, + "height": 42, + "iscoinbase": False, + "privatekey": privkey, + } + ], ) - self.restart_node( - 0, ['-avaproofstakeutxodustthreshold=1000000']) + self.restart_node(0, ["-avaproofstakeutxodustthreshold=1000000"]) peer = node.add_p2p_connection(P2PInterface()) msg = msg_avaproof() @@ -161,10 +167,12 @@ peer.sync_with_ping() msg.proof = bad_proof - with node.assert_debug_log([ - 'Misbehaving', - 'invalid-proof', - ]): + with node.assert_debug_log( + [ + "Misbehaving", + "invalid-proof", + ] + ): peer.send_message(msg) peer.wait_for_disconnect() @@ -180,22 +188,30 @@ def restart_nodes_with_proof(nodes, extra_args=None): for node in nodes: privkey, proof = proofs_keys[node.index] - self.restart_node(node.index, self.extra_args[node.index] + [ - f"-avaproof={proof.serialize().hex()}", - f"-avamasterkey={bytes_to_wif(privkey.get_bytes())}" - ] + (extra_args or [])) + self.restart_node( + node.index, + self.extra_args[node.index] + + [ + f"-avaproof={proof.serialize().hex()}", + f"-avamasterkey={bytes_to_wif(privkey.get_bytes())}", + ] + + (extra_args or []), + ) restart_nodes_with_proof(self.nodes[:-1]) - chainwork = int(self.nodes[-1].getblockchaininfo()['chainwork'], 16) + chainwork = int(self.nodes[-1].getblockchaininfo()["chainwork"], 16) restart_nodes_with_proof( - self.nodes[-1:], extra_args=[f'-minimumchainwork={chainwork + 100:#x}']) + self.nodes[-1:], extra_args=[f"-minimumchainwork={chainwork + 100:#x}"] + ) # Add an inbound so the node proof can be registered and advertised [node.add_p2p_connection(P2PInterface()) for node in self.nodes] - [[self.connect_nodes(node.index, j) - for j in range(node.index)] for node in self.nodes] + [ + [self.connect_nodes(node.index, j) for j in range(node.index)] + for node in self.nodes + ] # Connect a block to make the proofs added to our pool self.generate(self.nodes[0], 1, sync_fun=self.sync_blocks) @@ -205,7 +221,7 @@ for node in self.nodes[:-1]: assert_equal(set(get_proof_ids(node)), proofids) - assert self.nodes[-1].getblockchaininfo()['initialblockdownload'] + assert self.nodes[-1].getblockchaininfo()["initialblockdownload"] self.log.info("Except the node that has not completed IBD") assert_equal(len(get_proof_ids(self.nodes[-1])), 1) @@ -217,20 +233,21 @@ peer.send_avaproof(proof) peer.sync_send_with_ping() with p2p_lock: - assert_equal(peer.message_count.get('getdata', 0), 0) + assert_equal(peer.message_count.get("getdata", 0), 0) # Leave the nodes in good shape for the next tests restart_nodes_with_proof(self.nodes) - [[self.connect_nodes(node.index, j) - for j in range(node.index)] for node in self.nodes] + [ + [self.connect_nodes(node.index, j) for j in range(node.index)] + for node in self.nodes + ] def test_manually_sent_proof(self): node0 = self.nodes[0] _, proof = self.generate_proof(node0) - self.log.info( - "Send a proof via RPC and check all the nodes download it") + self.log.info("Send a proof via RPC and check all the nodes download it") node0.sendavalancheproof(proof.serialize().hex()) self.sync_proofs() @@ -262,8 +279,11 @@ def proof_inv_received(peers): with p2p_lock: - return all(p.last_message.get( - "inv") and p.last_message["inv"].inv[-1].hash == proof.proofid for p in peers) + return all( + p.last_message.get("inv") + and p.last_message["inv"].inv[-1].hash == proof.proofid + for p in peers + ) self.wait_until(lambda: proof_inv_received(peers)) @@ -287,8 +307,7 @@ assert not proof_inv_received(peers) - self.log.info( - "Proofs that become invalid should no longer be broadcasted") + self.log.info("Proofs that become invalid should no longer be broadcasted") # Restart and add connect a new set of peers self.restart_node(0) @@ -305,18 +324,20 @@ self.generate(node, 100, sync_fun=self.no_op) utxo = proof.stakes[0].stake.utxo raw_tx = node.createrawtransaction( - inputs=[{ - # coinbase - "txid": uint256_hex(utxo.txid), - "vout": utxo.n - }], + inputs=[ + { + # coinbase + "txid": uint256_hex(utxo.txid), + "vout": utxo.n, + } + ], outputs={ADDRESS_ECREG_UNSPENDABLE: 25_000_000 - 250.00}, ) signed_tx = node.signrawtransactionwithkey( hexstring=raw_tx, privkeys=[node.get_deterministic_priv_key().key], ) - node.sendrawtransaction(signed_tx['hex']) + node.sendrawtransaction(signed_tx["hex"]) # Mine the tx in a block self.generate(node, 1, sync_fun=self.no_op) @@ -324,13 +345,13 @@ # Wait for the proof to be invalidated def check_proof_not_found(proofid): try: - assert_raises_rpc_error(-8, - "Proof not found", - node.getrawavalancheproof, - proofid) + assert_raises_rpc_error( + -8, "Proof not found", node.getrawavalancheproof, proofid + ) return True except BaseException: return False + self.wait_until(lambda: check_proof_not_found(proofid_hex)) # It should no longer be broadcasted @@ -351,5 +372,5 @@ self.test_ban_invalid_proof() -if __name__ == '__main__': +if __name__ == "__main__": ProofInventoryTest().main() diff --git a/test/functional/abc_p2p_version_timestamp.py b/test/functional/abc_p2p_version_timestamp.py --- a/test/functional/abc_p2p_version_timestamp.py +++ b/test/functional/abc_p2p_version_timestamp.py @@ -23,8 +23,7 @@ super().__init__() self.versionTimestamp = timestamp - def peer_connect(self, *args, services=NODE_NETWORK, - send_version=False, **kwargs): + def peer_connect(self, *args, services=NODE_NETWORK, send_version=False, **kwargs): create_conn = super().peer_connect(*args, send_version=send_version, **kwargs) # Send version message with invalid timestamp @@ -60,41 +59,56 @@ self.log.info("Check some invalid timestamp in the version message") with self.nodes[0].assert_debug_log( - expected_msgs=["Added connection peer=0", - "Ignoring invalid timestamp in version message"]): + expected_msgs=[ + "Added connection peer=0", + "Ignoring invalid timestamp in version message", + ] + ): self.nodes[0].add_p2p_connection( ModifiedVersionTimestampP2PInterface(-9223372036854775807), - send_version=False) + send_version=False, + ) self.log.info("Check invalid side of the timestamp boundary") with self.nodes[0].assert_debug_log( - expected_msgs=["Added connection peer=1", - "Ignoring invalid timestamp in version message"]): + expected_msgs=[ + "Added connection peer=1", + "Ignoring invalid timestamp in version message", + ] + ): self.nodes[0].add_p2p_connection( ModifiedVersionTimestampP2PInterface(TIME_GENESIS_BLOCK - 1), - send_version=False) + send_version=False, + ) self.log.info("Check valid side of the timestamp boundary (genesis timestamp)") # Outbound connection: the timestamp is used for our adjusted time self.nodes[1].setmocktime(TIME_GENESIS_BLOCK) with self.nodes[0].assert_debug_log( - expected_msgs=["Added connection peer=2", "added time data"], - unexpected_msgs=["Ignoring invalid timestamp in version message"]): + expected_msgs=["Added connection peer=2", "added time data"], + unexpected_msgs=["Ignoring invalid timestamp in version message"], + ): self.connect_nodes(0, 1) # This check verifies that the mocktime was indeed used in the VERSION message - assert_equal(self.nodes[0].getpeerinfo()[2]["timeoffset"], - TIME_GENESIS_BLOCK - NODE0_TIME) + assert_equal( + self.nodes[0].getpeerinfo()[2]["timeoffset"], + TIME_GENESIS_BLOCK - NODE0_TIME, + ) # Inbound connection: the timestamp is ignored with self.nodes[0].assert_debug_log( - expected_msgs=["Added connection peer=3"], - unexpected_msgs=["Ignoring invalid timestamp in version message", - "added time data"]): + expected_msgs=["Added connection peer=3"], + unexpected_msgs=[ + "Ignoring invalid timestamp in version message", + "added time data", + ], + ): self.nodes[0].add_p2p_connection( ModifiedVersionTimestampP2PInterface(TIME_GENESIS_BLOCK), - send_version=False) + send_version=False, + ) -if __name__ == '__main__': +if __name__ == "__main__": VersionTimestampTest().main() diff --git a/test/functional/abc_rpc_addavalanchenode.py b/test/functional/abc_rpc_addavalanchenode.py --- a/test/functional/abc_rpc_addavalanchenode.py +++ b/test/functional/abc_rpc_addavalanchenode.py @@ -25,22 +25,27 @@ n = P2PInterface() test_node.add_p2p_connection(n) n.wait_for_verack() - return test_node.getpeerinfo()[-1]['id'] + return test_node.getpeerinfo()[-1]["id"] class AddAvalancheNodeTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.extra_args = [['-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=1', - '-avacooldown=0']] + self.extra_args = [ + [ + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=1", + "-avacooldown=0", + ] + ] def run_test(self): node = self.nodes[0] addrkey0 = node.get_deterministic_priv_key() blockhashes = self.generatetoaddress( - node, 2, addrkey0.address, sync_fun=self.no_op) + node, 2, addrkey0.address, sync_fun=self.no_op + ) stakes = create_coinbase_stakes(node, [blockhashes[0]], addrkey0.key) privkey = ECKey() @@ -51,12 +56,19 @@ proof_sequence = 42 proof_expiration = 2000000000 proof = node.buildavalancheproof( - proof_sequence, proof_expiration, wif_privkey, stakes) + proof_sequence, proof_expiration, wif_privkey, stakes + ) nodeid = add_interface_node(node) def check_addavalanchenode_error( - error_code, error_message, nodeid=nodeid, proof=proof, pubkey=proof_master, delegation=None): + error_code, + error_message, + nodeid=nodeid, + proof=proof, + pubkey=proof_master, + delegation=None, + ): assert_raises_rpc_error( error_code, error_message, @@ -68,42 +80,47 @@ ) self.log.info("Invalid proof") - check_addavalanchenode_error(-22, - "Proof must be an hexadecimal string", - proof="not a proof") - check_addavalanchenode_error(-22, - "Proof has invalid format", - proof="f000") + check_addavalanchenode_error( + -22, "Proof must be an hexadecimal string", proof="not a proof" + ) + check_addavalanchenode_error(-22, "Proof has invalid format", proof="f000") no_stake = node.buildavalancheproof( - proof_sequence, proof_expiration, wif_privkey, []) - check_addavalanchenode_error(-8, - "The proof is invalid: no-stake", - proof=no_stake) + proof_sequence, proof_expiration, wif_privkey, [] + ) + check_addavalanchenode_error( + -8, "The proof is invalid: no-stake", proof=no_stake + ) self.log.info("Node doesn't exist") - check_addavalanchenode_error(-8, - f"The node does not exist: {nodeid + 1}", - nodeid=nodeid + 1) + check_addavalanchenode_error( + -8, f"The node does not exist: {nodeid + 1}", nodeid=nodeid + 1 + ) self.log.info("Invalid delegation") dg_privkey = ECKey() dg_privkey.generate() dg_pubkey = dg_privkey.get_pubkey().get_bytes() - check_addavalanchenode_error(-22, - "Delegation must be an hexadecimal string", - pubkey=dg_pubkey.hex(), - delegation="not a delegation") - check_addavalanchenode_error(-22, - "Delegation has invalid format", - pubkey=dg_pubkey.hex(), - delegation="f000") + check_addavalanchenode_error( + -22, + "Delegation must be an hexadecimal string", + pubkey=dg_pubkey.hex(), + delegation="not a delegation", + ) + check_addavalanchenode_error( + -22, + "Delegation has invalid format", + pubkey=dg_pubkey.hex(), + delegation="f000", + ) self.log.info("Delegation mismatch with the proof") delegation_wrong_proofid = AvalancheDelegation() - check_addavalanchenode_error(-8, - "The delegation does not match the proof", - pubkey=dg_pubkey.hex(), - delegation=delegation_wrong_proofid.serialize().hex()) + check_addavalanchenode_error( + -8, + "The delegation does not match the proof", + pubkey=dg_pubkey.hex(), + delegation=delegation_wrong_proofid.serialize().hex(), + ) proofobj = avalanche_proof_from_hex(proof) delegation = AvalancheDelegation( @@ -116,20 +133,19 @@ pubkey=dg_pubkey, ) delegation.levels.append(bad_level) - check_addavalanchenode_error(-8, - "The delegation is invalid", - pubkey=dg_pubkey.hex(), - delegation=delegation.serialize().hex()) + check_addavalanchenode_error( + -8, + "The delegation is invalid", + pubkey=dg_pubkey.hex(), + delegation=delegation.serialize().hex(), + ) delegation.levels = [] level = AvalancheDelegationLevel( pubkey=dg_pubkey, sig=privkey.sign_schnorr( - hash256( - delegation.getid() + - ser_string(dg_pubkey) - ) - ) + hash256(delegation.getid() + ser_string(dg_pubkey)) + ), ) delegation.levels.append(level) @@ -169,5 +185,5 @@ assert node.addavalanchenode(nodeid2, proof_master, proof) -if __name__ == '__main__': +if __name__ == "__main__": AddAvalancheNodeTest().main() diff --git a/test/functional/abc_rpc_avalancheproof.py b/test/functional/abc_rpc_avalancheproof.py --- a/test/functional/abc_rpc_avalancheproof.py +++ b/test/functional/abc_rpc_avalancheproof.py @@ -50,20 +50,22 @@ n = P2PInterface() test_node.add_p2p_connection(n) n.wait_for_verack() - return test_node.getpeerinfo()[-1]['id'] + return test_node.getpeerinfo()[-1]["id"] class AvalancheProofTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 - self.extra_args = [[ - f'-avaproofstakeutxodustthreshold={PROOF_DUST_THRESHOLD}', - '-avaproofstakeutxoconfirmations=1', - '-avalancheconflictingproofcooldown=0', - '-avacooldown=0', - '-whitelist=noban@127.0.0.1', - ]] * self.num_nodes + self.extra_args = [ + [ + f"-avaproofstakeutxodustthreshold={PROOF_DUST_THRESHOLD}", + "-avaproofstakeutxoconfirmations=1", + "-avalancheconflictingproofcooldown=0", + "-avacooldown=0", + "-whitelist=noban@127.0.0.1", + ] + ] * self.num_nodes self.supports_cli = False self.rpc_timeout = 120 @@ -78,19 +80,23 @@ # LUT from test_node.py def legacy_to_ecash_p2pkh(legacy): payload, _ = base58_to_byte(legacy) - return encode_full('ecregtest', PUBKEY_TYPE, payload) + return encode_full("ecregtest", PUBKEY_TYPE, payload) addrkey0 = node.get_deterministic_priv_key() node_ecash_addr = legacy_to_ecash_p2pkh(addrkey0.address) blockhashes = self.generatetoaddress( - node, 100, node_ecash_addr, sync_fun=self.no_op) + node, 100, node_ecash_addr, sync_fun=self.no_op + ) - self.log.info( - "Make build a valid proof and restart the node to use it") + self.log.info("Make build a valid proof and restart the node to use it") privkey = ECKey() - privkey.set(bytes.fromhex( - "12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747"), True) + privkey.set( + bytes.fromhex( + "12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747" + ), + True, + ) wif_privkey = bytes_to_wif(privkey.get_bytes()) def get_hex_pubkey(privkey): @@ -101,33 +107,45 @@ proof_expiration = 0 stakes = create_coinbase_stakes(node, [blockhashes[0]], addrkey0.key) proof = node.buildavalancheproof( - proof_sequence, proof_expiration, wif_privkey, stakes, ADDRESS_ECREG_UNSPENDABLE) + proof_sequence, + proof_expiration, + wif_privkey, + stakes, + ADDRESS_ECREG_UNSPENDABLE, + ) self.log.info("Test decodeavalancheproof RPC") # Invalid hex (odd number of hex digits) - assert_raises_rpc_error(-22, "Proof must be an hexadecimal string", - node.decodeavalancheproof, proof[:-1]) + assert_raises_rpc_error( + -22, + "Proof must be an hexadecimal string", + node.decodeavalancheproof, + proof[:-1], + ) # Valid hex but invalid proof - assert_raises_rpc_error(-22, "Proof has invalid format", - node.decodeavalancheproof, proof[:-2]) + assert_raises_rpc_error( + -22, "Proof has invalid format", node.decodeavalancheproof, proof[:-2] + ) decoded_proof = node.decodeavalancheproof(proof) - assert_equal( - decoded_proof["sequence"], - proof_sequence) - assert_equal( - decoded_proof["expiration"], - proof_expiration) + assert_equal(decoded_proof["sequence"], proof_sequence) + assert_equal(decoded_proof["expiration"], proof_expiration) assert_equal(decoded_proof["master"], proof_master) - assert_equal(decoded_proof["payoutscript"], { - "asm": "OP_DUP OP_HASH160 0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG", - "hex": "76a914000000000000000000000000000000000000000088ac", - "reqSigs": 1, - "type": "pubkeyhash", - "addresses": [ADDRESS_ECREG_UNSPENDABLE], - }) + assert_equal( + decoded_proof["payoutscript"], + { + "asm": ( + "OP_DUP OP_HASH160 0000000000000000000000000000000000000000" + " OP_EQUALVERIFY OP_CHECKSIG" + ), + "hex": "76a914000000000000000000000000000000000000000088ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ADDRESS_ECREG_UNSPENDABLE], + }, + ) proofobj = FromHex(AvalancheProof(), proof) limited_id_hex = uint256_hex(proofobj.limited_proofid) @@ -135,46 +153,35 @@ assert_equal( decoded_proof["signature"], - base64.b64encode(proofobj.signature).decode("ascii")) - assert_equal( - decoded_proof["proofid"], - uint256_hex(proofobj.proofid)) - assert_equal( - decoded_proof["limitedid"], - uint256_hex(proofobj.limited_proofid)) - assert_equal( - decoded_proof["staked_amount"], - Decimal('50000000.00')) - assert_equal( - decoded_proof["score"], - 5000) - assert_equal( - decoded_proof["stakes"][0]["txid"], - stakes[0]["txid"]) - assert_equal( - decoded_proof["stakes"][0]["vout"], - stakes[0]["vout"]) - assert_equal( - decoded_proof["stakes"][0]["height"], - stakes[0]["height"]) - assert_equal( - decoded_proof["stakes"][0]["iscoinbase"], - stakes[0]["iscoinbase"]) - assert_equal( - decoded_proof["stakes"][0]["address"], - node_ecash_addr) + base64.b64encode(proofobj.signature).decode("ascii"), + ) + assert_equal(decoded_proof["proofid"], uint256_hex(proofobj.proofid)) + assert_equal(decoded_proof["limitedid"], uint256_hex(proofobj.limited_proofid)) + assert_equal(decoded_proof["staked_amount"], Decimal("50000000.00")) + assert_equal(decoded_proof["score"], 5000) + assert_equal(decoded_proof["stakes"][0]["txid"], stakes[0]["txid"]) + assert_equal(decoded_proof["stakes"][0]["vout"], stakes[0]["vout"]) + assert_equal(decoded_proof["stakes"][0]["height"], stakes[0]["height"]) + assert_equal(decoded_proof["stakes"][0]["iscoinbase"], stakes[0]["iscoinbase"]) + assert_equal(decoded_proof["stakes"][0]["address"], node_ecash_addr) assert_equal( decoded_proof["stakes"][0]["signature"], - base64.b64encode(proofobj.stakes[0].sig).decode("ascii")) + base64.b64encode(proofobj.stakes[0].sig).decode("ascii"), + ) # Restart the node with this proof - self.restart_node(0, self.extra_args[0] + [ - f"-avaproof={proof}", - "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", - ]) + self.restart_node( + 0, + self.extra_args[0] + + [ + f"-avaproof={proof}", + "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", + ], + ) self.log.info( - "The proof is registered at first chaintip update if we have inbounds") + "The proof is registered at first chaintip update if we have inbounds" + ) assert_equal(len(node.getavalanchepeerinfo()), 0) self.generate(node, 1, sync_fun=self.no_op) node.syncwithvalidationinterfacequeue() @@ -191,11 +198,15 @@ self.log.info("Start a node with an immature proof") stake_age = node.getblockcount() + 2 - self.restart_node(1, self.extra_args[0] + [ - f"-avaproofstakeutxoconfirmations={stake_age}", - f"-avaproof={proof}", - "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", - ]) + self.restart_node( + 1, + self.extra_args[0] + + [ + f"-avaproofstakeutxoconfirmations={stake_age}", + f"-avaproof={proof}", + "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", + ], + ) self.connect_nodes(1, node.index) self.sync_blocks() @@ -208,11 +219,12 @@ # Mine another block to make the proof mature self.generate(self.nodes[1], 1, sync_fun=self.no_op) - self.wait_until(lambda: self.nodes[1].getrawavalancheproof( - proofid_hex)["boundToPeer"] is True) + self.wait_until( + lambda: self.nodes[1].getrawavalancheproof(proofid_hex)["boundToPeer"] + is True + ) - self.log.info( - "Generate delegations for the proof, verify and decode them") + self.log.info("Generate delegations for the proof, verify and decode them") # Stack up a few delegation levels def gen_privkey(): @@ -235,15 +247,15 @@ assert node.verifyavalanchedelegation(delegation) dg_info = node.decodeavalanchedelegation(delegation) - assert_equal(dg_info['pubkey'], delegated_pubkey) - assert_equal(dg_info['proofmaster'], proof_master) - assert 'delegationid' in dg_info.keys() - assert_equal(dg_info['limitedid'], limited_id_hex) - assert_equal(dg_info['proofid'], proofid_hex) - assert_equal(dg_info['depth'], i + 1) - assert_equal(len(dg_info['levels']), dg_info['depth']) - assert_equal(dg_info['levels'][-1]['pubkey'], delegated_pubkey) - assert 'signature' in dg_info['levels'][-1] + assert_equal(dg_info["pubkey"], delegated_pubkey) + assert_equal(dg_info["proofmaster"], proof_master) + assert "delegationid" in dg_info.keys() + assert_equal(dg_info["limitedid"], limited_id_hex) + assert_equal(dg_info["proofid"], proofid_hex) + assert_equal(dg_info["depth"], i + 1) + assert_equal(len(dg_info["levels"]), dg_info["depth"]) + assert_equal(dg_info["levels"][-1]["pubkey"], delegated_pubkey) + assert "signature" in dg_info["levels"][-1] delegator_privkey = delegated_privkey @@ -256,93 +268,123 @@ delegation, ) - assert_raises_rpc_error(-8, - "too-many-levels", - node.verifyavalanchedelegation, - too_many_levels_delegation) + assert_raises_rpc_error( + -8, + "too-many-levels", + node.verifyavalanchedelegation, + too_many_levels_delegation, + ) random_privkey = gen_privkey() random_pubkey = get_hex_pubkey(random_privkey) # Invalid proof - no_stake = node.buildavalancheproof(proof_sequence, proof_expiration, - wif_privkey, []) + no_stake = node.buildavalancheproof( + proof_sequence, proof_expiration, wif_privkey, [] + ) # Invalid privkey - assert_raises_rpc_error(-5, "The private key is invalid", - node.delegateavalancheproof, - limited_id_hex, - bytes_to_wif(bytes(32)), - random_pubkey, - ) + assert_raises_rpc_error( + -5, + "The private key is invalid", + node.delegateavalancheproof, + limited_id_hex, + bytes_to_wif(bytes(32)), + random_pubkey, + ) # Invalid delegation bad_dg = AvalancheDelegation() - assert_raises_rpc_error(-8, "The delegation does not match the proof", - node.delegateavalancheproof, - limited_id_hex, - bytes_to_wif(privkey.get_bytes()), - random_pubkey, - bad_dg.serialize().hex(), - ) + assert_raises_rpc_error( + -8, + "The delegation does not match the proof", + node.delegateavalancheproof, + limited_id_hex, + bytes_to_wif(privkey.get_bytes()), + random_pubkey, + bad_dg.serialize().hex(), + ) # Still invalid, but with a matching proofid bad_dg.limited_proofid = proofobj.limited_proofid bad_dg.proof_master = proofobj.master bad_dg.levels = [AvalancheDelegationLevel()] - assert_raises_rpc_error(-8, "The delegation is invalid", - node.delegateavalancheproof, - limited_id_hex, - bytes_to_wif(privkey.get_bytes()), - random_pubkey, - bad_dg.serialize().hex(), - ) + assert_raises_rpc_error( + -8, + "The delegation is invalid", + node.delegateavalancheproof, + limited_id_hex, + bytes_to_wif(privkey.get_bytes()), + random_pubkey, + bad_dg.serialize().hex(), + ) # Wrong privkey, match the proof but does not match the delegation - assert_raises_rpc_error(-5, "The private key does not match the delegation", - node.delegateavalancheproof, - limited_id_hex, - bytes_to_wif(privkey.get_bytes()), - random_pubkey, - delegation, - ) + assert_raises_rpc_error( + -5, + "The private key does not match the delegation", + node.delegateavalancheproof, + limited_id_hex, + bytes_to_wif(privkey.get_bytes()), + random_pubkey, + delegation, + ) # Delegation not hex - assert_raises_rpc_error(-22, "Delegation must be an hexadecimal string.", - node.delegateavalancheproof, - limited_id_hex, - bytes_to_wif(privkey.get_bytes()), - random_pubkey, - "f00", - ) + assert_raises_rpc_error( + -22, + "Delegation must be an hexadecimal string.", + node.delegateavalancheproof, + limited_id_hex, + bytes_to_wif(privkey.get_bytes()), + random_pubkey, + "f00", + ) # Delegation is hex but ill-formed - assert_raises_rpc_error(-22, "Delegation has invalid format", - node.delegateavalancheproof, - limited_id_hex, - bytes_to_wif(privkey.get_bytes()), - random_pubkey, - "dead", - ) + assert_raises_rpc_error( + -22, + "Delegation has invalid format", + node.delegateavalancheproof, + limited_id_hex, + bytes_to_wif(privkey.get_bytes()), + random_pubkey, + "dead", + ) # Test invalid proofs dust = node.buildavalancheproof( - proof_sequence, proof_expiration, wif_privkey, - create_coinbase_stakes(node, [blockhashes[0]], addrkey0.key, amount="0")) + proof_sequence, + proof_expiration, + wif_privkey, + create_coinbase_stakes(node, [blockhashes[0]], addrkey0.key, amount="0"), + ) dust2 = node.buildavalancheproof( - proof_sequence, proof_expiration, wif_privkey, - create_coinbase_stakes(node, [blockhashes[0]], addrkey0.key, - amount=f"{PROOF_DUST_THRESHOLD * 0.9999:.2f}")) + proof_sequence, + proof_expiration, + wif_privkey, + create_coinbase_stakes( + node, + [blockhashes[0]], + addrkey0.key, + amount=f"{PROOF_DUST_THRESHOLD * 0.9999:.2f}", + ), + ) missing_stake = node.buildavalancheproof( - proof_sequence, proof_expiration, wif_privkey, [{ - 'txid': '0' * 64, - 'vout': 0, - 'amount': 10000000, - 'height': 42, - 'iscoinbase': False, - 'privatekey': addrkey0.key, - }] + proof_sequence, + proof_expiration, + wif_privkey, + [ + { + "txid": "0" * 64, + "vout": 0, + "amount": 10000000, + "height": 42, + "iscoinbase": False, + "privatekey": addrkey0.key, + } + ], ) # The hardcoded proofs are extracted from proof_tests.cpp @@ -394,44 +436,48 @@ ) expired = node.buildavalancheproof( - proof_sequence, 1, wif_privkey, - create_coinbase_stakes(node, [blockhashes[0]], addrkey0.key)) + proof_sequence, + 1, + wif_privkey, + create_coinbase_stakes(node, [blockhashes[0]], addrkey0.key), + ) - self.log.info( - "Check the verifyavalancheproof and sendavalancheproof RPCs") + self.log.info("Check the verifyavalancheproof and sendavalancheproof RPCs") if self.is_wallet_compiled(): - self.log.info( - "Check a proof with the maximum number of UTXO is valid") + self.log.info("Check a proof with the maximum number of UTXO is valid") new_blocks = self.generate( - node, AVALANCHE_MAX_PROOF_STAKES // 10 + 1, sync_fun=self.no_op) + node, AVALANCHE_MAX_PROOF_STAKES // 10 + 1, sync_fun=self.no_op + ) # confirm the coinbase UTXOs self.generate(node, 101, sync_fun=self.no_op) too_many_stakes = create_stakes( - self, node, new_blocks, AVALANCHE_MAX_PROOF_STAKES + 1) + self, node, new_blocks, AVALANCHE_MAX_PROOF_STAKES + 1 + ) # Make the newly split UTXOs mature self.generate(node, stake_age, sync_fun=self.no_op) maximum_stakes = too_many_stakes[:-1] good_proof = node.buildavalancheproof( - proof_sequence, proof_expiration, - wif_privkey, maximum_stakes) + proof_sequence, proof_expiration, wif_privkey, maximum_stakes + ) too_many_utxos = node.buildavalancheproof( - proof_sequence, proof_expiration, - wif_privkey, too_many_stakes) + proof_sequence, proof_expiration, wif_privkey, too_many_stakes + ) assert node.verifyavalancheproof(good_proof) for rpc in [node.verifyavalancheproof, node.sendavalancheproof]: - assert_raises_rpc_error(-22, "Proof must be an hexadecimal string", - rpc, "f00") - assert_raises_rpc_error(-22, "Proof has invalid format", - rpc, "f00d") + assert_raises_rpc_error( + -22, "Proof must be an hexadecimal string", rpc, "f00" + ) + assert_raises_rpc_error(-22, "Proof has invalid format", rpc, "f00d") def check_rpc_failure(proof, message): - assert_raises_rpc_error(-8, f"The proof is invalid: {message}", - rpc, proof) + assert_raises_rpc_error( + -8, f"The proof is invalid: {message}", rpc, proof + ) check_rpc_failure(no_stake, "no-stake") check_rpc_failure(dust, "amount-below-dust-threshold") @@ -444,16 +490,22 @@ check_rpc_failure(too_many_utxos, "too-many-utxos") conflicting_utxo = node.buildavalancheproof( - proof_sequence - 1, proof_expiration, wif_privkey, stakes) - assert_raises_rpc_error(-8, "conflicting-utxos", - node.sendavalancheproof, conflicting_utxo) + proof_sequence - 1, proof_expiration, wif_privkey, stakes + ) + assert_raises_rpc_error( + -8, "conflicting-utxos", node.sendavalancheproof, conflicting_utxo + ) # Clear the proof pool stake_age = node.getblockcount() - self.restart_node(0, self.extra_args[0] + [ - f"-avaproofstakeutxoconfirmations={stake_age}", - '-avalancheconflictingproofcooldown=0' - ]) + self.restart_node( + 0, + self.extra_args[0] + + [ + f"-avaproofstakeutxoconfirmations={stake_age}", + "-avalancheconflictingproofcooldown=0", + ], + ) # Good proof assert node.verifyavalancheproof(proof) @@ -466,41 +518,43 @@ def inv_found(): with p2p_lock: - return peer.last_message.get( - "inv") and peer.last_message["inv"].inv[-1].hash == proofid + return ( + peer.last_message.get("inv") + and peer.last_message["inv"].inv[-1].hash == proofid + ) + self.wait_until(inv_found) self.log.info("Check the getrawproof RPC") raw_proof = node.getrawavalancheproof(uint256_hex(proofid)) - assert_equal(raw_proof['proof'], proof) - assert_equal(raw_proof['immature'], False) - assert_equal(raw_proof['boundToPeer'], True) - assert_equal(raw_proof['conflicting'], False) - assert_equal(raw_proof['finalized'], False) - - assert_raises_rpc_error(-8, "Proof not found", - node.getrawavalancheproof, '0' * 64) + assert_equal(raw_proof["proof"], proof) + assert_equal(raw_proof["immature"], False) + assert_equal(raw_proof["boundToPeer"], True) + assert_equal(raw_proof["conflicting"], False) + assert_equal(raw_proof["finalized"], False) + + assert_raises_rpc_error( + -8, "Proof not found", node.getrawavalancheproof, "0" * 64 + ) conflicting_proof = node.buildavalancheproof( - proof_sequence - 1, proof_expiration, wif_privkey, stakes) + proof_sequence - 1, proof_expiration, wif_privkey, stakes + ) conflicting_proofobj = avalanche_proof_from_hex(conflicting_proof) conflicting_proofid_hex = uint256_hex(conflicting_proofobj.proofid) msg = msg_avaproof() msg.proof = conflicting_proofobj peer.send_message(msg) - wait_for_proof( - node, - conflicting_proofid_hex, - expect_status="conflicting") + wait_for_proof(node, conflicting_proofid_hex, expect_status="conflicting") raw_proof = node.getrawavalancheproof(conflicting_proofid_hex) - assert_equal(raw_proof['proof'], conflicting_proof) - assert_equal(raw_proof['immature'], False) - assert_equal(raw_proof['boundToPeer'], False) - assert_equal(raw_proof['conflicting'], True) - assert_equal(raw_proof['finalized'], False) + assert_equal(raw_proof["proof"], conflicting_proof) + assert_equal(raw_proof["immature"], False) + assert_equal(raw_proof["boundToPeer"], False) + assert_equal(raw_proof["conflicting"], True) + assert_equal(raw_proof["finalized"], False) # Make the proof immature by switching to a shorter chain node.invalidateblock(node.getbestblockhash()) @@ -508,10 +562,7 @@ # called unless new chainwork needs evaluating, so invalidate another # block and then mine a new one. node.invalidateblock(node.getbestblockhash()) - node.setmocktime( - node.getblock( - node.getbestblockhash())['mediantime'] + - 100) + node.setmocktime(node.getblock(node.getbestblockhash())["mediantime"] + 100) self.generate(node, 1, sync_fun=self.no_op) # Wait until UpdatedBlockTip has been called so we know the proof @@ -519,32 +570,37 @@ node.syncwithvalidationinterfacequeue() raw_proof = node.getrawavalancheproof(uint256_hex(proofid)) - assert_equal(raw_proof['proof'], proof) - assert_equal(raw_proof['immature'], True) - assert_equal(raw_proof['boundToPeer'], False) - assert_equal(raw_proof['conflicting'], False) - assert_equal(raw_proof['finalized'], False) + assert_equal(raw_proof["proof"], proof) + assert_equal(raw_proof["immature"], True) + assert_equal(raw_proof["boundToPeer"], False) + assert_equal(raw_proof["conflicting"], False) + assert_equal(raw_proof["finalized"], False) self.log.info("Bad proof should be rejected at startup") self.stop_node(0) node.assert_start_raises_init_error( - self.extra_args[0] + [ + self.extra_args[0] + + [ "-avasessionkey=0", ], expected_msg="Error: The avalanche session key is invalid.", ) node.assert_start_raises_init_error( - self.extra_args[0] + [ + self.extra_args[0] + + [ f"-avaproof={proof}", ], - expected_msg="Error: The avalanche master key is missing for the avalanche proof.", + expected_msg=( + "Error: The avalanche master key is missing for the avalanche proof." + ), ) node.assert_start_raises_init_error( - self.extra_args[0] + [ + self.extra_args[0] + + [ f"-avaproof={proof}", "-avamasterkey=0", ], @@ -553,29 +609,30 @@ def check_proof_init_error(proof, message): node.assert_start_raises_init_error( - self.extra_args[0] + [ + self.extra_args[0] + + [ f"-avaproof={proof}", "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", ], expected_msg=f"Error: {message}", ) - check_proof_init_error(no_stake, - "The avalanche proof has no stake.") - check_proof_init_error(dust, - "The avalanche proof stake is too low.") - check_proof_init_error(dust2, - "The avalanche proof stake is too low.") - check_proof_init_error(duplicate_stake, - "The avalanche proof has duplicated stake.") - check_proof_init_error(bad_sig, - "The avalanche proof has invalid stake signatures.") + check_proof_init_error(no_stake, "The avalanche proof has no stake.") + check_proof_init_error(dust, "The avalanche proof stake is too low.") + check_proof_init_error(dust2, "The avalanche proof stake is too low.") + check_proof_init_error( + duplicate_stake, "The avalanche proof has duplicated stake." + ) + check_proof_init_error( + bad_sig, "The avalanche proof has invalid stake signatures." + ) if self.is_wallet_compiled(): # The too many utxos case creates a proof which is that large that it # cannot fit on the command line append_config(node.datadir, [f"avaproof={too_many_utxos}"]) node.assert_start_raises_init_error( - self.extra_args[0] + [ + self.extra_args[0] + + [ "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", ], expected_msg="Error: The avalanche proof has too many utxos.", @@ -586,7 +643,8 @@ random_privkey = ECKey() random_privkey.generate() node.assert_start_raises_init_error( - self.extra_args[0] + [ + self.extra_args[0] + + [ f"-avaproof={proof}", f"-avamasterkey={bytes_to_wif(random_privkey.get_bytes())}", ], @@ -597,7 +655,8 @@ def check_delegation_init_error(delegation, message): node.assert_start_raises_init_error( - self.extra_args[0] + [ + self.extra_args[0] + + [ f"-avadelegation={delegation}", f"-avaproof={proof}", f"-avamasterkey={bytes_to_wif(delegated_privkey.get_bytes())}", @@ -609,43 +668,55 @@ check_delegation_init_error( AvalancheDelegation().serialize().hex(), - "The delegation does not match the proof.") + "The delegation does not match the proof.", + ) bad_level_sig = FromHex(AvalancheDelegation(), delegation) # Tweak some key to cause the signature to mismatch bad_level_sig.levels[-2].pubkey = bytes.fromhex(proof_master) - check_delegation_init_error(bad_level_sig.serialize().hex(), - "The avalanche delegation has invalid signatures.") + check_delegation_init_error( + bad_level_sig.serialize().hex(), + "The avalanche delegation has invalid signatures.", + ) node.assert_start_raises_init_error( - self.extra_args[0] + [ + self.extra_args[0] + + [ f"-avadelegation={delegation}", f"-avaproof={proof}", f"-avamasterkey={bytes_to_wif(random_privkey.get_bytes())}", ], - expected_msg="Error: The master key does not match the delegation public key.", + expected_msg=( + "Error: The master key does not match the delegation public key." + ), ) # The node stacks another delegation level at startup node.assert_start_raises_init_error( - self.extra_args[0] + [ + self.extra_args[0] + + [ f"-avadelegation={delegation}", f"-avaproof={proof}", f"-avamasterkey={bytes_to_wif(delegated_privkey.get_bytes())}", ], - expected_msg="Error: The avalanche delegation has too many delegation levels.", + expected_msg=( + "Error: The avalanche delegation has too many delegation levels." + ), ) node.assert_start_raises_init_error( - self.extra_args[0] + [ + self.extra_args[0] + + [ f"-avadelegation={too_many_levels_delegation}", f"-avaproof={proof}", f"-avamasterkey={bytes_to_wif(too_many_levels_privkey.get_bytes())}", f"-avasessionkey={bytes_to_wif(too_many_levels_privkey.get_bytes())}", ], - expected_msg="Error: The avalanche delegation has too many delegation levels.", + expected_msg=( + "Error: The avalanche delegation has too many delegation levels." + ), ) -if __name__ == '__main__': +if __name__ == "__main__": AvalancheProofTest().main() diff --git a/test/functional/abc_rpc_buildavalancheproof.py b/test/functional/abc_rpc_buildavalancheproof.py --- a/test/functional/abc_rpc_buildavalancheproof.py +++ b/test/functional/abc_rpc_buildavalancheproof.py @@ -15,15 +15,15 @@ class BuildAvalancheProofTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.extra_args = [['-avaproofstakeutxoconfirmations=1', - '-avacooldown=0']] + self.extra_args = [["-avaproofstakeutxoconfirmations=1", "-avacooldown=0"]] def run_test(self): node = self.nodes[0] addrkey0 = node.get_deterministic_priv_key() blockhashes = self.generatetoaddress( - node, 2, addrkey0.address, sync_fun=self.no_op) + node, 2, addrkey0.address, sync_fun=self.no_op + ) stakes = create_coinbase_stakes(node, [blockhashes[0]], addrkey0.key) privkey = ECKey() @@ -31,7 +31,8 @@ wif_privkey = bytes_to_wif(privkey.get_bytes()) def check_buildavalancheproof_error( - error_code, error_message, stakes, master_key=wif_privkey): + error_code, error_message, stakes, master_key=wif_privkey + ): assert_raises_rpc_error( error_code, error_message, @@ -48,74 +49,76 @@ self.log.info("Error cases") - check_buildavalancheproof_error(-8, - "Invalid master key", - [good_stake], - master_key=bytes_to_wif(b'f00') - ) + check_buildavalancheproof_error( + -8, "Invalid master key", [good_stake], master_key=bytes_to_wif(b"f00") + ) negative_vout = good_stake.copy() - negative_vout['vout'] = -1 - check_buildavalancheproof_error(-22, - "vout cannot be negative", - [negative_vout], - ) + negative_vout["vout"] = -1 + check_buildavalancheproof_error( + -22, + "vout cannot be negative", + [negative_vout], + ) zero_height = good_stake.copy() - zero_height['height'] = 0 - check_buildavalancheproof_error(-22, - "height must be positive", - [zero_height], - ) + zero_height["height"] = 0 + check_buildavalancheproof_error( + -22, + "height must be positive", + [zero_height], + ) negative_height = good_stake.copy() - negative_height['height'] = -1 - check_buildavalancheproof_error(-22, - "height must be positive", - [negative_height], - ) + negative_height["height"] = -1 + check_buildavalancheproof_error( + -22, + "height must be positive", + [negative_height], + ) missing_amount = good_stake.copy() - del missing_amount['amount'] - check_buildavalancheproof_error(-8, - "Missing amount", - [missing_amount], - ) + del missing_amount["amount"] + check_buildavalancheproof_error( + -8, + "Missing amount", + [missing_amount], + ) invalid_privkey = good_stake.copy() - invalid_privkey['privatekey'] = 'foobar' - check_buildavalancheproof_error(-8, - "Invalid private key", - [invalid_privkey], - ) + invalid_privkey["privatekey"] = "foobar" + check_buildavalancheproof_error( + -8, + "Invalid private key", + [invalid_privkey], + ) duplicate_stake = [good_stake] * 2 - check_buildavalancheproof_error(-8, - "Duplicated stake", - duplicate_stake, - ) + check_buildavalancheproof_error( + -8, + "Duplicated stake", + duplicate_stake, + ) self.log.info("Happy path") assert node.buildavalancheproof(0, 0, wif_privkey, [good_stake]) self.log.info("Check the payout address") - assert_raises_rpc_error(-8, - "Invalid payout address", - node.buildavalancheproof, - 0, - 0, - wif_privkey, - [good_stake], - "ecregtest:qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqcrl5mqkq", - ) - - # Happy path - node.buildavalancheproof( + assert_raises_rpc_error( + -8, + "Invalid payout address", + node.buildavalancheproof, 0, 0, wif_privkey, [good_stake], - ADDRESS_ECREG_UNSPENDABLE) + "ecregtest:qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqcrl5mqkq", + ) + + # Happy path + node.buildavalancheproof( + 0, 0, wif_privkey, [good_stake], ADDRESS_ECREG_UNSPENDABLE + ) -if __name__ == '__main__': +if __name__ == "__main__": BuildAvalancheProofTest().main() diff --git a/test/functional/abc_rpc_ecash.py b/test/functional/abc_rpc_ecash.py --- a/test/functional/abc_rpc_ecash.py +++ b/test/functional/abc_rpc_ecash.py @@ -16,8 +16,7 @@ def set_test_params(self): self.num_nodes = 1 - def test_currency(self, *, ticker: str, satoshis_per_unit: int, - decimals: int): + def test_currency(self, *, ticker: str, satoshis_per_unit: int, decimals: int): info = self.nodes[0].getcurrencyinfo() assert_equal(info["ticker"], ticker) assert_equal(info["satoshisperunit"], satoshis_per_unit) @@ -36,24 +35,21 @@ "477735025535bceea91c7ba40ec79818dccb164871b16e" ) expected_sats = 5_000_000_000 - assert_equal(decodedproof["stakes"][0]["amount"], - expected_sats / satoshis_per_unit) + assert_equal( + decodedproof["stakes"][0]["amount"], expected_sats / satoshis_per_unit + ) def run_test(self): self.log.info("Test with -ecash enabled (default setting)") - self.test_currency(ticker="XEC", - satoshis_per_unit=100, - decimals=2) + self.test_currency(ticker="XEC", satoshis_per_unit=100, decimals=2) self.log.info("Test with -ecash disabled") # Disable fallbackfee, because its default setting for tests # is adapted to XEC only. # In BCHA mode, it triggers a "-fallbackfee is set very high!" error. self.restart_node(0, ["-ecash=0", "-fallbackfee=0"]) - self.test_currency(ticker="BCHA", - satoshis_per_unit=100_000_000, - decimals=8) + self.test_currency(ticker="BCHA", satoshis_per_unit=100_000_000, decimals=8) -if __name__ == '__main__': +if __name__ == "__main__": ECashRPCTest().main() diff --git a/test/functional/abc_rpc_excessiveblock.py b/test/functional/abc_rpc_excessiveblock.py --- a/test/functional/abc_rpc_excessiveblock.py +++ b/test/functional/abc_rpc_excessiveblock.py @@ -21,7 +21,6 @@ class ExcessiveBlockSizeRPCTest(BitcoinTestFramework): - def set_test_params(self): self.num_nodes = 1 self.tip = None @@ -31,7 +30,7 @@ def check_subversion(self, pattern_str): # Check that the subversion is set as expected netinfo = self.nodes[0].getnetworkinfo() - subversion = netinfo['subversion'] + subversion = netinfo["subversion"] pattern = re.compile(pattern_str) assert pattern.match(subversion) @@ -40,25 +39,24 @@ # Check that we start with DEFAULT_MAX_BLOCK_SIZE getsize = node.getexcessiveblock() - ebs = getsize['excessiveBlockSize'] + ebs = getsize["excessiveBlockSize"] assert_equal(ebs, DEFAULT_MAX_BLOCK_SIZE) def setexcessiveblock(block_size): self.restart_node( - 0, - self.extra_args[0] + - [f"-excessiveblocksize={block_size}"]) + 0, self.extra_args[0] + [f"-excessiveblocksize={block_size}"] + ) # Check that setting to legacy size is ok setexcessiveblock(LEGACY_MAX_BLOCK_SIZE + 1) getsize = node.getexcessiveblock() - ebs = getsize['excessiveBlockSize'] + ebs = getsize["excessiveBlockSize"] assert_equal(ebs, LEGACY_MAX_BLOCK_SIZE + 1) # Check setting to 2MB setexcessiveblock(2 * ONE_MEGABYTE) getsize = node.getexcessiveblock() - ebs = getsize['excessiveBlockSize'] + ebs = getsize["excessiveBlockSize"] assert_equal(ebs, 2 * ONE_MEGABYTE) # Check for EB correctness in the subver string self.check_subversion(r"/Bitcoin ABC:.*\(EB2\.0; .*\)/") @@ -66,7 +64,7 @@ # Check setting to 13MB setexcessiveblock(13 * ONE_MEGABYTE) getsize = node.getexcessiveblock() - ebs = getsize['excessiveBlockSize'] + ebs = getsize["excessiveBlockSize"] assert_equal(ebs, 13 * ONE_MEGABYTE) # Check for EB correctness in the subver string self.check_subversion(r"/Bitcoin ABC:.*\(EB13\.0; .*\)/") @@ -74,7 +72,7 @@ # Check setting to 13.14MB setexcessiveblock(13140000) getsize = node.getexcessiveblock() - ebs = getsize['excessiveBlockSize'] + ebs = getsize["excessiveBlockSize"] assert_equal(ebs, 13.14 * ONE_MEGABYTE) # check for EB correctness in the subver string self.check_subversion(r"/Bitcoin ABC:.*\(EB13\.1; .*\)/") @@ -83,5 +81,5 @@ self.test_excessiveblock() -if __name__ == '__main__': +if __name__ == "__main__": ExcessiveBlockSizeRPCTest().main() diff --git a/test/functional/abc_rpc_getavalancheinfo.py b/test/functional/abc_rpc_getavalancheinfo.py --- a/test/functional/abc_rpc_getavalancheinfo.py +++ b/test/functional/abc_rpc_getavalancheinfo.py @@ -32,14 +32,16 @@ def set_test_params(self): self.num_nodes = 1 self.conflicting_proof_cooldown = 100 - self.extra_args = [[ - f'-avalancheconflictingproofcooldown={self.conflicting_proof_cooldown}', - '-avacooldown=0', - '-avaminquorumstake=250000000', - '-avaminquorumconnectedstakeratio=0.9', - '-avaproofstakeutxodustthreshold=1000000', - '-avaminavaproofsnodecount=0', - ]] + self.extra_args = [ + [ + f"-avalancheconflictingproofcooldown={self.conflicting_proof_cooldown}", + "-avacooldown=0", + "-avaminquorumstake=250000000", + "-avaminquorumconnectedstakeratio=0.9", + "-avaproofstakeutxodustthreshold=1000000", + "-avaminavaproofsnodecount=0", + ] + ] def run_test(self): node = self.nodes[0] @@ -49,97 +51,107 @@ def assert_avalancheinfo(expected): assert_equal(node.getavalancheinfo(), expected) - coinbase_amount = Decimal('25000000.00') + coinbase_amount = Decimal("25000000.00") self.log.info("The test node has no proof") - assert_avalancheinfo({ - "ready_to_poll": False, - "network": { - "proof_count": 0, - "connected_proof_count": 0, - "dangling_proof_count": 0, - "finalized_proof_count": 0, - "conflicting_proof_count": 0, - "immature_proof_count": 0, - "total_stake_amount": Decimal('0.00'), - "connected_stake_amount": Decimal('0.00'), - "dangling_stake_amount": Decimal('0.00'), - "immature_stake_amount": Decimal('0.00'), - "node_count": 0, - "connected_node_count": 0, - "pending_node_count": 0, + assert_avalancheinfo( + { + "ready_to_poll": False, + "network": { + "proof_count": 0, + "connected_proof_count": 0, + "dangling_proof_count": 0, + "finalized_proof_count": 0, + "conflicting_proof_count": 0, + "immature_proof_count": 0, + "total_stake_amount": Decimal("0.00"), + "connected_stake_amount": Decimal("0.00"), + "dangling_stake_amount": Decimal("0.00"), + "immature_stake_amount": Decimal("0.00"), + "node_count": 0, + "connected_node_count": 0, + "pending_node_count": 0, + }, } - }) + ) self.log.info("The test node has a proof") - self.restart_node(0, self.extra_args[0] + [ - f'-avaproof={proof.serialize().hex()}', - f'-avamasterkey={bytes_to_wif(privkey.get_bytes())}', - '-avaproofstakeutxoconfirmations=1', - ]) - - assert_avalancheinfo({ - "ready_to_poll": False, - "local": { - "verified": False, - "verification_status": "pending", - "sharing": False, - "proofid": uint256_hex(proof.proofid), - "limited_proofid": uint256_hex(proof.limited_proofid), - "master": privkey.get_pubkey().get_bytes().hex(), - "stake_amount": coinbase_amount, - "payout_address": ADDRESS_ECREG_UNSPENDABLE, - }, - "network": { - "proof_count": 0, - "connected_proof_count": 0, - "dangling_proof_count": 0, - "finalized_proof_count": 0, - "conflicting_proof_count": 0, - "immature_proof_count": 0, - "total_stake_amount": Decimal('0.00'), - "connected_stake_amount": Decimal('0.00'), - "dangling_stake_amount": Decimal('0.00'), - "immature_stake_amount": Decimal('0.00'), - "node_count": 0, - "connected_node_count": 0, - "pending_node_count": 0, + self.restart_node( + 0, + self.extra_args[0] + + [ + f"-avaproof={proof.serialize().hex()}", + f"-avamasterkey={bytes_to_wif(privkey.get_bytes())}", + "-avaproofstakeutxoconfirmations=1", + ], + ) + + assert_avalancheinfo( + { + "ready_to_poll": False, + "local": { + "verified": False, + "verification_status": "pending", + "sharing": False, + "proofid": uint256_hex(proof.proofid), + "limited_proofid": uint256_hex(proof.limited_proofid), + "master": privkey.get_pubkey().get_bytes().hex(), + "stake_amount": coinbase_amount, + "payout_address": ADDRESS_ECREG_UNSPENDABLE, + }, + "network": { + "proof_count": 0, + "connected_proof_count": 0, + "dangling_proof_count": 0, + "finalized_proof_count": 0, + "conflicting_proof_count": 0, + "immature_proof_count": 0, + "total_stake_amount": Decimal("0.00"), + "connected_stake_amount": Decimal("0.00"), + "dangling_stake_amount": Decimal("0.00"), + "immature_stake_amount": Decimal("0.00"), + "node_count": 0, + "connected_node_count": 0, + "pending_node_count": 0, + }, } - }) + ) # Add an inbound so the node proof can be registered and advertised node.add_p2p_connection(P2PInterface()) - assert_avalancheinfo({ - "ready_to_poll": False, - "local": { - "verified": False, - "verification_status": "pending", - "sharing": True, - "proofid": uint256_hex(proof.proofid), - "limited_proofid": uint256_hex(proof.limited_proofid), - "master": privkey.get_pubkey().get_bytes().hex(), - "stake_amount": coinbase_amount, - "payout_address": ADDRESS_ECREG_UNSPENDABLE, - }, - "network": { - "proof_count": 0, - "connected_proof_count": 0, - "dangling_proof_count": 0, - "finalized_proof_count": 0, - "conflicting_proof_count": 0, - "immature_proof_count": 0, - "total_stake_amount": Decimal('0.00'), - "connected_stake_amount": Decimal('0.00'), - "dangling_stake_amount": Decimal('0.00'), - "immature_stake_amount": Decimal('0.00'), - "node_count": 0, - "connected_node_count": 0, - "pending_node_count": 0, + assert_avalancheinfo( + { + "ready_to_poll": False, + "local": { + "verified": False, + "verification_status": "pending", + "sharing": True, + "proofid": uint256_hex(proof.proofid), + "limited_proofid": uint256_hex(proof.limited_proofid), + "master": privkey.get_pubkey().get_bytes().hex(), + "stake_amount": coinbase_amount, + "payout_address": ADDRESS_ECREG_UNSPENDABLE, + }, + "network": { + "proof_count": 0, + "connected_proof_count": 0, + "dangling_proof_count": 0, + "finalized_proof_count": 0, + "conflicting_proof_count": 0, + "immature_proof_count": 0, + "total_stake_amount": Decimal("0.00"), + "connected_stake_amount": Decimal("0.00"), + "dangling_stake_amount": Decimal("0.00"), + "immature_stake_amount": Decimal("0.00"), + "node_count": 0, + "connected_node_count": 0, + "pending_node_count": 0, + }, } - }) + ) # Make sure receiving our own proof from the network before validating # the local proof doesn't change our proof count. @@ -149,78 +161,86 @@ # Make sure getting the proof via RPC doesn't change our proof count # either. node.sendavalancheproof(proof.serialize().hex()) - assert_avalancheinfo({ - "ready_to_poll": False, - "local": { - "verified": False, - "verification_status": "pending", - "sharing": True, - "proofid": uint256_hex(proof.proofid), - "limited_proofid": uint256_hex(proof.limited_proofid), - "master": privkey.get_pubkey().get_bytes().hex(), - "stake_amount": coinbase_amount, - "payout_address": ADDRESS_ECREG_UNSPENDABLE, - }, - "network": { - "proof_count": 0, - "connected_proof_count": 0, - "dangling_proof_count": 0, - "finalized_proof_count": 0, - "conflicting_proof_count": 0, - "immature_proof_count": 0, - "total_stake_amount": Decimal('0.00'), - "connected_stake_amount": Decimal('0.00'), - "dangling_stake_amount": Decimal('0.00'), - "immature_stake_amount": Decimal('0.00'), - "node_count": 0, - "connected_node_count": 0, - "pending_node_count": 0, + assert_avalancheinfo( + { + "ready_to_poll": False, + "local": { + "verified": False, + "verification_status": "pending", + "sharing": True, + "proofid": uint256_hex(proof.proofid), + "limited_proofid": uint256_hex(proof.limited_proofid), + "master": privkey.get_pubkey().get_bytes().hex(), + "stake_amount": coinbase_amount, + "payout_address": ADDRESS_ECREG_UNSPENDABLE, + }, + "network": { + "proof_count": 0, + "connected_proof_count": 0, + "dangling_proof_count": 0, + "finalized_proof_count": 0, + "conflicting_proof_count": 0, + "immature_proof_count": 0, + "total_stake_amount": Decimal("0.00"), + "connected_stake_amount": Decimal("0.00"), + "dangling_stake_amount": Decimal("0.00"), + "immature_stake_amount": Decimal("0.00"), + "node_count": 0, + "connected_node_count": 0, + "pending_node_count": 0, + }, } - }) - - self.restart_node(0, self.extra_args[0] + [ - f'-avaproof={proof.serialize().hex()}', - f'-avamasterkey={bytes_to_wif(privkey.get_bytes())}', - '-avaproofstakeutxoconfirmations=3', - ]) - - assert_avalancheinfo({ - "ready_to_poll": False, - "local": { - "verified": False, - "verification_status": "pending", - "sharing": False, - "proofid": uint256_hex(proof.proofid), - "limited_proofid": uint256_hex(proof.limited_proofid), - "master": privkey.get_pubkey().get_bytes().hex(), - "stake_amount": coinbase_amount, - "payout_address": ADDRESS_ECREG_UNSPENDABLE, - }, - "network": { - "proof_count": 0, - "connected_proof_count": 0, - "dangling_proof_count": 0, - "finalized_proof_count": 0, - "conflicting_proof_count": 0, - "immature_proof_count": 0, - "total_stake_amount": Decimal('0.00'), - "connected_stake_amount": Decimal('0.00'), - "dangling_stake_amount": Decimal('0.00'), - "immature_stake_amount": Decimal('0.00'), - "node_count": 0, - "connected_node_count": 0, - "pending_node_count": 0, + ) + + self.restart_node( + 0, + self.extra_args[0] + + [ + f"-avaproof={proof.serialize().hex()}", + f"-avamasterkey={bytes_to_wif(privkey.get_bytes())}", + "-avaproofstakeutxoconfirmations=3", + ], + ) + + assert_avalancheinfo( + { + "ready_to_poll": False, + "local": { + "verified": False, + "verification_status": "pending", + "sharing": False, + "proofid": uint256_hex(proof.proofid), + "limited_proofid": uint256_hex(proof.limited_proofid), + "master": privkey.get_pubkey().get_bytes().hex(), + "stake_amount": coinbase_amount, + "payout_address": ADDRESS_ECREG_UNSPENDABLE, + }, + "network": { + "proof_count": 0, + "connected_proof_count": 0, + "dangling_proof_count": 0, + "finalized_proof_count": 0, + "conflicting_proof_count": 0, + "immature_proof_count": 0, + "total_stake_amount": Decimal("0.00"), + "connected_stake_amount": Decimal("0.00"), + "dangling_stake_amount": Decimal("0.00"), + "immature_stake_amount": Decimal("0.00"), + "node_count": 0, + "connected_node_count": 0, + "pending_node_count": 0, + }, } - }) + ) # Add an inbound so the node proof can be registered and advertised node.add_p2p_connection(P2PInterface()) - self.log.info( - "Mine a block to trigger proof validation, check it is immature") + self.log.info("Mine a block to trigger proof validation, check it is immature") self.generate(node, 1, sync_fun=self.no_op) self.wait_until( - lambda: node.getavalancheinfo() == { + lambda: node.getavalancheinfo() + == { "ready_to_poll": False, "local": { "verified": False, @@ -239,21 +259,22 @@ "finalized_proof_count": 0, "conflicting_proof_count": 0, "immature_proof_count": 1, - "total_stake_amount": Decimal('0.00'), - "connected_stake_amount": Decimal('0.00'), - "dangling_stake_amount": Decimal('0.00'), + "total_stake_amount": Decimal("0.00"), + "connected_stake_amount": Decimal("0.00"), + "dangling_stake_amount": Decimal("0.00"), "immature_stake_amount": coinbase_amount, "node_count": 0, "connected_node_count": 0, "pending_node_count": 0, - } + }, } ) self.log.info("Mine another block to mature the local proof") self.generate(node, 1, sync_fun=self.no_op) self.wait_until( - lambda: node.getavalancheinfo() == { + lambda: node.getavalancheinfo() + == { "ready_to_poll": False, "local": { "verified": True, @@ -273,12 +294,12 @@ "immature_proof_count": 0, "total_stake_amount": coinbase_amount, "connected_stake_amount": coinbase_amount, - "dangling_stake_amount": Decimal('0.00'), - "immature_stake_amount": Decimal('0.00'), + "dangling_stake_amount": Decimal("0.00"), + "immature_stake_amount": Decimal("0.00"), "node_count": 1, "connected_node_count": 1, "pending_node_count": 0, - } + }, } ) @@ -299,9 +320,11 @@ # For each proof, also make a conflicting one stakes = create_coinbase_stakes( - node, [node.getbestblockhash()], node.get_deterministic_priv_key().key) + node, [node.getbestblockhash()], node.get_deterministic_priv_key().key + ) conflicting_proof_hex = node.buildavalancheproof( - 10, 0, bytes_to_wif(_privkey.get_bytes()), stakes) + 10, 0, bytes_to_wif(_privkey.get_bytes()), stakes + ) conflicting_proof = avalanche_proof_from_hex(conflicting_proof_hex) conflicting_proofs.append(conflicting_proof) @@ -326,7 +349,8 @@ n.send_avaproof(immature_proof) self.wait_until( - lambda: node.getavalancheinfo() == { + lambda: node.getavalancheinfo() + == { "ready_to_poll": True, "local": { "verified": True, @@ -346,12 +370,12 @@ "immature_proof_count": 1, "total_stake_amount": coinbase_amount * (N + 1), "connected_stake_amount": coinbase_amount * (N + 1), - "dangling_stake_amount": Decimal('0.00'), + "dangling_stake_amount": Decimal("0.00"), "immature_stake_amount": coinbase_amount, "node_count": N + 1, "connected_node_count": N + 1, "pending_node_count": 0, - } + }, } ) @@ -364,7 +388,8 @@ n.wait_for_disconnect() self.wait_until( - lambda: node.getavalancheinfo() == { + lambda: node.getavalancheinfo() + == { "ready_to_poll": True, "local": { "verified": True, @@ -389,7 +414,7 @@ "node_count": N + 1 - D, "connected_node_count": N + 1 - D, "pending_node_count": 0, - } + }, } ) @@ -410,7 +435,7 @@ uint256_hex(_proof.limited_proofid), bytes_to_wif(_privkey.get_bytes()), dg_pub, - None + None, ) # It would be much simpler to just use get_ava_p2p_interface here @@ -425,33 +450,35 @@ # Immature became mature proofs.append(immature_proof) - assert_avalancheinfo({ - "ready_to_poll": True, - "local": { - "verified": True, - "sharing": True, - "proofid": uint256_hex(proof.proofid), - "limited_proofid": uint256_hex(proof.limited_proofid), - "master": privkey.get_pubkey().get_bytes().hex(), - "stake_amount": coinbase_amount, - "payout_address": ADDRESS_ECREG_UNSPENDABLE, - }, - "network": { - "proof_count": N + 2, - "connected_proof_count": N + 1 - D, - "dangling_proof_count": D + 1, - "finalized_proof_count": 0, - "conflicting_proof_count": N, - "immature_proof_count": 0, - "total_stake_amount": coinbase_amount * (N + 2), - "connected_stake_amount": coinbase_amount * (N + 1 - D), - "dangling_stake_amount": coinbase_amount * (D + 1), - "immature_stake_amount": Decimal('0.00'), - "node_count": N + 1 - D + P, - "connected_node_count": N + 1 - D, - "pending_node_count": P, + assert_avalancheinfo( + { + "ready_to_poll": True, + "local": { + "verified": True, + "sharing": True, + "proofid": uint256_hex(proof.proofid), + "limited_proofid": uint256_hex(proof.limited_proofid), + "master": privkey.get_pubkey().get_bytes().hex(), + "stake_amount": coinbase_amount, + "payout_address": ADDRESS_ECREG_UNSPENDABLE, + }, + "network": { + "proof_count": N + 2, + "connected_proof_count": N + 1 - D, + "dangling_proof_count": D + 1, + "finalized_proof_count": 0, + "conflicting_proof_count": N, + "immature_proof_count": 0, + "total_stake_amount": coinbase_amount * (N + 2), + "connected_stake_amount": coinbase_amount * (N + 1 - D), + "dangling_stake_amount": coinbase_amount * (D + 1), + "immature_stake_amount": Decimal("0.00"), + "node_count": N + 1 - D + P, + "connected_node_count": N + 1 - D, + "pending_node_count": P, + }, } - }) + ) self.log.info("Finalize the proofs for some peers") @@ -479,54 +506,69 @@ # Check if all proofs are finalized or invalidated return all( - [node.getrawavalancheproof(uint256_hex(p.proofid)).get("finalized", False) for p in proofs] + - [try_rpc(-8, "Proof not found", node.getrawavalancheproof, - uint256_hex(c.proofid)) for c in conflicting_proofs] + [ + node.getrawavalancheproof(uint256_hex(p.proofid)).get( + "finalized", False + ) + for p in proofs + ] + + [ + try_rpc( + -8, + "Proof not found", + node.getrawavalancheproof, + uint256_hex(c.proofid), + ) + for c in conflicting_proofs + ] ) # Vote until all the proofs have finalized (including ours) expected_logs = [] for p in proofs: - expected_logs.append( - f"Avalanche finalized proof {uint256_hex(p.proofid)}") + expected_logs.append(f"Avalanche finalized proof {uint256_hex(p.proofid)}") with node.assert_debug_log(expected_logs): self.wait_until(lambda: vote_for_all_proofs()) self.log.info( - "Disconnect all the nodes, so we are the only node left on the network") + "Disconnect all the nodes, so we are the only node left on the network" + ) node.disconnect_p2ps() - assert_avalancheinfo({ - "ready_to_poll": False, - "local": { - "verified": True, - "sharing": True, - "proofid": uint256_hex(proof.proofid), - "limited_proofid": uint256_hex(proof.limited_proofid), - "master": privkey.get_pubkey().get_bytes().hex(), - "stake_amount": coinbase_amount, - "payout_address": ADDRESS_ECREG_UNSPENDABLE, - }, - "network": { - "proof_count": N + 2, - "connected_proof_count": 1, - "dangling_proof_count": N + 1, - "finalized_proof_count": N + 2, - "conflicting_proof_count": 0, - "immature_proof_count": 0, - "total_stake_amount": coinbase_amount * (N + 2), - "connected_stake_amount": coinbase_amount, - "dangling_stake_amount": coinbase_amount * (N + 1), - "immature_stake_amount": Decimal('0.00'), - "node_count": 1, - "connected_node_count": 1, - "pending_node_count": 0, + assert_avalancheinfo( + { + "ready_to_poll": False, + "local": { + "verified": True, + "sharing": True, + "proofid": uint256_hex(proof.proofid), + "limited_proofid": uint256_hex(proof.limited_proofid), + "master": privkey.get_pubkey().get_bytes().hex(), + "stake_amount": coinbase_amount, + "payout_address": ADDRESS_ECREG_UNSPENDABLE, + }, + "network": { + "proof_count": N + 2, + "connected_proof_count": 1, + "dangling_proof_count": N + 1, + "finalized_proof_count": N + 2, + "conflicting_proof_count": 0, + "immature_proof_count": 0, + "total_stake_amount": coinbase_amount * (N + 2), + "connected_stake_amount": coinbase_amount, + "dangling_stake_amount": coinbase_amount * (N + 1), + "immature_stake_amount": Decimal("0.00"), + "node_count": 1, + "connected_node_count": 1, + "pending_node_count": 0, + }, } - }) + ) self.log.info( - "Expire the local proof and check the verification status is now invalid") + "Expire the local proof and check the verification status is now invalid" + ) node.setmocktime(proof.expiration + 1) # Expiry is based on MTP, so we have to generate 6 blocks @@ -543,10 +585,13 @@ # mocked time jump. def local_status_invalid(): local_info = node.getavalancheinfo()["local"] - return local_info["verified"] is False and local_info["verification_status"] == "invalid-proof" + return ( + local_info["verified"] is False + and local_info["verification_status"] == "invalid-proof" + ) self.wait_until(local_status_invalid) -if __name__ == '__main__': +if __name__ == "__main__": GetAvalancheInfoTest().main() diff --git a/test/functional/abc_rpc_getavalanchepeerinfo.py b/test/functional/abc_rpc_getavalanchepeerinfo.py --- a/test/functional/abc_rpc_getavalanchepeerinfo.py +++ b/test/functional/abc_rpc_getavalanchepeerinfo.py @@ -52,10 +52,13 @@ def on_avapoll(self, message): self.send_avaresponse( - message.poll.round, [ - AvalancheVote( - AvalancheVoteError.ACCEPTED, inv.hash) for inv in message.poll.invs], - self.master_privkey if self.delegation is None else self.delegated_privkey) + message.poll.round, + [ + AvalancheVote(AvalancheVoteError.ACCEPTED, inv.hash) + for inv in message.poll.invs + ], + self.master_privkey if self.delegation is None else self.delegated_privkey, + ) super().on_avapoll(message) @@ -63,21 +66,25 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - self.extra_args = [['-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=1', - '-avacooldown=0']] + self.extra_args = [ + [ + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=1", + "-avacooldown=0", + ] + ] def test_proofs_and_nodecounts(self): node = self.nodes[0] peercount = 5 nodecount = 10 - self.log.info( - f"Generating {peercount} peers with {nodecount} nodes each") + self.log.info(f"Generating {peercount} peers with {nodecount} nodes each") addrkey0 = node.get_deterministic_priv_key() blockhashes = self.generatetoaddress( - node, peercount, addrkey0.address, sync_fun=self.no_op) + node, peercount, addrkey0.address, sync_fun=self.no_op + ) # Use the first coinbase to create a stake stakes = create_coinbase_stakes(node, blockhashes, addrkey0.key) @@ -89,31 +96,32 @@ proof_sequence = 11 proof_expiration = 0 proof = node.buildavalancheproof( - proof_sequence, proof_expiration, bytes_to_wif( - privkey.get_bytes()), - [stake]) + proof_sequence, + proof_expiration, + bytes_to_wif(privkey.get_bytes()), + [stake], + ) return (pubkey.get_bytes().hex(), proof) # Create peercount * nodecount node array - nodes = [[get_ava_p2p_interface_no_handshake(node) for _ in range( - nodecount)] for _ in range(peercount)] + nodes = [ + [get_ava_p2p_interface_no_handshake(node) for _ in range(nodecount)] + for _ in range(peercount) + ] # Add peercount peers and bind all the nodes to each proofs = [] for i in range(peercount): pubkey_hex, proof = getProof(stakes[i]) proofs.append(proof) - [node.addavalanchenode(n.nodeid, pubkey_hex, proof) - for n in nodes[i]] + [node.addavalanchenode(n.nodeid, pubkey_hex, proof) for n in nodes[i]] self.log.info("Testing getavalanchepeerinfo...") avapeerinfo = node.getavalanchepeerinfo() assert_equal(len(avapeerinfo), peercount) for i, peer in enumerate(avapeerinfo): - proofid_hex = uint256_hex( - avalanche_proof_from_hex( - proofs[i]).proofid) + proofid_hex = uint256_hex(avalanche_proof_from_hex(proofs[i]).proofid) assert_equal(peer["avalanche_peerid"], i) assert_equal(peer["availability_score"], 0.0) assert_equal(peer["proofid"], proofid_hex) @@ -123,21 +131,25 @@ self.log.info("Testing with a specified proofid") - assert_raises_rpc_error(-8, "Proofid not found", - node.getavalanchepeerinfo, proofid="0" * 64) + assert_raises_rpc_error( + -8, "Proofid not found", node.getavalanchepeerinfo, proofid="0" * 64 + ) target_proof = choice(proofs) target_proofid = avalanche_proof_from_hex(target_proof).proofid - avapeerinfo = node.getavalanchepeerinfo( - proofid=uint256_hex(target_proofid)) + avapeerinfo = node.getavalanchepeerinfo(proofid=uint256_hex(target_proofid)) assert_equal(len(avapeerinfo), 1) assert_equal(avapeerinfo[0]["proof"], target_proof) def test_peer_availability_scores(self): - self.restart_node(0, extra_args=self.extra_args[0] + [ - '-avaminquorumstake=0', - '-avaminavaproofsnodecount=0', - ]) + self.restart_node( + 0, + extra_args=self.extra_args[0] + + [ + "-avaminquorumstake=0", + "-avaminavaproofsnodecount=0", + ], + ) node = self.nodes[0] # Setup node interfaces, some responsive and some not @@ -172,7 +184,8 @@ avanode, p2p_idx=p2p_idx, connection_type="avalanche", - services=NODE_NETWORK | NODE_AVALANCHE) + services=NODE_NETWORK | NODE_AVALANCHE, + ) p2p_idx += 1 assert_equal(len(avanodes), num_proof * num_avanode) @@ -183,7 +196,7 @@ return False for avapeer in avapeers: - if avapeer['nodecount'] != num_avanode: + if avapeer["nodecount"] != num_avanode: return False return True @@ -196,8 +209,11 @@ def poll_all_for_block(): with p2p_lock: - return all(avanode.poll_received > ( - 10 if avanode.is_responding else 0) for avanode in avanodes) + return all( + avanode.poll_received > (10 if avanode.is_responding else 0) + for avanode in avanodes + ) + self.wait_until(poll_all_for_block) # Move the scheduler forward so that so that our peers get availability @@ -210,8 +226,8 @@ # Get availability scores for each peer scores = {} for peerinfo in peerinfos: - p = avaproofids.index(peerinfo['proofid']) - scores[p] = peerinfo['availability_score'] + p = avaproofids.index(peerinfo["proofid"]) + scores[p] = peerinfo["availability_score"] # Wait until scores have been computed if scores[p] == 0.0: @@ -235,5 +251,5 @@ self.test_peer_availability_scores() -if __name__ == '__main__': +if __name__ == "__main__": GetAvalanchePeerInfoTest().main() diff --git a/test/functional/abc_rpc_getavalancheproofs.py b/test/functional/abc_rpc_getavalancheproofs.py --- a/test/functional/abc_rpc_getavalancheproofs.py +++ b/test/functional/abc_rpc_getavalancheproofs.py @@ -23,15 +23,17 @@ def set_test_params(self): self.num_nodes = 1 self.conflicting_proof_cooldown = 100 - self.extra_args = [[ - f'-avalancheconflictingproofcooldown={self.conflicting_proof_cooldown}', - '-avaproofstakeutxoconfirmations=2', - '-avacooldown=0', - '-avaminquorumstake=250000000', - '-avaminquorumconnectedstakeratio=0.9', - '-avaproofstakeutxodustthreshold=1000000', - '-avaminavaproofsnodecount=0', - ]] + self.extra_args = [ + [ + f"-avalancheconflictingproofcooldown={self.conflicting_proof_cooldown}", + "-avaproofstakeutxoconfirmations=2", + "-avacooldown=0", + "-avaminquorumstake=250000000", + "-avaminquorumconnectedstakeratio=0.9", + "-avaproofstakeutxodustthreshold=1000000", + "-avaminavaproofsnodecount=0", + ] + ] def run_test(self): node = self.nodes[0] @@ -51,36 +53,46 @@ self.log.info("The test node has no proof") - assert avalancheproofs_equals({ - "valid": [], - "conflicting": [], - "immature": [], - }) + assert avalancheproofs_equals( + { + "valid": [], + "conflicting": [], + "immature": [], + } + ) self.log.info("The test node has a proof") - self.restart_node(0, self.extra_args[0] + [ - f'-avaproof={proof.serialize().hex()}', - f'-avamasterkey={bytes_to_wif(privkey.get_bytes())}' - ]) + self.restart_node( + 0, + self.extra_args[0] + + [ + f"-avaproof={proof.serialize().hex()}", + f"-avamasterkey={bytes_to_wif(privkey.get_bytes())}", + ], + ) # Before local proof is validated - assert avalancheproofs_equals({ - "valid": [], - "conflicting": [], - "immature": [], - }) + assert avalancheproofs_equals( + { + "valid": [], + "conflicting": [], + "immature": [], + } + ) # Add an inbound so the node proof can be registered and advertised node.add_p2p_connection(P2PInterface()) # Mine a block to trigger proof validation self.generate(node, 1, sync_fun=self.no_op) self.wait_until( - lambda: avalancheproofs_equals({ - "valid": [uint256_hex(proof.proofid)], - "conflicting": [], - "immature": [], - }) + lambda: avalancheproofs_equals( + { + "valid": [uint256_hex(proof.proofid)], + "conflicting": [], + "immature": [], + } + ) ) self.log.info("Connect a bunch of peers and nodes") @@ -100,9 +112,11 @@ # For each proof, also make a conflicting one stakes = create_coinbase_stakes( - node, [node.getbestblockhash()], node.get_deterministic_priv_key().key) + node, [node.getbestblockhash()], node.get_deterministic_priv_key().key + ) conflicting_proof_hex = node.buildavalancheproof( - 10, 0, bytes_to_wif(_privkey.get_bytes()), stakes) + 10, 0, bytes_to_wif(_privkey.get_bytes()), stakes + ) conflicting_proof = avalanche_proof_from_hex(conflicting_proof_hex) conflicting_proofs.append(conflicting_proof) @@ -127,14 +141,16 @@ n.send_avaproof(immature_proof) self.wait_until( - lambda: avalancheproofs_equals({ - "valid": [uint256_hex(p.proofid) for p in proofs], - "conflicting": [uint256_hex(p.proofid) for p in conflicting_proofs], - "immature": [uint256_hex(immature_proof.proofid)], - }) + lambda: avalancheproofs_equals( + { + "valid": [uint256_hex(p.proofid) for p in proofs], + "conflicting": [uint256_hex(p.proofid) for p in conflicting_proofs], + "immature": [uint256_hex(immature_proof.proofid)], + } + ) ) - assert_equal(node.getavalancheinfo()['ready_to_poll'], True) + assert_equal(node.getavalancheinfo()["ready_to_poll"], True) self.log.info("Finalize the proofs for some peers") @@ -162,20 +178,34 @@ # Check if all proofs are finalized or invalidated return all( - [node.getrawavalancheproof(uint256_hex(p.proofid)).get("finalized", False) for p in proofs] + - [try_rpc(-8, "Proof not found", node.getrawavalancheproof, - uint256_hex(c.proofid)) for c in conflicting_proofs] + [ + node.getrawavalancheproof(uint256_hex(p.proofid)).get( + "finalized", False + ) + for p in proofs + ] + + [ + try_rpc( + -8, + "Proof not found", + node.getrawavalancheproof, + uint256_hex(c.proofid), + ) + for c in conflicting_proofs + ] ) # Vote until all the proofs have finalized (including ours) self.wait_until(lambda: vote_for_all_proofs()) self.wait_until( - lambda: avalancheproofs_equals({ - "valid": [uint256_hex(p.proofid) for p in proofs], - "conflicting": [], - "immature": [uint256_hex(immature_proof.proofid)], - }) + lambda: avalancheproofs_equals( + { + "valid": [uint256_hex(p.proofid) for p in proofs], + "conflicting": [], + "immature": [uint256_hex(immature_proof.proofid)], + } + ) ) # Make the immature proof mature @@ -183,13 +213,15 @@ proofs.append(immature_proof) self.wait_until( - lambda: avalancheproofs_equals({ - "valid": [uint256_hex(p.proofid) for p in proofs], - "conflicting": [], - "immature": [], - }) + lambda: avalancheproofs_equals( + { + "valid": [uint256_hex(p.proofid) for p in proofs], + "conflicting": [], + "immature": [], + } + ) ) -if __name__ == '__main__': +if __name__ == "__main__": GetAvalancheProofsTest().main() diff --git a/test/functional/abc_rpc_isfinal.py b/test/functional/abc_rpc_isfinal.py --- a/test/functional/abc_rpc_isfinal.py +++ b/test/functional/abc_rpc_isfinal.py @@ -22,11 +22,11 @@ self.num_nodes = 1 self.extra_args = [ [ - '-avaproofstakeutxodustthreshold=1000000', - '-avaproofstakeutxoconfirmations=1', - '-avacooldown=0', - '-avaminquorumstake=0', - '-avaminavaproofsnodecount=0', + "-avaproofstakeutxodustthreshold=1000000", + "-avaproofstakeutxoconfirmations=1", + "-avacooldown=0", + "-avaminquorumstake=0", + "-avaminavaproofsnodecount=0", ] ] @@ -45,24 +45,27 @@ -1, "Avalanche is not ready to poll yet.", self.nodes[0].isfinaltransaction, - node.getblock(tip)['tx'][0], + node.getblock(tip)["tx"][0], tip, ) # Build a fake quorum of nodes. def get_quorum(): - return [node.add_p2p_connection(AvaP2PInterface(self, node)) - for _ in range(0, QUORUM_NODE_COUNT)] + return [ + node.add_p2p_connection(AvaP2PInterface(self, node)) + for _ in range(0, QUORUM_NODE_COUNT) + ] # Pick one node from the quorum for polling. quorum = get_quorum() def is_quorum_established(): - return node.getavalancheinfo()['ready_to_poll'] is True + return node.getavalancheinfo()["ready_to_poll"] is True + self.wait_until(is_quorum_established) blockhash = self.generate(node, 1, sync_fun=self.no_op)[0] - cb_txid = node.getblock(blockhash)['tx'][0] + cb_txid = node.getblock(blockhash)["tx"][0] assert not node.isfinalblock(blockhash) assert not node.isfinaltransaction(cb_txid, blockhash) @@ -75,19 +78,18 @@ assert node.isfinaltransaction(cb_txid, blockhash) self.log.info("Check block ancestors are finalized as well") - tip_height = node.getblockheader(blockhash)['height'] + tip_height = node.getblockheader(blockhash)["height"] for height in range(0, tip_height): blockhash = node.getblockhash(height) assert node.isfinalblock(blockhash) - txid = node.getblock(blockhash)['tx'][0] + txid = node.getblock(blockhash)["tx"][0] assert node.isfinaltransaction(txid, blockhash) if self.is_wallet_compiled(): self.log.info("Check mempool transactions are not finalized") # Mature some utxos tip = self.generate(node, 100, sync_fun=self.no_op)[-1] - wallet_txid = node.sendtoaddress( - ADDRESS_ECREG_UNSPENDABLE, 1_000_000) + wallet_txid = node.sendtoaddress(ADDRESS_ECREG_UNSPENDABLE, 1_000_000) assert wallet_txid in node.getrawmempool() assert_raises_rpc_error( -5, @@ -98,7 +100,8 @@ ) self.log.info( - "A transaction is only finalized if the containing block is finalized") + "A transaction is only finalized if the containing block is finalized" + ) tip = self.generate(node, 1, sync_fun=self.no_op)[0] assert wallet_txid not in node.getrawmempool() assert not node.isfinaltransaction(wallet_txid, tip) @@ -108,14 +111,16 @@ # Needs -txindex assert_raises_rpc_error( -5, - "No such transaction. Use -txindex or provide a block hash to enable blockchain transaction queries.", + ( + "No such transaction. Use -txindex or provide a block hash to" + " enable blockchain transaction queries." + ), node.isfinaltransaction, wallet_txid, ) - self.log.info( - "Repeat with -txindex so we don't need the blockhash") - self.restart_node(0, self.extra_args[0] + ['-txindex']) + self.log.info("Repeat with -txindex so we don't need the blockhash") + self.restart_node(0, self.extra_args[0] + ["-txindex"]) quorum = get_quorum() self.wait_until(is_quorum_established) @@ -126,29 +131,33 @@ uint256_hex(random.randint(0, 2**256 - 1)), ) except JSONRPCException as e: - assert_equal(e.error['code'], -5) + assert_equal(e.error["code"], -5) - if e.error['message'] == "No such mempool or blockchain transaction.": + if e.error["message"] == "No such mempool or blockchain transaction.": # If we got a regular "not found" error, the txindex should # have synced. - assert node.getindexinfo()['txindex']['synced'] is True + assert node.getindexinfo()["txindex"]["synced"] is True else: # Otherwise we might have successfully raised before the # indexer completed. Checking the status now is useless as # the indexer might have completed the synchronization in # the meantime and the status is no longer relevant. - assert e.error['message'] == "No such transaction. Blockchain transactions are still in the process of being indexed." + assert ( + e.error["message"] + == "No such transaction. Blockchain transactions are still in" + " the process of being indexed." + ) else: - assert False, "The isfinaltransaction RPC call did not throw as expected." + assert ( + False + ), "The isfinaltransaction RPC call did not throw as expected." - self.wait_until(lambda: node.getindexinfo()[ - 'txindex']['synced'] is True) + self.wait_until(lambda: node.getindexinfo()["txindex"]["synced"] is True) self.wait_until(lambda: is_finalblock(tip)) assert node.isfinaltransaction(wallet_txid) - wallet_txid = node.sendtoaddress( - ADDRESS_ECREG_UNSPENDABLE, 1_000_000) + wallet_txid = node.sendtoaddress(ADDRESS_ECREG_UNSPENDABLE, 1_000_000) assert wallet_txid in node.getrawmempool() assert not node.isfinaltransaction(wallet_txid) @@ -177,7 +186,7 @@ tip = node.getbestblockhash() height = node.getblockcount() + 1 - time = node.getblock(tip)['time'] + 1 + time = node.getblock(tip)["time"] + 1 block = create_block(int(tip, 16), create_coinbase(height), time) block.solve() @@ -186,7 +195,7 @@ msg.headers = [CBlockHeader(block)] peer.send_message(msg) - self.wait_until(lambda: node.getchaintips()[0]['height'] == height) + self.wait_until(lambda: node.getchaintips()[0]["height"] == height) assert_raises_rpc_error( -1, "Block data not downloaded yet.", @@ -196,5 +205,5 @@ ) -if __name__ == '__main__': +if __name__ == "__main__": AvalancheIsFinalTest().main() diff --git a/test/functional/abc_rpc_mocktime.py b/test/functional/abc_rpc_mocktime.py --- a/test/functional/abc_rpc_mocktime.py +++ b/test/functional/abc_rpc_mocktime.py @@ -18,12 +18,16 @@ def run_test(self): self.nodes[0].setmocktime(9223372036854775807) self.nodes[0].setmocktime(0) - assert_raises_rpc_error(-8, "Mocktime can not be negative: -1.", - self.nodes[0].setmocktime, -1) assert_raises_rpc_error( - -8, "Mocktime can not be negative: -9223372036854775808.", - self.nodes[0].setmocktime, -9223372036854775808) + -8, "Mocktime can not be negative: -1.", self.nodes[0].setmocktime, -1 + ) + assert_raises_rpc_error( + -8, + "Mocktime can not be negative: -9223372036854775808.", + self.nodes[0].setmocktime, + -9223372036854775808, + ) -if __name__ == '__main__': +if __name__ == "__main__": MocktimeTest().main() diff --git a/test/functional/abc_wallet_dumpcoins.py b/test/functional/abc_wallet_dumpcoins.py --- a/test/functional/abc_wallet_dumpcoins.py +++ b/test/functional/abc_wallet_dumpcoins.py @@ -30,8 +30,7 @@ coinbases = [] def generate_and_get_txid(address, expected_coins): - blockhash = self.generatetoaddress( - node, 1, address, sync_fun=self.no_op)[0] + blockhash = self.generatetoaddress(node, 1, address, sync_fun=self.no_op)[0] assert_equal(node.dumpcoins(), expected_coins) # Get the coinbase txid @@ -43,31 +42,43 @@ generate_and_get_txid(address1, {}) # Coinbases reach maturity and start to show up. - generate_and_get_txid(address1, { - address0: [{ - "txid": coinbases[0], - "vout": 0, - "depth": 101, - "value": Decimal('50000000.00'), - }], - }) + generate_and_get_txid( + address1, + { + address0: [ + { + "txid": coinbases[0], + "vout": 0, + "depth": 101, + "value": Decimal("50000000.00"), + } + ], + }, + ) # And now on address1 - generate_and_get_txid(address1, { - address0: [{ - "txid": coinbases[0], - "vout": 0, - "depth": 102, - "value": Decimal('50000000.00'), - }], - address1: [{ - "txid": coinbases[1], - "vout": 0, - "depth": 101, - "value": Decimal('50000000.00'), - }], - }) - - -if __name__ == '__main__': + generate_and_get_txid( + address1, + { + address0: [ + { + "txid": coinbases[0], + "vout": 0, + "depth": 102, + "value": Decimal("50000000.00"), + } + ], + address1: [ + { + "txid": coinbases[1], + "vout": 0, + "depth": 101, + "value": Decimal("50000000.00"), + } + ], + }, + ) + + +if __name__ == "__main__": DumpCoinsTest().main() diff --git a/test/functional/abc_wallet_standardness.py b/test/functional/abc_wallet_standardness.py --- a/test/functional/abc_wallet_standardness.py +++ b/test/functional/abc_wallet_standardness.py @@ -23,14 +23,14 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error -SATOSHI = Decimal('0.01') +SATOSHI = Decimal("0.01") class WalletStandardnessTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 - self.extra_args = [['-acceptnonstdtxn=0'], ['-acceptnonstdtxn=1']] + self.extra_args = [["-acceptnonstdtxn=0"], ["-acceptnonstdtxn=1"]] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -43,8 +43,15 @@ # make and mature some coins for the nonstandard node self.generate(nonstd_node, 120) - def fund_and_test_wallet(scriptPubKey, is_standard, expected_in_std_wallet, - amount=10000, spendfee=500, nonstd_error="scriptpubkey", sign_error=None): + def fund_and_test_wallet( + scriptPubKey, + is_standard, + expected_in_std_wallet, + amount=10000, + spendfee=500, + nonstd_error="scriptpubkey", + sign_error=None, + ): """ Get the nonstandard node to fund a transaction, test its standardness by trying to broadcast on the standard node, @@ -58,12 +65,13 @@ tx = CTransaction() tx.vout.append(CTxOut(max(amount, 10000), scriptPubKey)) rawtx = nonstd_node.fundrawtransaction( - ToHex(tx), {'lockUnspents': True, 'changePosition': 1})['hex'] + ToHex(tx), {"lockUnspents": True, "changePosition": 1} + )["hex"] # fundrawtransaction doesn't like to fund dust outputs, so we # have to manually override the amount. FromHex(tx, rawtx) tx.vout[0].nValue = min(amount, 10000) - rawtx = nonstd_node.signrawtransactionwithwallet(ToHex(tx))['hex'] + rawtx = nonstd_node.signrawtransactionwithwallet(ToHex(tx))["hex"] # ensure signing process did not disturb scriptPubKey signedtx = FromHex(CTransaction(), rawtx) @@ -77,8 +85,9 @@ std_node.sendrawtransaction(rawtx) assert txid in std_node.getrawmempool() else: - assert_raises_rpc_error(-26, nonstd_error, - std_node.sendrawtransaction, rawtx) + assert_raises_rpc_error( + -26, nonstd_error, std_node.sendrawtransaction, rawtx + ) assert txid not in std_node.getrawmempool() # make sure it's in nonstandard node's mempool, then mine it @@ -88,8 +97,9 @@ # make sure it was mined assert txid in nonstd_node.getblock(blockhash)["tx"] - wallet_outpoints = {(entry['txid'], entry['vout']) - for entry in std_node.listunspent()} + wallet_outpoints = { + (entry["txid"], entry["vout"]) for entry in std_node.listunspent() + } # calculate wallet balance change just as a double check balance_change = std_node.getbalance() - balance_initial @@ -109,75 +119,124 @@ else: outputs = [{address_nonstd: outamount}] spendtx = std_node.createrawtransaction( - [{'txid': txid, 'vout': 0}], outputs) + [{"txid": txid, "vout": 0}], outputs + ) signresult = std_node.signrawtransactionwithwallet(spendtx) if sign_error is None: - assert_equal(signresult['complete'], True) - txid = std_node.sendrawtransaction(signresult['hex']) + assert_equal(signresult["complete"], True) + txid = std_node.sendrawtransaction(signresult["hex"]) [blockhash] = self.generate(std_node, 1) # make sure it was mined assert txid in std_node.getblock(blockhash)["tx"] else: - assert_equal(signresult['complete'], False) - assert_equal(signresult['errors'][0]['error'], sign_error) + assert_equal(signresult["complete"], False) + assert_equal(signresult["errors"][0]["error"], sign_error) # we start with an empty wallet assert_equal(std_node.getbalance(), 0) address = std_node.getnewaddress() - pubkey = bytes.fromhex(std_node.getaddressinfo(address)['pubkey']) + pubkey = bytes.fromhex(std_node.getaddressinfo(address)["pubkey"]) pubkeyhash = hash160(pubkey) # P2PK fund_and_test_wallet(CScript([pubkey, OP_CHECKSIG]), True, True) fund_and_test_wallet( - CScript([OP_PUSHDATA1, pubkey, OP_CHECKSIG]), False, False, - sign_error='Data push larger than necessary') + CScript([OP_PUSHDATA1, pubkey, OP_CHECKSIG]), + False, + False, + sign_error="Data push larger than necessary", + ) # P2PKH - fund_and_test_wallet(CScript( - [OP_DUP, OP_HASH160, pubkeyhash, OP_EQUALVERIFY, OP_CHECKSIG]), True, True) + fund_and_test_wallet( + CScript([OP_DUP, OP_HASH160, pubkeyhash, OP_EQUALVERIFY, OP_CHECKSIG]), + True, + True, + ) # The signing error changes here since the script check (with empty # scriptSig) hits OP_DUP before it hits the nonminimal push; in all # other cases we hit the nonminimal push first. - fund_and_test_wallet(CScript( - [OP_DUP, OP_HASH160, OP_PUSHDATA1, pubkeyhash, OP_EQUALVERIFY, OP_CHECKSIG]), False, False, - sign_error='Unable to sign input, invalid stack size (possibly missing key)') + fund_and_test_wallet( + CScript( + [ + OP_DUP, + OP_HASH160, + OP_PUSHDATA1, + pubkeyhash, + OP_EQUALVERIFY, + OP_CHECKSIG, + ] + ), + False, + False, + sign_error=( + "Unable to sign input, invalid stack size (possibly missing key)" + ), + ) # Bare multisig fund_and_test_wallet( - CScript([OP_1, pubkey, OP_1, OP_CHECKMULTISIG]), True, False) + CScript([OP_1, pubkey, OP_1, OP_CHECKMULTISIG]), True, False + ) fund_and_test_wallet( - CScript([OP_1, OP_PUSHDATA1, pubkey, OP_1, - OP_CHECKMULTISIG]), False, False, - sign_error='Data push larger than necessary') + CScript([OP_1, OP_PUSHDATA1, pubkey, OP_1, OP_CHECKMULTISIG]), + False, + False, + sign_error="Data push larger than necessary", + ) fund_and_test_wallet( - CScript([OP_1, pubkey, b'\x01', OP_CHECKMULTISIG]), False, False, - sign_error='Data push larger than necessary') + CScript([OP_1, pubkey, b"\x01", OP_CHECKMULTISIG]), + False, + False, + sign_error="Data push larger than necessary", + ) fund_and_test_wallet( - CScript([b'\x01', pubkey, OP_1, OP_CHECKMULTISIG]), False, False, - sign_error='Data push larger than necessary') + CScript([b"\x01", pubkey, OP_1, OP_CHECKMULTISIG]), + False, + False, + sign_error="Data push larger than necessary", + ) # Note: 1-of-5 is nonstandard to fund yet is standard to spend. However, # trying to spend it with our wallet in particular will generate # too-dense sigchecks since our wallet currently only signs with ECDSA # (Schnorr would not have this issue). fund_and_test_wallet( - CScript([OP_1, pubkey, pubkey, pubkey, pubkey, pubkey, - OP_5, OP_CHECKMULTISIG]), False, False, - sign_error='Input SigChecks limit exceeded') + CScript( + [OP_1, pubkey, pubkey, pubkey, pubkey, pubkey, OP_5, OP_CHECKMULTISIG] + ), + False, + False, + sign_error="Input SigChecks limit exceeded", + ) fund_and_test_wallet( - CScript([OP_1, pubkey, pubkey, pubkey, OP_PUSHDATA1, - pubkey, pubkey, OP_5, OP_CHECKMULTISIG]), False, False, - sign_error='Data push larger than necessary') + CScript( + [ + OP_1, + pubkey, + pubkey, + pubkey, + OP_PUSHDATA1, + pubkey, + pubkey, + OP_5, + OP_CHECKMULTISIG, + ] + ), + False, + False, + sign_error="Data push larger than necessary", + ) # Dust also is nonstandard to fund but standard to spend. fund_and_test_wallet( - CScript([pubkey, OP_CHECKSIG]), False, True, amount=200, nonstd_error="dust") + CScript([pubkey, OP_CHECKSIG]), False, True, amount=200, nonstd_error="dust" + ) # and we end with an empty wallet assert_equal(std_node.getbalance(), 0) -if __name__ == '__main__': +if __name__ == "__main__": WalletStandardnessTest().main()