async def test_basic_sync_wallet(self, wallet_node, default_400_blocks): full_node_api, wallet_node, full_node_server, wallet_server = wallet_node for block in default_400_blocks: await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(block)) await wallet_server.start_client( PeerInfo(self_hostname, uint16(full_node_server._port)), None) # The second node should eventually catch up to the first one, and have the # same tip at height num_blocks - 1. await time_out_assert(100, wallet_height_at_least, True, wallet_node, len(default_400_blocks) - 1) # Tests a reorg with the wallet num_blocks = 30 blocks_reorg = bt.get_consecutive_blocks( num_blocks, block_list_input=default_400_blocks[:-5]) for i in range(1, len(blocks_reorg)): await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(blocks_reorg[i])) await disconnect_all_and_reconnect(wallet_server, full_node_server) await time_out_assert(100, wallet_height_at_least, True, wallet_node, len(default_400_blocks) + num_blocks - 5 - 1)
async def test_mempool_update_performance(self, wallet_nodes, default_400_blocks): blocks = default_400_blocks full_nodes, wallets = wallet_nodes wallet_node = wallets[0][0] wallet_server = wallets[0][1] full_node_api_1 = full_nodes[0] full_node_api_2 = full_nodes[1] server_1 = full_node_api_1.full_node.server server_2 = full_node_api_2.full_node.server wallet = wallet_node.wallet_state_manager.main_wallet ph = await wallet.get_new_puzzlehash() for block in blocks: await full_node_api_1.full_node.respond_block(full_node_protocol.RespondBlock(block)) await wallet_server.start_client(PeerInfo(self_hostname, uint16(server_1._port)), None) await time_out_assert(60, wallet_height_at_least, True, wallet_node, 399) big_transaction: TransactionRecord = await wallet.generate_signed_transaction(40000000000000, ph, 2213) peer = await connect_and_get_peer(server_1, server_2) await full_node_api_1.respond_transaction( full_node_protocol.RespondTransaction(big_transaction.spend_bundle), peer, test=True ) cons = list(server_1.all_connections.values())[:] for con in cons: await con.close() blocks = bt.get_consecutive_blocks(3, blocks) await full_node_api_1.full_node.respond_block(full_node_protocol.RespondBlock(blocks[-3])) for block in blocks[-2:]: start_t_2 = time.time() await full_node_api_1.full_node.respond_block(full_node_protocol.RespondBlock(block)) assert time.time() - start_t_2 < 1
async def test_blocks_load(self, two_nodes): num_blocks = 50 full_node_1, full_node_2, server_1, server_2 = two_nodes blocks = bt.get_consecutive_blocks(num_blocks) peer = await connect_and_get_peer(server_1, server_2) await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(blocks[0]), peer) await server_2.start_client( PeerInfo(self_hostname, uint16(server_1._port)), None) async def num_connections(): return len(server_2.get_connections()) await time_out_assert(10, num_connections, 1) start_unf = time.time() for i in range(1, num_blocks): await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(blocks[i])) await full_node_2.full_node.respond_block( full_node_protocol.RespondBlock(blocks[i])) print( f"Time taken to process {num_blocks} is {time.time() - start_unf}") assert time.time() - start_unf < 100
async def test_basic_blockchain_tx(self, two_nodes): num_blocks = 10 wallet_a = WALLET_A coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0] receiver_puzzlehash = BURN_PUZZLE_HASH blocks = bt.get_consecutive_blocks( num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_transaction_block=True ) full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes peer = await connect_and_get_peer(server_1, server_2) full_node_1 = full_node_api_1.full_node for block in blocks: await full_node_api_1.full_node.respond_block(full_node_protocol.RespondBlock(block), None) spend_block = blocks[2] spend_coin = None for coin in list(spend_block.get_included_reward_coins()): if coin.puzzle_hash == coinbase_puzzlehash: spend_coin = coin spend_bundle = wallet_a.generate_signed_transaction(1000, receiver_puzzlehash, spend_coin) assert spend_bundle is not None tx: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(spend_bundle) await full_node_api_1.respond_transaction(tx, peer) sb = full_node_1.mempool_manager.get_spendbundle(spend_bundle.name()) assert sb is spend_bundle last_block = blocks[-1] next_spendbundle, additions, removals = await full_node_1.mempool_manager.create_bundle_from_mempool( last_block.header_hash ) assert next_spendbundle is not None new_blocks = bt.get_consecutive_blocks( 1, block_list_input=blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, transaction_data=next_spendbundle, guarantee_transaction_block=True, ) next_block = new_blocks[-1] await full_node_1.respond_block(full_node_protocol.RespondBlock(next_block)) assert next_block.header_hash == full_node_1.blockchain.get_peak().header_hash added_coins = next_spendbundle.additions() # Two coins are added, main spend and change assert len(added_coins) == 2 for coin in added_coins: unspent = await full_node_1.coin_store.get_coin_record(coin.name()) assert unspent is not None assert not unspent.spent assert not unspent.coinbase
async def test_wallet_reorg_sync(self, wallet_node_simulator, default_400_blocks, trusted): num_blocks = 5 full_nodes, wallets = wallet_node_simulator full_node_api = full_nodes[0] wallet_node, server_2 = wallets[0] fn_server = full_node_api.full_node.server wsm: WalletStateManager = wallet_node.wallet_state_manager wallet = wsm.main_wallet ph = await wallet.get_new_puzzlehash() if trusted: wallet_node.config["trusted_peers"] = { fn_server.node_id.hex(): fn_server.node_id.hex() } else: wallet_node.config["trusted_peers"] = {} await server_2.start_client( PeerInfo(self_hostname, uint16(fn_server._port)), None) # Insert 400 blocks for block in default_400_blocks: await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(block)) # Farm few more with reward for i in range(0, num_blocks): await full_node_api.farm_new_transaction_block( FarmNewBlockProtocol(ph)) # Confirm we have the funds funds = sum([ calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks) ]) await time_out_assert(5, wallet.get_confirmed_balance, funds) async def get_tx_count(wallet_id): txs = await wsm.get_all_transactions(wallet_id) return len(txs) await time_out_assert(5, get_tx_count, 2 * (num_blocks - 1), 1) # Reorg blocks that carry reward num_blocks = 30 blocks_reorg = bt.get_consecutive_blocks( num_blocks, block_list_input=default_400_blocks[:-5]) for block in blocks_reorg[-30:]: await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(block)) await time_out_assert(5, get_tx_count, 0, 1) await time_out_assert(5, wallet.get_confirmed_balance, 0)
async def test_validate_blockchain_spend_reorg_since_genesis( self, two_nodes): num_blocks = 10 wallet_a = WALLET_A coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0] receiver_1_puzzlehash = WALLET_A_PUZZLE_HASHES[1] blocks = bt.get_consecutive_blocks( num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_transaction_block=True) full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes for block in blocks: await full_node_api_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) spend_block = blocks[-1] spend_coin = None for coin in list(spend_block.get_included_reward_coins()): if coin.puzzle_hash == coinbase_puzzlehash: spend_coin = coin spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_1_puzzlehash, spend_coin) new_blocks = bt.get_consecutive_blocks( 1, blocks, seed=b"", farmer_reward_puzzle_hash=coinbase_puzzlehash, transaction_data=spend_bundle) await full_node_api_1.full_node.respond_block( full_node_protocol.RespondBlock(new_blocks[-1])) # Spends a coin in a genesis reorg, that was already spent new_blocks = bt.get_consecutive_blocks( 12, [], seed=b"reorg since genesis", farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_transaction_block=True, ) for block in new_blocks: await full_node_api_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) new_blocks = bt.get_consecutive_blocks( 1, new_blocks, seed=b"reorg since genesis", farmer_reward_puzzle_hash=coinbase_puzzlehash, transaction_data=spend_bundle, ) await full_node_api_1.full_node.respond_block( full_node_protocol.RespondBlock(new_blocks[-1]))
async def test_wallet_reorg_get_coinbase(self, wallet_node_simulator, default_400_blocks): full_nodes, wallets = wallet_node_simulator full_node_api = full_nodes[0] wallet_node, server_2 = wallets[0] fn_server = full_node_api.full_node.server wsm = wallet_node.wallet_state_manager wallet = wallet_node.wallet_state_manager.main_wallet ph = await wallet.get_new_puzzlehash() await server_2.start_client( PeerInfo(self_hostname, uint16(fn_server._port)), None) # Insert 400 blocks for block in default_400_blocks: await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(block)) # Reorg blocks that carry reward num_blocks_reorg = 30 blocks_reorg = bt.get_consecutive_blocks( num_blocks_reorg, block_list_input=default_400_blocks[:-5]) for block in blocks_reorg[:-5]: await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(block)) async def get_tx_count(wallet_id): txs = await wsm.get_all_transactions(wallet_id) return len(txs) await time_out_assert(10, get_tx_count, 0, 1) num_blocks_reorg_1 = 40 blocks_reorg_1 = bt.get_consecutive_blocks( 1, pool_reward_puzzle_hash=ph, farmer_reward_puzzle_hash=ph, block_list_input=blocks_reorg[:-30]) blocks_reorg_2 = bt.get_consecutive_blocks( num_blocks_reorg_1, block_list_input=blocks_reorg_1) for block in blocks_reorg_2[-41:]: await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(block)) await disconnect_all_and_reconnect(server_2, fn_server) # Confirm we have the funds funds = calculate_pool_reward(uint32( len(blocks_reorg_1))) + calculate_base_farmer_reward( uint32(len(blocks_reorg_1))) await time_out_assert(10, get_tx_count, 2, 1) await time_out_assert(10, wallet.get_confirmed_balance, funds)
async def test_sync_bad_peak_while_synced(self, three_nodes, default_1000_blocks, default_10000_blocks): # Must be larger than "sync_block_behind_threshold" in the config num_blocks_initial = len(default_1000_blocks) - 250 blocks_750 = default_1000_blocks[:num_blocks_initial] full_node_1, full_node_2, full_node_3 = three_nodes server_1 = full_node_1.full_node.server server_2 = full_node_2.full_node.server server_3 = full_node_3.full_node.server full_node_3.full_node.weight_proof_handler = None for block in blocks_750: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) # Node 3 syncs from a different blockchain for block in default_10000_blocks[:1100]: await full_node_3.full_node.respond_block( full_node_protocol.RespondBlock(block)) await server_2.start_client( PeerInfo(self_hostname, uint16(server_1._port)), full_node_2.full_node.on_connect) # The second node should eventually catch up to the first one, and have the # same tip at height num_blocks - 1 await time_out_assert(180, node_height_exactly, True, full_node_2, num_blocks_initial - 1) # set new heavy peak, fn3 cannot serve wp's # node 2 should keep being synced and receive blocks await server_3.start_client( PeerInfo(self_hostname, uint16(server_3._port)), full_node_3.full_node.on_connect) # trigger long sync in full node 2 peak_block = default_10000_blocks[1050] await server_2.start_client( PeerInfo(self_hostname, uint16(server_3._port)), full_node_2.full_node.on_connect) con = server_2.all_connections[full_node_3.full_node.server.node_id] peak = full_node_protocol.NewPeak( peak_block.header_hash, peak_block.height, peak_block.weight, peak_block.height, peak_block.reward_chain_block.get_unfinished().get_hash(), ) await full_node_2.full_node.new_peak(peak, con) await asyncio.sleep(2) assert not full_node_2.full_node.sync_store.get_sync_mode() for block in default_1000_blocks[1000 - num_blocks_initial:]: await full_node_2.full_node.respond_block( full_node_protocol.RespondBlock(block)) assert node_height_exactly(full_node_2, 999)
async def test_validate_blockchain_spend_reorg_cb_coin(self, two_nodes): num_blocks = 15 wallet_a = WALLET_A coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0] receiver_1_puzzlehash = WALLET_A_PUZZLE_HASHES[1] blocks = bt.get_consecutive_blocks( num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash) full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes for block in blocks: await full_node_api_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) # Spends a coinbase created in reorg new_blocks = bt.get_consecutive_blocks( 5, blocks[:6], seed=b"reorg cb coin", farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_transaction_block=True, ) for block in new_blocks: await full_node_api_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) spend_block = new_blocks[-1] spend_coin = None for coin in list(spend_block.get_included_reward_coins()): if coin.puzzle_hash == coinbase_puzzlehash: spend_coin = coin spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_1_puzzlehash, spend_coin) new_blocks = bt.get_consecutive_blocks( 1, new_blocks, seed=b"reorg cb coin", farmer_reward_puzzle_hash=coinbase_puzzlehash, transaction_data=spend_bundle, guarantee_transaction_block=True, ) await full_node_api_1.full_node.respond_block( full_node_protocol.RespondBlock(new_blocks[-1])) coins_created = [] for coin in new_blocks[-1].additions(): if coin.puzzle_hash == receiver_1_puzzlehash: coins_created.append(coin) assert len(coins_created) == 1
async def test_long_sync_wallet(self, wallet_node, default_1000_blocks, default_400_blocks, trusted): full_node_api, wallet_node, full_node_server, wallet_server = wallet_node for block in default_400_blocks: await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(block)) if trusted: wallet_node.config["trusted_peers"] = { full_node_server.node_id.hex(): full_node_server.node_id.hex() } else: wallet_node.config["trusted_peers"] = {} await wallet_server.start_client( PeerInfo(self_hostname, uint16(full_node_server._port)), None) # The second node should eventually catch up to the first one, and have the # same tip at height num_blocks - 1. await time_out_assert(600, wallet_height_at_least, True, wallet_node, len(default_400_blocks) - 1) # Tests a long reorg for block in default_1000_blocks: await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(block)) await disconnect_all_and_reconnect(wallet_server, full_node_server) log.info( f"wallet node height is {wallet_node.wallet_state_manager.blockchain.get_peak_height()}" ) await time_out_assert(600, wallet_height_at_least, True, wallet_node, len(default_1000_blocks) - 1) await disconnect_all_and_reconnect(wallet_server, full_node_server) # Tests a short reorg num_blocks = 30 blocks_reorg = bt.get_consecutive_blocks( num_blocks, block_list_input=default_1000_blocks[:-5]) for i in range(1, len(blocks_reorg)): await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(blocks_reorg[i])) await time_out_assert(600, wallet_height_at_least, True, wallet_node, len(default_1000_blocks) + num_blocks - 5 - 1)
async def test_block_ses_mismatch(self, two_nodes, default_1000_blocks): full_node_1, full_node_2, server_1, server_2 = two_nodes blocks = default_1000_blocks for block in blocks[:501]: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) peak1 = full_node_1.full_node.blockchain.get_peak() full_node_2.full_node.sync_store.set_long_sync(True) await server_2.start_client( PeerInfo(self_hostname, uint16(server_1._port)), full_node_2.full_node.on_connect) wp = await full_node_1.full_node.weight_proof_handler.get_proof_of_weight( peak1.header_hash) summaries1, _ = _validate_sub_epoch_summaries( full_node_1.full_node.weight_proof_handler.constants, wp) summaries2 = summaries1 s = summaries1[1] # change summary so check would fail on 2 sub epoch summaries2[1] = SubEpochSummary( s.prev_subepoch_summary_hash, s.reward_chain_hash, s.num_blocks_overflow, s.new_difficulty * 2, s.new_sub_slot_iters * 2, ) await full_node_2.full_node.sync_from_fork_point( 0, 500, peak1.header_hash, summaries2) log.info( f"full node height {full_node_2.full_node.blockchain.get_peak().height}" ) assert node_height_between(full_node_2, 320, 400)
async def condition_tester2(self, two_nodes, test_fun: Callable[[Coin, Coin], SpendBundle]): reward_ph = WALLET_A.get_new_puzzlehash() full_node_1, full_node_2, server_1, server_2 = two_nodes blocks = await full_node_1.get_all_full_blocks() start_height = blocks[-1].height if len(blocks) > 0 else -1 blocks = bt.get_consecutive_blocks( 3, block_list_input=blocks, guarantee_transaction_block=True, farmer_reward_puzzle_hash=reward_ph, pool_reward_puzzle_hash=reward_ph, ) peer = await connect_and_get_peer(server_1, server_2) for block in blocks: await full_node_1.full_node.respond_block(full_node_protocol.RespondBlock(block)) await time_out_assert(60, node_height_at_least, True, full_node_1, start_height + 3) coin_1 = list(blocks[-2].get_included_reward_coins())[0] coin_2 = list(blocks[-1].get_included_reward_coins())[0] bundle = test_fun(coin_1, coin_2) tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(bundle) status, err = await respond_transaction(full_node_1, tx1, peer) return blocks, bundle, status, err
async def test_agg_sig_condition(self, two_nodes): reward_ph = WALLET_A.get_new_puzzlehash() full_node_1, full_node_2, server_1, server_2 = two_nodes blocks = await full_node_1.get_all_full_blocks() start_height = blocks[-1].height blocks = bt.get_consecutive_blocks( 3, block_list_input=blocks, guarantee_transaction_block=True, farmer_reward_puzzle_hash=reward_ph, pool_reward_puzzle_hash=reward_ph, ) for block in blocks: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) await time_out_assert(60, node_height_at_least, True, full_node_1, start_height + 3) # this code has been changed to use generate_test_spend_bundle # not quite sure why all the gymnastics are being performed coin = list(blocks[-1].get_included_reward_coins())[0] spend_bundle_0 = generate_test_spend_bundle(coin) unsigned: List[CoinSolution] = spend_bundle_0.coin_solutions assert len(unsigned) == 1 coin_solution: CoinSolution = unsigned[0] err, con, cost = conditions_for_solution(coin_solution.puzzle_reveal, coin_solution.solution) assert con is not None
async def test_basic_mempool(self, two_nodes): reward_ph = WALLET_A.get_new_puzzlehash() blocks = bt.get_consecutive_blocks( 3, guarantee_transaction_block=True, farmer_reward_puzzle_hash=reward_ph, pool_reward_puzzle_hash=reward_ph, ) full_node_1, full_node_2, server_1, server_2 = two_nodes peer = await connect_and_get_peer(server_1, server_2) for block in blocks: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) await time_out_assert(60, node_height_at_least, True, full_node_2, 2) spend_bundle = generate_test_spend_bundle( list(blocks[-1].get_included_reward_coins())[0]) assert spend_bundle is not None tx: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle) await full_node_1.respond_transaction(tx, peer) await time_out_assert( 10, full_node_1.full_node.mempool_manager.get_spendbundle, spend_bundle, spend_bundle.name(), )
async def test_invalid_block_age(self, two_nodes): reward_ph = WALLET_A.get_new_puzzlehash() blocks = bt.get_consecutive_blocks( 3, guarantee_transaction_block=True, farmer_reward_puzzle_hash=reward_ph, pool_reward_puzzle_hash=reward_ph, ) full_node_1, full_node_2, server_1, server_2 = two_nodes peer = await connect_and_get_peer(server_1, server_2) for block in blocks: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) await time_out_assert(60, node_height_at_least, True, full_node_1, 2) cvp = ConditionVarPair(ConditionOpcode.ASSERT_HEIGHT_AGE_EXCEEDS, [uint64(5).to_bytes(4, "big")]) dic = {cvp.opcode: [cvp]} spend_bundle1 = generate_test_spend_bundle( list(blocks[-1].get_included_reward_coins())[0], dic) assert spend_bundle1 is not None tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle1) await full_node_1.respond_transaction(tx1, peer) sb1 = full_node_1.full_node.mempool_manager.get_spendbundle( spend_bundle1.name()) assert sb1 is None
async def test_assert_seconds_absolute(self, two_nodes): num_blocks = 10 wallet_a = WALLET_A coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0] receiver_puzzlehash = BURN_PUZZLE_HASH # Farm blocks blocks = bt.get_consecutive_blocks( num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_transaction_block=True ) full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes full_node_1 = full_node_api_1.full_node for block in blocks: await full_node_api_1.full_node.respond_block(full_node_protocol.RespondBlock(block)) # Coinbase that gets spent block1 = blocks[2] spend_coin_block_1 = None for coin in list(block1.get_included_reward_coins()): if coin.puzzle_hash == coinbase_puzzlehash: spend_coin_block_1 = coin # This condition requires block1 coinbase to be spent after 30 seconds from now current_time_plus3 = uint64(blocks[-1].foliage_transaction_block.timestamp + 30) block1_cvp = ConditionWithArgs(ConditionOpcode.ASSERT_SECONDS_ABSOLUTE, [int_to_bytes(current_time_plus3)]) block1_dic = {block1_cvp.opcode: [block1_cvp]} block1_spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spend_coin_block_1, block1_dic ) # program that will be sent to early assert block1_spend_bundle is not None invalid_new_blocks = bt.get_consecutive_blocks( 1, blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, transaction_data=block1_spend_bundle, time_per_block=20, guarantee_transaction_block=True, ) # Try to validate that block before 30 sec res, err, _ = await full_node_1.blockchain.receive_block(invalid_new_blocks[-1]) assert res == ReceiveBlockResult.INVALID_BLOCK assert err == Err.ASSERT_SECONDS_ABSOLUTE_FAILED valid_new_blocks = bt.get_consecutive_blocks( 1, blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, transaction_data=block1_spend_bundle, guarantee_transaction_block=True, time_per_block=31, ) res, err, _ = await full_node_1.blockchain.receive_block(valid_new_blocks[-1]) assert err is None assert res == ReceiveBlockResult.NEW_PEAK
async def test_assert_fee_condition(self, two_nodes): num_blocks = 10 wallet_a = WALLET_A coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0] receiver_puzzlehash = BURN_PUZZLE_HASH # Farm blocks blocks = bt.get_consecutive_blocks( num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_transaction_block=True ) full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes full_node_1 = full_node_api_1.full_node for block in blocks: await full_node_api_1.full_node.respond_block(full_node_protocol.RespondBlock(block)) # Coinbase that gets spent block1 = blocks[2] spend_coin_block_1 = None for coin in list(block1.get_included_reward_coins()): if coin.puzzle_hash == coinbase_puzzlehash: spend_coin_block_1 = coin # This condition requires fee to be 10 mojo cvp_fee = ConditionWithArgs(ConditionOpcode.RESERVE_FEE, [int_to_bytes(10)]) # This spend bundle has 9 mojo as fee block1_dic_bad = {cvp_fee.opcode: [cvp_fee]} block1_dic_good = {cvp_fee.opcode: [cvp_fee]} block1_spend_bundle_bad = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spend_coin_block_1, block1_dic_bad, fee=9 ) block1_spend_bundle_good = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spend_coin_block_1, block1_dic_good, fee=10 ) log.warning(block1_spend_bundle_good.additions()) log.warning(f"Spend bundle fees: {block1_spend_bundle_good.fees()}") invalid_new_blocks = bt.get_consecutive_blocks( 1, blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, transaction_data=block1_spend_bundle_bad, guarantee_transaction_block=True, ) res, err, _ = await full_node_1.blockchain.receive_block(invalid_new_blocks[-1]) assert res == ReceiveBlockResult.INVALID_BLOCK assert err == Err.RESERVE_FEE_CONDITION_FAILED valid_new_blocks = bt.get_consecutive_blocks( 1, blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, transaction_data=block1_spend_bundle_good, guarantee_transaction_block=True, ) res, err, _ = await full_node_1.blockchain.receive_block(valid_new_blocks[-1]) assert err is None assert res == ReceiveBlockResult.NEW_PEAK
async def test_stealing_fee(self, two_nodes): reward_ph = WALLET_A.get_new_puzzlehash() full_node_1, full_node_2, server_1, server_2 = two_nodes blocks = await full_node_1.get_all_full_blocks() start_height = blocks[-1].height blocks = bt.get_consecutive_blocks( 5, block_list_input=blocks, guarantee_transaction_block=True, farmer_reward_puzzle_hash=reward_ph, pool_reward_puzzle_hash=reward_ph, ) full_node_1, full_node_2, server_1, server_2 = two_nodes peer = await connect_and_get_peer(server_1, server_2) for block in blocks: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) await time_out_assert(60, node_height_at_least, True, full_node_1, start_height + 5) receiver_puzzlehash = BURN_PUZZLE_HASH cvp = ConditionWithArgs(ConditionOpcode.RESERVE_FEE, [int_to_bytes(10)]) dic = {cvp.opcode: [cvp]} fee = 9 coin_1 = list(blocks[-2].get_included_reward_coins())[0] coin_2 = None for coin in list(blocks[-1].get_included_reward_coins()): if coin.amount == coin_1.amount: coin_2 = coin spend_bundle1 = generate_test_spend_bundle(coin_1, dic, uint64(fee)) steal_fee_spendbundle = WALLET_A.generate_signed_transaction( coin_1.amount + fee - 4, receiver_puzzlehash, coin_2) assert spend_bundle1 is not None assert steal_fee_spendbundle is not None combined = SpendBundle.aggregate( [spend_bundle1, steal_fee_spendbundle]) assert combined.fees() == 4 tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle1) await full_node_1.respond_transaction(tx1, peer) mempool_bundle = full_node_1.full_node.mempool_manager.get_spendbundle( spend_bundle1.name()) assert mempool_bundle is None
async def test_almost_recent(self, wallet_node, default_1000_blocks, trusted): # Tests the edge case of receiving funds right before the recent blocks in weight proof full_node_api, wallet_node, full_node_server, wallet_server = wallet_node for block in default_1000_blocks: await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(block)) wallet = wallet_node.wallet_state_manager.main_wallet ph = await wallet.get_new_puzzlehash() if trusted: wallet_node.config["trusted_peers"] = { full_node_server.node_id.hex(): full_node_server.node_id.hex() } else: wallet_node.config["trusted_peers"] = {} # Tests a reorg with the wallet num_blocks = 20 new_blocks = bt.get_consecutive_blocks( num_blocks, block_list_input=default_1000_blocks, pool_reward_puzzle_hash=ph) for i in range(1000, len(new_blocks)): await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(new_blocks[i])) new_blocks = bt.get_consecutive_blocks( test_constants.WEIGHT_PROOF_RECENT_BLOCKS + 10, block_list_input=new_blocks) for i in range(1020, len(new_blocks)): await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(new_blocks[i])) await wallet_server.start_client( PeerInfo(self_hostname, uint16(full_node_server._port)), None) await time_out_assert(30, wallet.get_confirmed_balance, 20 * calculate_pool_reward(1000))
async def test_close_height_but_big_reorg(self, three_nodes): blocks_a = bt.get_consecutive_blocks(50) blocks_b = bt.get_consecutive_blocks(51, seed=b"B") blocks_c = bt.get_consecutive_blocks(90, seed=b"C") full_node_1, full_node_2, full_node_3 = three_nodes server_1 = full_node_1.full_node.server server_2 = full_node_2.full_node.server server_3 = full_node_3.full_node.server for block in blocks_a: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) for block in blocks_b: await full_node_2.full_node.respond_block( full_node_protocol.RespondBlock(block)) for block in blocks_c: await full_node_3.full_node.respond_block( full_node_protocol.RespondBlock(block)) await server_2.start_client( PeerInfo(self_hostname, uint16(server_1._port)), on_connect=full_node_2.full_node.on_connect, ) await time_out_assert(60, node_height_exactly, True, full_node_1, 50) await time_out_assert(60, node_height_exactly, True, full_node_2, 50) await time_out_assert(60, node_height_exactly, True, full_node_3, 89) await server_3.start_client( PeerInfo(self_hostname, uint16(server_1._port)), on_connect=full_node_3.full_node.on_connect, ) await server_3.start_client( PeerInfo(self_hostname, uint16(server_2._port)), on_connect=full_node_3.full_node.on_connect, ) await time_out_assert(60, node_height_exactly, True, full_node_1, 89) await time_out_assert(60, node_height_exactly, True, full_node_2, 89) await time_out_assert(60, node_height_exactly, True, full_node_3, 89)
async def test_invalid_announcement_consumed_two(self, two_nodes): reward_ph = WALLET_A.get_new_puzzlehash() full_node_1, full_node_2, server_1, server_2 = two_nodes blocks = await full_node_1.get_all_full_blocks() start_height = blocks[-1].height if len(blocks) > 0 else -1 blocks = bt.get_consecutive_blocks( 3, block_list_input=blocks, guarantee_transaction_block=True, farmer_reward_puzzle_hash=reward_ph, pool_reward_puzzle_hash=reward_ph, ) peer = await connect_and_get_peer(server_1, server_2) for block in blocks: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) await time_out_assert(60, node_height_at_least, True, full_node_1, start_height + 3) coin_1 = list(blocks[-2].get_included_reward_coins())[0] coin_2 = list(blocks[-1].get_included_reward_coins())[0] announce = Announcement(coin_1.name(), bytes("test", "utf-8")) cvp = ConditionVarPair(ConditionOpcode.ASSERT_ANNOUNCEMENT, [announce.name()]) dic = {cvp.opcode: [cvp]} cvp2 = ConditionVarPair( ConditionOpcode.CREATE_ANNOUNCEMENT, [bytes("test", "utf-8")], ) dic2 = {cvp.opcode: [cvp2]} spend_bundle1 = generate_test_spend_bundle(coin_1, dic) spend_bundle2 = generate_test_spend_bundle(coin_2, dic2) bundle = SpendBundle.aggregate([spend_bundle1, spend_bundle2]) tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle1) await full_node_1.respond_transaction(tx1, peer) mempool_bundle = full_node_1.full_node.mempool_manager.get_spendbundle( bundle.name()) assert mempool_bundle is None
async def test_batch_sync(self, two_nodes): # Must be below "sync_block_behind_threshold" in the config num_blocks = 20 num_blocks_2 = 9 blocks = bt.get_consecutive_blocks(num_blocks) blocks_2 = bt.get_consecutive_blocks(num_blocks_2, seed=b"123") full_node_1, full_node_2, server_1, server_2 = two_nodes # 12 blocks to node_1 for block in blocks: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) # 9 different blocks to node_2 for block in blocks_2: await full_node_2.full_node.respond_block( full_node_protocol.RespondBlock(block)) await server_2.start_client( PeerInfo(self_hostname, uint16(server_1._port)), on_connect=full_node_2.full_node.on_connect, ) await time_out_assert(60, node_height_exactly, True, full_node_2, num_blocks - 1)
async def test_backtrack_sync_wallet(self, wallet_node, default_400_blocks): full_node_api, wallet_node, full_node_server, wallet_server = wallet_node for block in default_400_blocks[:20]: await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(block)) await wallet_server.start_client( PeerInfo(self_hostname, uint16(full_node_server._port)), None) # The second node should eventually catch up to the first one, and have the # same tip at height num_blocks - 1. await time_out_assert(100, wallet_height_at_least, True, wallet_node, 19)
async def test_backtrack_sync_2(self, two_nodes): blocks = bt.get_consecutive_blocks(1, skip_slots=3) blocks = bt.get_consecutive_blocks(8, blocks, skip_slots=0) full_node_1, full_node_2, server_1, server_2 = two_nodes # 3 blocks to node_1 in different sub slots for block in blocks: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) await server_2.start_client( PeerInfo(self_hostname, uint16(server_1._port)), on_connect=full_node_2.full_node.on_connect, ) await time_out_assert(60, node_height_exactly, True, full_node_2, 8)
async def test_assert_time_exceeds_both_cases(self, two_nodes): reward_ph = WALLET_A.get_new_puzzlehash() full_node_1, full_node_2, server_1, server_2 = two_nodes blocks = await full_node_1.get_all_full_blocks() start_height = blocks[-1].height if len(blocks) > 0 else -1 blocks = bt.get_consecutive_blocks( 3, block_list_input=blocks, guarantee_transaction_block=True, farmer_reward_puzzle_hash=reward_ph, pool_reward_puzzle_hash=reward_ph, ) peer = await connect_and_get_peer(server_1, server_2) for block in blocks: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) await time_out_assert(60, node_height_at_least, True, full_node_1, start_height + 3) time_now = uint64(int(time() * 1000)) time_now_plus_3 = time_now + 3000 cvp = ConditionVarPair(ConditionOpcode.ASSERT_SECONDS_NOW_EXCEEDS, [time_now_plus_3.to_bytes(8, "big")]) dic = {cvp.opcode: [cvp]} spend_bundle1 = generate_test_spend_bundle( list(blocks[-1].get_included_reward_coins())[0], dic) assert spend_bundle1 is not None tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle1) await full_node_1.respond_transaction(tx1, peer) # Sleep so that 3 sec passes await asyncio.sleep(3) tx2: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle1) await full_node_1.respond_transaction(tx2, peer) sb1 = full_node_1.full_node.mempool_manager.get_spendbundle( spend_bundle1.name()) assert sb1 is spend_bundle1
async def test_double_spend_with_higher_fee(self, two_nodes): reward_ph = WALLET_A.get_new_puzzlehash() full_node_1, full_node_2, server_1, server_2 = two_nodes blocks = await full_node_1.get_all_full_blocks() start_height = blocks[-1].height blocks = bt.get_consecutive_blocks( 3, block_list_input=blocks, guarantee_transaction_block=True, farmer_reward_puzzle_hash=reward_ph, pool_reward_puzzle_hash=reward_ph, ) peer = await connect_and_get_peer(server_1, server_2) for block in blocks: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) await time_out_assert(60, node_height_at_least, True, full_node_1, start_height + 3) spend_bundle1 = generate_test_spend_bundle( list(blocks[-1].get_included_reward_coins())[0]) assert spend_bundle1 is not None tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle1) await full_node_1.respond_transaction(tx1, peer) spend_bundle2 = generate_test_spend_bundle(list( blocks[-1].get_included_reward_coins())[0], fee=uint64(1)) assert spend_bundle2 is not None tx2: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle2) await full_node_1.respond_transaction(tx2, peer) sb1 = full_node_1.full_node.mempool_manager.get_spendbundle( spend_bundle1.name()) sb2 = full_node_1.full_node.mempool_manager.get_spendbundle( spend_bundle2.name()) assert sb1 is None assert sb2 == spend_bundle2
async def test_validate_blockchain_duplicate_output(self, two_nodes): num_blocks = 3 wallet_a = WALLET_A coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0] receiver_puzzlehash = BURN_PUZZLE_HASH blocks = bt.get_consecutive_blocks( num_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_transaction_block=True) full_node_api_1, full_node_api_2, server_1, server_2 = two_nodes full_node_1 = full_node_api_1.full_node for block in blocks: await full_node_api_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) spend_block = blocks[2] spend_coin = None for coin in list(spend_block.get_included_reward_coins()): if coin.puzzle_hash == coinbase_puzzlehash: spend_coin = coin spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spend_coin) spend_bundle_double = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spend_coin) block_spendbundle = SpendBundle.aggregate( [spend_bundle, spend_bundle_double]) new_blocks = bt.get_consecutive_blocks( 1, block_list_input=blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, transaction_data=block_spendbundle, guarantee_transaction_block=True, ) next_block = new_blocks[-1] res, err, _ = await full_node_1.blockchain.receive_block(next_block) assert res == ReceiveBlockResult.INVALID_BLOCK assert err == Err.DUPLICATE_OUTPUT
async def test_double_spend_same_bundle(self, two_nodes): reward_ph = WALLET_A.get_new_puzzlehash() full_node_1, full_node_2, server_1, server_2 = two_nodes blocks = await full_node_1.get_all_full_blocks() start_height = blocks[-1].height blocks = bt.get_consecutive_blocks( 3, block_list_input=blocks, guarantee_transaction_block=True, farmer_reward_puzzle_hash=reward_ph, pool_reward_puzzle_hash=reward_ph, ) peer = await connect_and_get_peer(server_1, server_2) for block in blocks: await full_node_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) await time_out_assert(60, node_height_at_least, True, full_node_1, start_height + 3) coin = list(blocks[-1].get_included_reward_coins())[0] spend_bundle1 = generate_test_spend_bundle(coin) assert spend_bundle1 is not None spend_bundle2 = generate_test_spend_bundle( coin, new_puzzle_hash=BURN_PUZZLE_HASH_2, ) assert spend_bundle2 is not None spend_bundle_combined = SpendBundle.aggregate( [spend_bundle1, spend_bundle2]) tx: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle_combined) await full_node_1.respond_transaction(tx, peer) sb = full_node_1.full_node.mempool_manager.get_spendbundle( spend_bundle_combined.name()) assert sb is None
async def test_double_spend(self, two_nodes): reward_ph = WALLET_A.get_new_puzzlehash() full_node_1, full_node_2, server_1, server_2 = two_nodes blocks = await full_node_1.get_all_full_blocks() start_height = blocks[-1].height blocks = bt.get_consecutive_blocks( 3, block_list_input=blocks, guarantee_transaction_block=True, farmer_reward_puzzle_hash=reward_ph, pool_reward_puzzle_hash=reward_ph, ) peer = await connect_and_get_peer(server_1, server_2) for block in blocks: await full_node_1.full_node.respond_block(full_node_protocol.RespondBlock(block)) await time_out_assert(60, node_height_at_least, True, full_node_1, start_height + 3) spend_bundle1 = generate_test_spend_bundle(list(blocks[-1].get_included_reward_coins())[0]) assert spend_bundle1 is not None tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(spend_bundle1) status, err = await respond_transaction(full_node_1, tx1, peer) assert status == MempoolInclusionStatus.SUCCESS assert err is None spend_bundle2 = generate_test_spend_bundle( list(blocks[-1].get_included_reward_coins())[0], new_puzzle_hash=BURN_PUZZLE_HASH_2, ) assert spend_bundle2 is not None tx2: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(spend_bundle2) status, err = await respond_transaction(full_node_1, tx2, peer) sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name()) sb2 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle2.name()) assert sb1 == spend_bundle1 assert sb2 is None assert status == MempoolInclusionStatus.PENDING assert err == Err.MEMPOOL_CONFLICT
async def test_short_batch_sync_wallet(self, wallet_node, default_400_blocks, trusted): full_node_api, wallet_node, full_node_server, wallet_server = wallet_node for block in default_400_blocks[:200]: await full_node_api.full_node.respond_block( full_node_protocol.RespondBlock(block)) if trusted: wallet_node.config["trusted_peers"] = { full_node_server.node_id.hex(): full_node_server.node_id.hex() } else: wallet_node.config["trusted_peers"] = {} await wallet_server.start_client( PeerInfo(self_hostname, uint16(full_node_server._port)), None) # The second node should eventually catch up to the first one, and have the # same tip at height num_blocks - 1. await time_out_assert(100, wallet_height_at_least, True, wallet_node, 199)