async def test_validate_blockchain_spend_reorg_cb_coin(self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() receiver_1_puzzlehash = wallet_a.get_new_puzzlehash() blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass # Spends a coinbase created in reorg new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks[:6], 10, b"reorg cb coin", coinbase_puzzlehash) [ _ async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(new_blocks[-1])) ] assert new_blocks[-1].header_hash in full_node_1.blockchain.headers spent_block = new_blocks[-1] spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_1_puzzlehash, spent_block.get_coinbase()) spend_bundle_2 = wallet_a.generate_signed_transaction( 1000, receiver_1_puzzlehash, spent_block.get_fees_coin()) block_spendbundle = SpendBundle.aggregate( [spend_bundle, spend_bundle_2]) program = best_solution_program(block_spendbundle) aggsig = block_spendbundle.aggregated_signature dic_h = {7: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 1, new_blocks, 10, b"reorg cb coin", coinbase_puzzlehash, dic_h, ) error = await full_node_1.blockchain._validate_transactions( new_blocks[-1], new_blocks[-1].get_fees_coin().amount) assert error is None [ _ async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(new_blocks[-1])) ] assert new_blocks[-1].header_hash in full_node_1.blockchain.headers coins_created = [] for coin in new_blocks[-1].additions(): if coin.puzzle_hash == receiver_1_puzzlehash: coins_created.append(coin) assert len(coins_created) == 2
async def test_validate_blockchain_spend_reorg_since_genesis(self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() receiver_1_puzzlehash = wallet_a.get_new_puzzlehash() blocks = bt.get_consecutive_blocks( test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash ) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block) ): pass spent_block = blocks[1] spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_1_puzzlehash, spent_block.get_coinbase() ) block_spendbundle = SpendBundle.aggregate([spend_bundle]) program = best_solution_program(block_spendbundle) aggsig = block_spendbundle.aggregated_signature dic_h = {11: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h ) [ _ async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(new_blocks[-1]) ) ] # Spends a coin in a genesis reorg, that was already spent dic_h = {5: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 12, [], 10, b"reorg since genesis", coinbase_puzzlehash, dic_h, ) for block in new_blocks: [ _ async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block) ) ] assert new_blocks[-1].header_hash in full_node_1.blockchain.headers
async def test_validate_blockchain_with_double_spend(self, two_nodes): num_blocks = 5 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() wallet_receiver = WalletTool() receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() blocks = bt.get_consecutive_blocks( test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash ) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block) ): pass spent_block = blocks[1] spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spent_block.get_coinbase() ) spend_bundle_double = wallet_a.generate_signed_transaction( 1001, receiver_puzzlehash, spent_block.get_coinbase() ) block_spendbundle = SpendBundle.aggregate([spend_bundle, spend_bundle_double]) program = best_solution_program(block_spendbundle) aggsig = block_spendbundle.aggregated_signature dic_h = {(num_blocks + 1): (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h ) next_block = new_blocks[num_blocks + 1] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount ) assert error is Err.DOUBLE_SPEND
async def test_validate_blockchain_spend_reorg_cb_coin_freeze( self, two_nodes_standard_freeze ): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() receiver_1_puzzlehash = wallet_a.get_new_puzzlehash() blocks = bt.get_consecutive_blocks( test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash ) full_node_1, full_node_2, server_1, server_2 = two_nodes_standard_freeze for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block) ): pass # Spends a coinbase created in reorg new_blocks = bt.get_consecutive_blocks( test_constants, 1, blocks[:6], 10, b"reorg cb coin", coinbase_puzzlehash ) [ _ async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(new_blocks[-1]) ) ] assert new_blocks[-1].header_hash in full_node_1.blockchain.headers spent_block = new_blocks[-1] spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_1_puzzlehash, spent_block.get_coinbase() ) block_spendbundle = SpendBundle.aggregate([spend_bundle]) program = best_solution_program(block_spendbundle) aggsig = block_spendbundle.aggregated_signature dic_h = {7: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 1, new_blocks, 10, b"reorg cb coin", coinbase_puzzlehash, dic_h, ) error = await full_node_1.blockchain._validate_transactions( new_blocks[-1], new_blocks[-1].get_coinbase().amount ) assert error is Err.COINBASE_NOT_YET_SPENDABLE
async def test_invalid_filter(self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() wallet_receiver = WalletTool() receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass spent_block = blocks[1] spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spent_block.get_coinbase()) assert spend_bundle is not None tx: full_node_protocol.RespondTransaction = ( full_node_protocol.RespondTransaction(spend_bundle)) async for _ in full_node_1.respond_transaction(tx): outbound: OutboundMessage = _ # Maybe transaction means that it's accepted in mempool assert outbound.message.function == "new_transaction" sb = full_node_1.mempool_manager.get_spendbundle(spend_bundle.name()) assert sb is spend_bundle last_block = blocks[10] next_spendbundle = await full_node_1.mempool_manager.create_bundle_for_tip( last_block.header) assert next_spendbundle is not None program = best_solution_program(next_spendbundle) aggsig = next_spendbundle.aggregated_signature dic_h = {11: (program, aggsig)} new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h) next_block = new_blocks[11] bad_header = HeaderData( next_block.header.data.height, next_block.header.data.prev_header_hash, next_block.header.data.timestamp, bytes32(bytes([3] * 32)), next_block.header.data.proof_of_space_hash, next_block.header.data.weight, next_block.header.data.total_iters, next_block.header.data.additions_root, next_block.header.data.removals_root, next_block.header.data.farmer_rewards_puzzle_hash, next_block.header.data.total_transaction_fees, next_block.header.data.pool_target, next_block.header.data.aggregated_signature, next_block.header.data.cost, next_block.header.data.extension_data, next_block.header.data.generator_hash, ) bad_block = FullBlock( next_block.proof_of_space, next_block.proof_of_time, Header( bad_header, bt.get_plot_signature( bad_header, next_block.proof_of_space.plot_public_key), ), next_block.transactions_generator, next_block.transactions_filter, ) result, removed, error_code = await full_node_1.blockchain.receive_block( bad_block) assert result == ReceiveBlockResult.INVALID_BLOCK assert error_code == Err.INVALID_TRANSACTIONS_FILTER_HASH result, removed, error_code = await full_node_1.blockchain.receive_block( next_block) assert result == ReceiveBlockResult.ADDED_TO_HEAD
async def test_assert_time_exceeds(self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() wallet_receiver = WalletTool() receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() # Farm blocks blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass # Coinbase that gets spent block1 = blocks[1] # This condition requires block1 coinbase to be spent after 3 seconds from now current_time_plus3 = uint64(int(time.time() * 1000) + 3000) block1_cvp = ConditionVarPair(ConditionOpcode.ASSERT_TIME_EXCEEDS, int_to_bytes(current_time_plus3), None) block1_dic = {block1_cvp.opcode: [block1_cvp]} block1_spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, block1.get_coinbase(), block1_dic) # program that will be sent to early assert block1_spend_bundle is not None program = best_solution_program(block1_spend_bundle) aggsig = block1_spend_bundle.aggregated_signature # Create another block that includes our transaction dic_h = {11: (program, aggsig)} invalid_new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h) # Try to validate that block before 3 sec next_block = invalid_new_blocks[11] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is Err.ASSERT_TIME_EXCEEDS_FAILED # wait 3 sec to pass await asyncio.sleep(3.1) dic_h = {12: (program, aggsig)} valid_new_blocks = bt.get_consecutive_blocks(test_constants, 2, blocks[:11], 10, b"", coinbase_puzzlehash, dic_h) for block in valid_new_blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass # Try to validate that block after 3 sec have passed next_block = valid_new_blocks[12] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is None
async def test_assert_block_age_exceeds(self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() wallet_receiver = WalletTool() receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() # Farm blocks blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass # Coinbase that gets spent block1 = blocks[1] # This condition requires block1 coinbase to be spent more than 10 block after it was farmed # block index has to be greater than (1 + 10 = 11) block1_cvp = ConditionVarPair(ConditionOpcode.ASSERT_BLOCK_AGE_EXCEEDS, int_to_bytes(10), None) block1_dic = {block1_cvp.opcode: [block1_cvp]} block1_spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, block1.get_coinbase(), block1_dic) # program that will be sent to early assert block1_spend_bundle is not None program = best_solution_program(block1_spend_bundle) aggsig = block1_spend_bundle.aggregated_signature # Create another block that includes our transaction dic_h = {11: (program, aggsig)} invalid_new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h) # Try to validate that block at index 11 next_block = invalid_new_blocks[11] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is Err.ASSERT_BLOCK_AGE_EXCEEDS_FAILED dic_h = {12: (program, aggsig)} valid_new_blocks = bt.get_consecutive_blocks(test_constants, 2, blocks[:11], 10, b"", coinbase_puzzlehash, dic_h) for block in valid_new_blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass # Try to validate that block at index 12 next_block = valid_new_blocks[12] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is None
async def test_assert_coin_consumed(self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() wallet_receiver = WalletTool() receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() # Farm blocks blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass # Coinbase that gets spent block1 = blocks[1] block2 = blocks[2] # This condition requires block2 coinbase to be spent block1_cvp = ConditionVarPair( ConditionOpcode.ASSERT_COIN_CONSUMED, block2.get_coinbase().name(), None, ) block1_dic = {block1_cvp.opcode: [block1_cvp]} block1_spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, block1.get_coinbase(), block1_dic) # This condition requires block1 coinbase to be spent block2_cvp = ConditionVarPair( ConditionOpcode.ASSERT_COIN_CONSUMED, block1.get_coinbase().name(), None, ) block2_dic = {block2_cvp.opcode: [block2_cvp]} block2_spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, block2.get_coinbase(), block2_dic) # Invalid block bundle assert block1_spend_bundle is not None solo_program = best_solution_program(block1_spend_bundle) aggsig = block1_spend_bundle.aggregated_signature # Create another block that includes our transaction dic_h = {11: (solo_program, aggsig)} invalid_new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h) # Try to validate that block next_block = invalid_new_blocks[11] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is Err.ASSERT_COIN_CONSUMED_FAILED # bundle_together contains both transactions bundle_together = SpendBundle.aggregate( [block1_spend_bundle, block2_spend_bundle]) valid_program = best_solution_program(bundle_together) aggsig = bundle_together.aggregated_signature # Create another block that includes our transaction dic_h = {11: (valid_program, aggsig)} new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks[:11], 10, b"1", coinbase_puzzlehash, dic_h) # Try to validate newly created block next_block = new_blocks[11] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is None
async def test_assert_my_coin_id(self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() wallet_receiver = WalletTool() receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() # Farm blocks blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass # Coinbase that gets spent spent_block = blocks[1] bad_block = blocks[2] valid_cvp = ConditionVarPair( ConditionOpcode.ASSERT_MY_COIN_ID, spent_block.get_coinbase().name(), None, ) valid_dic = {valid_cvp.opcode: [valid_cvp]} bad_cvp = ConditionVarPair( ConditionOpcode.ASSERT_MY_COIN_ID, bad_block.get_coinbase().name(), None, ) bad_dic = {bad_cvp.opcode: [bad_cvp]} bad_spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spent_block.get_coinbase(), bad_dic) valid_spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spent_block.get_coinbase(), valid_dic) # Invalid block bundle assert bad_spend_bundle is not None invalid_program = best_solution_program(bad_spend_bundle) aggsig = bad_spend_bundle.aggregated_signature # Create another block that includes our transaction dic_h = {11: (invalid_program, aggsig)} invalid_new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h) # Try to validate that block next_block = invalid_new_blocks[11] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is Err.ASSERT_MY_COIN_ID_FAILED # Valid block bundle assert valid_spend_bundle is not None valid_program = best_solution_program(valid_spend_bundle) aggsig = valid_spend_bundle.aggregated_signature # Create another block that includes our transaction dic_h = {11: (valid_program, aggsig)} new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks[:11], 10, b"1", coinbase_puzzlehash, dic_h) next_block = new_blocks[11] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is None
async def test_basic_blockchain_tx(self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() wallet_receiver = WalletTool() receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass spent_block = blocks[1] spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spent_block.get_coinbase()) assert spend_bundle is not None tx: full_node_protocol.RespondTransaction = ( full_node_protocol.RespondTransaction(spend_bundle)) async for _ in full_node_1.respond_transaction(tx): outbound: OutboundMessage = _ # Maybe transaction means that it's accepted in mempool assert outbound.message.function == "new_transaction" sb = full_node_1.mempool_manager.get_spendbundle(spend_bundle.name()) assert sb is spend_bundle last_block = blocks[10] next_spendbundle = await full_node_1.mempool_manager.create_bundle_for_tip( last_block.header) assert next_spendbundle is not None program = best_solution_program(next_spendbundle) aggsig = next_spendbundle.aggregated_signature dic_h = {11: (program, aggsig)} new_blocks = bt.get_consecutive_blocks(test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h) next_block = new_blocks[11] async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(next_block)): pass tips = full_node_1.blockchain.get_current_tips() assert next_block.header in tips 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(), next_block.header) assert unspent is not None full_tips = await full_node_1.blockchain.get_full_tips() in_full_tips = False farmed_block: Optional[FullBlock] = None for tip in full_tips: if tip.header == next_block.header: in_full_tips = True farmed_block = tip assert in_full_tips assert farmed_block is not None assert farmed_block.transactions_generator == program
async def test_validate_blockchain_spend_reorg_coin(self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() receiver_1_puzzlehash = wallet_a.get_new_puzzlehash() receiver_2_puzzlehash = wallet_a.get_new_puzzlehash() receiver_3_puzzlehash = wallet_a.get_new_puzzlehash() blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass spent_block = blocks[1] spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_1_puzzlehash, spent_block.get_coinbase()) block_spendbundle = SpendBundle.aggregate([spend_bundle]) program = best_solution_program(block_spendbundle) aggsig = block_spendbundle.aggregated_signature dic_h = {5: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 1, blocks[:5], 10, b"spend_reorg_coin", coinbase_puzzlehash, dic_h, ) [ _ async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(new_blocks[-1])) ] assert new_blocks[-1].header_hash in full_node_1.blockchain.headers coin_2 = None for coin in new_blocks[-1].additions(): if coin.puzzle_hash == receiver_1_puzzlehash: coin_2 = coin break assert coin_2 is not None spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_2_puzzlehash, coin_2) block_spendbundle = SpendBundle.aggregate([spend_bundle]) program = best_solution_program(block_spendbundle) aggsig = block_spendbundle.aggregated_signature dic_h = {6: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 1, new_blocks[:6], 10, b"spend_reorg_coin", coinbase_puzzlehash, dic_h, ) [ _ async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(new_blocks[-1])) ] assert new_blocks[-1].header_hash in full_node_1.blockchain.headers coin_3 = None for coin in new_blocks[-1].additions(): if coin.puzzle_hash == receiver_2_puzzlehash: coin_3 = coin break assert coin_3 is not None spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_3_puzzlehash, coin_3) block_spendbundle = SpendBundle.aggregate([spend_bundle]) program = best_solution_program(block_spendbundle) aggsig = block_spendbundle.aggregated_signature dic_h = {7: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 1, new_blocks[:7], 10, b"spend_reorg_coin", coinbase_puzzlehash, dic_h, ) [ _ async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(new_blocks[-1])) ] assert new_blocks[-1].header_hash in full_node_1.blockchain.headers coin_4 = None for coin in new_blocks[-1].additions(): if coin.puzzle_hash == receiver_3_puzzlehash: coin_4 = coin break assert coin_4 is not None
async def test_validate_blockchain_with_reorg_double_spend( self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() wallet_receiver = WalletTool() receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass spent_block = blocks[1] spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, spent_block.get_coinbase()) block_spendbundle = SpendBundle.aggregate([spend_bundle]) program = best_solution_program(block_spendbundle) aggsig = block_spendbundle.aggregated_signature dic_h = {11: (program, aggsig)} blocks = bt.get_consecutive_blocks(test_constants, 10, blocks, 10, b"", coinbase_puzzlehash, dic_h) # Move chain to height 20, with a spend at height 11 for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass # Reorg at block 5, same spend at block 13 and 14 that was previously at block 11 dic_h = {13: (program, aggsig), 14: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 9, blocks[:6], 10, b"another seed", coinbase_puzzlehash, dic_h, ) for block in new_blocks[:13]: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass next_block = new_blocks[13] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is None [ _ async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(new_blocks[13])) ] next_block = new_blocks[14] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is Err.DOUBLE_SPEND # Now test Reorg at block 5, same spend at block 9 that was previously at block 11 dic_h = {9: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 4, blocks[:6], 10, b"another seed 2", coinbase_puzzlehash, dic_h, ) for block in new_blocks[:9]: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass next_block = new_blocks[9] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is None # Now test Reorg at block 10, same spend at block 11 that was previously at block 11 dic_h = {11: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 4, blocks[:11], 10, b"another seed 3", coinbase_puzzlehash, dic_h, ) for block in new_blocks[:11]: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass next_block = new_blocks[11] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is None # Now test Reorg at block 11, same spend at block 12 that was previously at block 11 dic_h = {12: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 4, blocks[:12], 10, b"another seed 4", coinbase_puzzlehash, dic_h, ) for block in new_blocks[:12]: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass next_block = new_blocks[12] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is Err.DOUBLE_SPEND # Now test Reorg at block 11, same spend at block 15 that was previously at block 11 dic_h = {15: (program, aggsig)} new_blocks = bt.get_consecutive_blocks( test_constants, 4, blocks[:12], 10, b"another seed 5", coinbase_puzzlehash, dic_h, ) for block in new_blocks[:15]: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass next_block = new_blocks[15] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is Err.DOUBLE_SPEND
async def test_assert_fee_condition(self, two_nodes): num_blocks = 10 wallet_a = WalletTool() coinbase_puzzlehash = wallet_a.get_new_puzzlehash() wallet_receiver = WalletTool() receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() # Farm blocks blocks = bt.get_consecutive_blocks(test_constants, num_blocks, [], 10, b"", coinbase_puzzlehash) full_node_1, full_node_2, server_1, server_2 = two_nodes for block in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass # Coinbase that gets spent block1 = blocks[1] # This condition requires fee to be 10 mojo cvp_fee = ConditionVarPair(ConditionOpcode.ASSERT_FEE, int_to_bytes(10), None) block1_dic = {cvp_fee.opcode: [cvp_fee]} # This spendbundle has 9 mojo as fee invalid_spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, block1.get_coinbase(), block1_dic, 9) assert invalid_spend_bundle is not None program = best_solution_program(invalid_spend_bundle) aggsig = invalid_spend_bundle.aggregated_signature # Create another block that includes our transaction dic_h = {11: (program, aggsig)} invalid_new_blocks = bt.get_consecutive_blocks( test_constants, 1, blocks, 10, b"", coinbase_puzzlehash, dic_h, fees=uint64(9), ) # Try to validate that block at index 11 next_block = invalid_new_blocks[11] error = await full_node_1.blockchain._validate_transactions( next_block, next_block.get_fees_coin().amount) assert error is Err.ASSERT_FEE_CONDITION_FAILED # This condition requires fee to be 10 mojo cvp_fee = ConditionVarPair(ConditionOpcode.ASSERT_FEE, int_to_bytes(10), None) condition_dict = {cvp_fee.opcode: [cvp_fee]} valid_spend_bundle = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, block1.get_coinbase(), condition_dict, 10) assert valid_spend_bundle is not None valid_program = best_solution_program(valid_spend_bundle) aggsig = valid_spend_bundle.aggregated_signature dic_h = {11: (valid_program, aggsig)} valid_new_blocks = bt.get_consecutive_blocks( test_constants, 1, blocks[:11], 10, b"", coinbase_puzzlehash, dic_h, fees=uint64(10), ) next_block = valid_new_blocks[11] fee_base = calculate_base_fee(next_block.height) error = await full_node_1.blockchain._validate_transactions( next_block, fee_base) assert error is None for block in valid_new_blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(block)): pass
async def test1(self, two_nodes): num_blocks = 5 test_rpc_port = uint16(21522) nodes, _ = two_nodes full_node_api_1, full_node_api_2 = nodes server_1 = full_node_api_1.full_node.server server_2 = full_node_api_2.full_node.server def stop_node_cb(): full_node_api_1._close() server_1.close_all() full_node_rpc_api = FullNodeRpcApi(full_node_api_1.full_node) config = bt.config hostname = config["self_hostname"] daemon_port = config["daemon_port"] rpc_cleanup = await start_rpc_server( full_node_rpc_api, hostname, daemon_port, test_rpc_port, stop_node_cb, bt.root_path, config, connect_to_daemon=False, ) try: client = await FullNodeRpcClient.create(self_hostname, test_rpc_port, bt.root_path, config) state = await client.get_blockchain_state() assert state["peak"] is None assert not state["sync"]["sync_mode"] assert state["difficulty"] > 0 assert state["sub_slot_iters"] > 0 blocks = bt.get_consecutive_blocks(num_blocks) blocks = bt.get_consecutive_blocks( num_blocks, block_list_input=blocks, guarantee_transaction_block=True) assert len(await client.get_unfinished_block_headers()) == 0 assert len((await client.get_block_records(0, 100))) == 0 for block in blocks: if is_overflow_block( test_constants, block.reward_chain_block.signage_point_index): finished_ss = block.finished_sub_slots[:-1] else: finished_ss = block.finished_sub_slots unf = UnfinishedBlock( finished_ss, block.reward_chain_block.get_unfinished(), block.challenge_chain_sp_proof, block.reward_chain_sp_proof, block.foliage, block.foliage_transaction_block, block.transactions_info, block.transactions_generator, [], ) await full_node_api_1.full_node.respond_unfinished_block( full_node_protocol.RespondUnfinishedBlock(unf), None) await full_node_api_1.full_node.respond_block( full_node_protocol.RespondBlock(block), None) assert len(await client.get_unfinished_block_headers()) > 0 assert len(await client.get_all_block(0, 2)) == 2 state = await client.get_blockchain_state() block = await client.get_block(state["peak"].header_hash) assert block == blocks[-1] assert (await client.get_block(bytes([1] * 32))) is None assert (await client.get_block_record_by_height(2) ).header_hash == blocks[2].header_hash assert len((await client.get_block_records(0, 100))) == num_blocks * 2 assert (await client.get_block_record_by_height(100)) is None ph = list(blocks[-1].get_included_reward_coins())[0].puzzle_hash coins = await client.get_coin_records_by_puzzle_hash(ph) print(coins) assert len(coins) >= 1 additions, removals = await client.get_additions_and_removals( blocks[-1].header_hash) assert len(additions) >= 2 and len(removals) == 0 wallet = WalletTool() wallet_receiver = WalletTool( AugSchemeMPL.key_gen(std_hash(b"123123"))) ph = wallet.get_new_puzzlehash() ph_2 = wallet.get_new_puzzlehash() ph_receiver = wallet_receiver.get_new_puzzlehash() assert len(await client.get_coin_records_by_puzzle_hash(ph)) == 0 assert len( await client.get_coin_records_by_puzzle_hash(ph_receiver)) == 0 blocks = bt.get_consecutive_blocks( 2, block_list_input=blocks, guarantee_transaction_block=True, farmer_reward_puzzle_hash=ph, pool_reward_puzzle_hash=ph, ) for block in blocks[-2:]: await full_node_api_1.full_node.respond_block( full_node_protocol.RespondBlock(block)) assert len(await client.get_coin_records_by_puzzle_hash(ph)) == 2 assert len( await client.get_coin_records_by_puzzle_hash(ph_receiver)) == 0 coin_to_spend = list(blocks[-1].get_included_reward_coins())[0] spend_bundle = wallet.generate_signed_transaction( coin_to_spend.amount, ph_receiver, coin_to_spend) assert len(await client.get_all_mempool_items()) == 0 assert len(await client.get_all_mempool_tx_ids()) == 0 assert (await client.get_mempool_item_by_tx_id(spend_bundle.name() )) is None await client.push_tx(spend_bundle) assert len(await client.get_all_mempool_items()) == 1 assert len(await client.get_all_mempool_tx_ids()) == 1 assert (SpendBundle.from_json_dict( list((await client.get_all_mempool_items() ).values())[0]["spend_bundle"]) == spend_bundle) assert (await client.get_all_mempool_tx_ids())[0] == spend_bundle.name() assert (SpendBundle.from_json_dict( (await client.get_mempool_item_by_tx_id( spend_bundle.name()))["spend_bundle"]) == spend_bundle) await full_node_api_1.farm_new_transaction_block( FarmNewBlockProtocol(ph_2)) assert len( await client.get_coin_records_by_puzzle_hash(ph_receiver)) == 1 assert len( list( filter(lambda cr: not cr.spent, (await client.get_coin_records_by_puzzle_hash(ph))))) == 3 assert len(await client.get_coin_records_by_puzzle_hash(ph, False)) == 3 assert len(await client.get_coin_records_by_puzzle_hash(ph, True)) == 4 assert len(await client.get_coin_records_by_puzzle_hash( ph, True, 0, 100)) == 4 assert len(await client.get_coin_records_by_puzzle_hash( ph, True, 50, 100)) == 0 assert len(await client.get_coin_records_by_puzzle_hash( ph, True, 0, blocks[-1].height + 1)) == 2 assert len(await client.get_coin_records_by_puzzle_hash(ph, True, 0, 1)) == 0 assert len(await client.get_connections()) == 0 await client.open_connection(self_hostname, server_2._port) async def num_connections(): return len(await client.get_connections()) await time_out_assert(10, num_connections, 1) connections = await client.get_connections() await client.close_connection(connections[0]["node_id"]) await time_out_assert(10, num_connections, 0) finally: # Checks that the RPC manages to stop the node client.close() await client.await_closed() await rpc_cleanup()