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_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
def add_int_cond( conds: Dict[ConditionOpcode, List[ConditionWithArgs]], op: ConditionOpcode, arg: int, ): if op not in conds: conds[op] = [] conds[op].append(ConditionWithArgs(op, [int_to_bytes(arg)]))
def type_for_atom(atom): if len(atom) > 2: try: v = atom.decode("utf8") if all(c in string.printable for c in v): return Type.QUOTES except UnicodeDecodeError: pass return Type.HEX if int_to_bytes(int_from_bytes(atom)) == atom: return Type.INT return Type.HEX
def generate_unsigned_transaction( self, amount, newpuzzlehash, coin: Coin, condition_dic: Dict[ConditionOpcode, List[ConditionVarPair]], fee: int = 0, secretkey=None, ): spends = [] spend_value = coin.amount puzzle_hash = coin.puzzle_hash if secretkey is None: pubkey, secretkey = self.get_keys(puzzle_hash) else: pubkey = secretkey.get_public_key() puzzle = puzzle_for_pk(bytes(pubkey)) if ConditionOpcode.CREATE_COIN not in condition_dic: condition_dic[ConditionOpcode.CREATE_COIN] = [] output = ConditionVarPair(ConditionOpcode.CREATE_COIN, newpuzzlehash, int_to_bytes(amount)) condition_dic[output.opcode].append(output) amount_total = sum( int_from_bytes(cvp.var2) for cvp in condition_dic[ConditionOpcode.CREATE_COIN]) change = spend_value - amount_total - fee if change > 0: changepuzzlehash = self.get_new_puzzlehash() change_output = ConditionVarPair(ConditionOpcode.CREATE_COIN, changepuzzlehash, int_to_bytes(change)) condition_dic[output.opcode].append(change_output) solution = self.make_solution(condition_dic) else: solution = self.make_solution(condition_dic) spends.append((puzzle, CoinSolution(coin, solution))) return spends
async def test_assert_fee_condition_wrong_fee(self, two_nodes): num_blocks = 2 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 block = blocks[1] for b in blocks: async for _ in full_node_1.respond_block( full_node_protocol.RespondBlock(b) ): pass cvp = ConditionVarPair(ConditionOpcode.ASSERT_FEE, int_to_bytes(10), None,) dic = {cvp.opcode: [cvp]} spend_bundle1 = wallet_a.generate_signed_transaction( 1000, receiver_puzzlehash, block.header.data.coinbase, dic, 9 ) assert spend_bundle1 is not None tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction( spend_bundle1 ) outbound_messages: List[OutboundMessage] = [] async for outbound in full_node_1.respond_transaction(tx1): outbound_messages.append(outbound) new_transaction = False for msg in outbound_messages: if msg.message.function == "new_transaction": new_transaction = True assert new_transaction == False mempool_bundle = full_node_1.mempool_manager.get_spendbundle( spend_bundle1.name() ) assert mempool_bundle is None
async def test_hints_in_blockchain(self, empty_blockchain): # noqa: F811 blockchain: Blockchain = empty_blockchain blocks = bt.get_consecutive_blocks( 5, block_list_input=[], guarantee_transaction_block=True, farmer_reward_puzzle_hash=bt.pool_ph, pool_reward_puzzle_hash=bt.pool_ph, ) for block in blocks: await blockchain.receive_block(block) wt: WalletTool = bt.get_pool_wallet_tool() puzzle_hash = 32 * b"\0" amount = int_to_bytes(1) hint = 32 * b"\5" coin_spent = list(blocks[-1].get_included_reward_coins())[0] condition_dict = { ConditionOpcode.CREATE_COIN: [ ConditionWithArgs(ConditionOpcode.CREATE_COIN, [puzzle_hash, amount, hint]) ] } tx: SpendBundle = wt.generate_signed_transaction( 10, wt.get_new_puzzlehash(), coin_spent, condition_dic=condition_dict, ) blocks = bt.get_consecutive_blocks(10, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx) for block in blocks: await blockchain.receive_block(block) get_hint = await blockchain.hint_store.get_coin_ids(hint) assert get_hint[0] == Coin(coin_spent.name(), puzzle_hash, 1).name()
def launcher_id_to_p2_puzzle_hash(launcher_id: bytes32, seconds_delay: uint64, delayed_puzzle_hash: bytes32) -> bytes32: return create_p2_singleton_puzzle(SINGLETON_MOD_HASH, launcher_id, int_to_bytes(seconds_delay), delayed_puzzle_hash).get_tree_hash()
def piggybank_announcement_assertion(pb_coin: Coin, contrib_amount: uint64): return [ ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT, std_hash(pb_coin.name() + int_to_bytes(pb_coin.amount + contrib_amount)) ]
async def test_subscribe_for_hint_long_sync(self, wallet_two_node_simulator): num_blocks = 4 full_nodes, wallets = wallet_two_node_simulator full_node_api = full_nodes[0] full_node_api_1 = full_nodes[1] wallet_node, server_2 = wallets[0] fn_server = full_node_api.full_node.server fn_server_1 = full_node_api_1.full_node.server wsm: WalletStateManager = wallet_node.wallet_state_manager await server_2.start_client( PeerInfo(self_hostname, uint16(fn_server._port)), None) incoming_queue, peer_id = await add_dummy_connection( fn_server, 12312, NodeType.WALLET) incoming_queue_1, peer_id_1 = await add_dummy_connection( fn_server_1, 12313, NodeType.WALLET) wt: WalletTool = bt.get_pool_wallet_tool() ph = wt.get_new_puzzlehash() for i in range(0, num_blocks): await full_node_api.farm_new_transaction_block( FarmNewBlockProtocol(ph)) await asyncio.sleep(6) coins = await full_node_api.full_node.coin_store.get_coin_records_by_puzzle_hashes( False, [ph]) coin_spent = coins[0].coin hint_puzzle_hash = 32 * b"\2" amount = 1 amount_bin = int_to_bytes(1) hint = 32 * b"\5" fake_wallet_peer = fn_server.all_connections[peer_id] fake_wallet_peer_1 = fn_server_1.all_connections[peer_id_1] msg = wallet_protocol.RegisterForPhUpdates([hint], 0) msg_response = await full_node_api.register_interest_in_puzzle_hash( msg, fake_wallet_peer) msg_response_1 = await full_node_api_1.register_interest_in_puzzle_hash( msg, fake_wallet_peer_1) assert msg_response.type == ProtocolMessageTypes.respond_to_ph_update.value data_response: RespondToPhUpdates = RespondToCoinUpdates.from_bytes( msg_response.data) assert len(data_response.coin_states) == 0 condition_dict = { ConditionOpcode.CREATE_COIN: [ ConditionWithArgs(ConditionOpcode.CREATE_COIN, [hint_puzzle_hash, amount_bin, hint]) ] } tx: SpendBundle = wt.generate_signed_transaction( 10, wt.get_new_puzzlehash(), coin_spent, condition_dic=condition_dict, ) await full_node_api.respond_transaction(RespondTransaction(tx), fake_wallet_peer) await time_out_assert(15, tx_in_pool, True, full_node_api.full_node.mempool_manager, tx.name()) # Create more blocks than recent "short_sync_blocks_behind_threshold" so that node enters batch for i in range(0, 100): await full_node_api.farm_new_transaction_block( FarmNewBlockProtocol(ph)) node1_height = full_node_api_1.full_node.blockchain.get_peak_height() assert node1_height is None await fn_server_1.start_client( PeerInfo(self_hostname, uint16(fn_server._port)), None) node0_height = full_node_api.full_node.blockchain.get_peak_height() await time_out_assert( 15, full_node_api_1.full_node.blockchain.get_peak_height, node0_height) all_messages = await self.get_all_messages_in_queue(incoming_queue) all_messages_1 = await self.get_all_messages_in_queue(incoming_queue_1) def check_messages_for_hint(messages): notified_state = None for message in messages: if message.type == ProtocolMessageTypes.coin_state_update.value: data_response: CoinStateUpdate = CoinStateUpdate.from_bytes( message.data) notified_state = data_response break assert notified_state is not None assert notified_state.items[0].coin == Coin( coin_spent.name(), hint_puzzle_hash, amount) check_messages_for_hint(all_messages) check_messages_for_hint(all_messages_1)
def get_name_puzzle_conditions(generator: BlockGenerator, max_cost: int, *, cost_per_byte: int, mempool_mode: bool, height: Optional[uint32] = None) -> NPCResult: block_program, block_program_args = setup_generator_args(generator) size_cost = len(bytes(generator.program)) * cost_per_byte max_cost -= size_cost if max_cost < 0: return NPCResult(uint16(Err.INVALID_BLOCK_COST.value), [], uint64(0)) # in mempool mode, the height doesn't matter, because it's always strict. # But otherwise, height must be specified to know which rules to apply assert mempool_mode or height is not None # mempool mode also has these rules apply assert (MEMPOOL_MODE & COND_CANON_INTS) != 0 assert (MEMPOOL_MODE & NO_NEG_DIV) != 0 if mempool_mode: flags = MEMPOOL_MODE elif unwrap(height) >= DEFAULT_CONSTANTS.SOFT_FORK_HEIGHT: # conditions must use integers in canonical encoding (i.e. no redundant # leading zeros) # the division operator may not be used with negative operands flags = COND_CANON_INTS | NO_NEG_DIV else: flags = 0 try: err, result = GENERATOR_MOD.run_as_generator(max_cost, flags, block_program, block_program_args) if err is not None: assert err != 0 return NPCResult(uint16(err), [], uint64(0)) first = True npc_list = [] for r in result.spends: conditions: Dict[ConditionOpcode, List[ConditionWithArgs]] = {} if r.height_relative is not None: add_int_cond(conditions, ConditionOpcode.ASSERT_HEIGHT_RELATIVE, r.height_relative) if r.seconds_relative > 0: add_int_cond(conditions, ConditionOpcode.ASSERT_SECONDS_RELATIVE, r.seconds_relative) for cc in r.create_coin: if cc[2] == b"": add_cond(conditions, ConditionOpcode.CREATE_COIN, [cc[0], int_to_bytes(cc[1])]) else: add_cond(conditions, ConditionOpcode.CREATE_COIN, [cc[0], int_to_bytes(cc[1]), cc[2]]) for sig in r.agg_sig_me: add_cond(conditions, ConditionOpcode.AGG_SIG_ME, [sig[0], sig[1]]) # all conditions that aren't tied to a specific spent coin, we roll into the first one if first: first = False if result.reserve_fee > 0: add_int_cond(conditions, ConditionOpcode.RESERVE_FEE, result.reserve_fee) if result.height_absolute > 0: add_int_cond(conditions, ConditionOpcode.ASSERT_HEIGHT_ABSOLUTE, result.height_absolute) if result.seconds_absolute > 0: add_int_cond(conditions, ConditionOpcode.ASSERT_SECONDS_ABSOLUTE, result.seconds_absolute) for sig in result.agg_sig_unsafe: add_cond(conditions, ConditionOpcode.AGG_SIG_UNSAFE, [sig[0], sig[1]]) npc_list.append( NPC(r.coin_id, r.puzzle_hash, [(op, cond) for op, cond in conditions.items()])) return NPCResult(None, npc_list, uint64(result.cost + size_cost)) except BaseException as e: log.debug(f"get_name_puzzle_condition failed: {e}") return NPCResult(uint16(Err.GENERATOR_RUNTIME_ERROR.value), [], uint64(0))
def __bytes__(self): return self.parent_coin_info + self.puzzle_hash + int_to_bytes(self.amount)
async def test_everything_with_signature(self, setup_sim): sim, sim_client = setup_sim try: sk = PrivateKey.from_bytes(secret_exponent_for_index(1).to_bytes(32, "big")) tail: Program = EverythingWithSig.construct([Program.to(sk.get_g1())]) checker_solution: Program = EverythingWithSig.solve([], {}) cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, tail.get_tree_hash(), acs) cat_ph: bytes32 = cat_puzzle.get_tree_hash() await sim.farm_block(cat_ph) # Test eve spend # We don't sign any message data because CLVM 0 translates to b'' apparently starting_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(cat_ph))[0].coin signature: G2Element = AugSchemeMPL.sign( sk, (starting_coin.name() + sim.defaults.AGG_SIG_ME_ADDITIONAL_DATA) ) await self.do_spend( sim, sim_client, tail, [starting_coin], [NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), starting_coin.amount], [51, 0, -113, tail, checker_solution], ] ) ], (MempoolInclusionStatus.SUCCESS, None), limitations_solutions=[checker_solution], signatures=[signature], cost_str="Signature Issuance", ) # Test melting value coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin signature = AugSchemeMPL.sign( sk, (int_to_bytes(-1) + coin.name() + sim.defaults.AGG_SIG_ME_ADDITIONAL_DATA) ) await self.do_spend( sim, sim_client, tail, [coin], [NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), coin.amount - 1], [51, 0, -113, tail, checker_solution], ] ) ], (MempoolInclusionStatus.SUCCESS, None), extra_deltas=[-1], limitations_solutions=[checker_solution], signatures=[signature], cost_str="Signature Melt", ) # Test minting value coin = (await sim_client.get_coin_records_by_puzzle_hash(cat_ph, include_spent_coins=False))[0].coin signature = AugSchemeMPL.sign(sk, (int_to_bytes(1) + coin.name() + sim.defaults.AGG_SIG_ME_ADDITIONAL_DATA)) # Need something to fund the minting temp_p = Program.to(1) temp_ph: bytes32 = temp_p.get_tree_hash() await sim.farm_block(temp_ph) acs_coin: Coin = (await sim_client.get_coin_records_by_puzzle_hash(temp_ph, include_spent_coins=False))[ 0 ].coin acs_bundle = SpendBundle( [ CoinSpend( acs_coin, temp_p, Program.to([]), ) ], G2Element(), ) await self.do_spend( sim, sim_client, tail, [coin], [NO_LINEAGE_PROOF], [ Program.to( [ [51, acs.get_tree_hash(), coin.amount + 1], [51, 0, -113, tail, checker_solution], ] ) ], (MempoolInclusionStatus.SUCCESS, None), extra_deltas=[1], limitations_solutions=[checker_solution], signatures=[signature], additional_spends=[acs_bundle], cost_str="Signature Mint", ) finally: await sim.close()
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.header.data.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.header.data.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.header.data.fees_coin.amount ) assert error is None
def to_atom(class_, v): if isinstance(v, int): v = int_to_bytes(v) return v
def __bytes__(self): f = io.BytesIO() f.write(self.parent_coin_info) f.write(self.puzzle_hash) f.write(int_to_bytes(self.amount)) return f.getvalue()
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.header.data.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.header.data.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.header.data.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 test_assert_block_age_exceeds(self, two_nodes): num_blocks = 11 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 index 11 # This condition requires block1 coinbase to be spent more than 10 block after it was farmed # block index has to be greater than (2 + 9 = 11) block1_cvp = ConditionWithArgs( ConditionOpcode.ASSERT_HEIGHT_AGE_EXCEEDS, [int_to_bytes(9)]) 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 too 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, guarantee_transaction_block=True, ) # Try to validate that block at index 11 res, err, _ = await full_node_1.blockchain.receive_block( invalid_new_blocks[-1]) assert res == ReceiveBlockResult.INVALID_BLOCK assert err == Err.ASSERT_HEIGHT_AGE_EXCEEDS_FAILED new_blocks = bt.get_consecutive_blocks( 1, blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_transaction_block=True, ) res, _, _ = await full_node_1.blockchain.receive_block(new_blocks[-1]) assert res == ReceiveBlockResult.NEW_PEAK # At index 12, it can be spent new_blocks = bt.get_consecutive_blocks( 1, new_blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, transaction_data=block1_spend_bundle, guarantee_transaction_block=True, ) res, err, _ = await full_node_1.blockchain.receive_block(new_blocks[-1] ) assert err is None assert res == ReceiveBlockResult.NEW_PEAK
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.header.data.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.header.data.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.header.data.fees_coin.amount ) assert error is None