async def start(self): self.store = await PoolStore.create() self.pending_point_partials = asyncio.Queue() self_hostname = self.config["self_hostname"] self.node_rpc_client = await FullNodeRpcClient.create( self_hostname, uint16(8555), DEFAULT_ROOT_PATH, self.config) self.wallet_rpc_client = await WalletRpcClient.create( self.config["self_hostname"], uint16(9256), DEFAULT_ROOT_PATH, self.config) self.blockchain_state = await self.node_rpc_client.get_blockchain_state( ) res = await self.wallet_rpc_client.log_in_and_skip( fingerprint=self.wallet_fingerprint) self.log.info(f"Logging in: {res}") res = await self.wallet_rpc_client.get_wallet_balance(self.wallet_id) self.log.info(f"Obtaining balance: {res}") self.scan_p2_singleton_puzzle_hashes = await self.store.get_pay_to_singleton_phs( ) self.confirm_partials_loop_task = asyncio.create_task( self.confirm_partials_loop()) self.collect_pool_rewards_loop_task = asyncio.create_task( self.collect_pool_rewards_loop()) self.create_payment_loop_task = asyncio.create_task( self.create_payment_loop()) self.submit_payment_loop_task = asyncio.create_task( self.submit_payment_loop()) self.get_peak_loop_task = asyncio.create_task(self.get_peak_loop()) self.pending_payments = asyncio.Queue()
def _run_generator( constants_dict: bytes, unfinished_block_bytes: bytes, block_generator_bytes: bytes, height: uint32, ) -> Optional[bytes]: """ Runs the CLVM generator from bytes inputs. This is meant to be called under a ProcessPoolExecutor, in order to validate the heavy parts of a block (clvm program) in a different process. """ try: constants: ConsensusConstants = dataclass_from_dict( ConsensusConstants, constants_dict) unfinished_block: UnfinishedBlock = UnfinishedBlock.from_bytes( unfinished_block_bytes) assert unfinished_block.transactions_info is not None block_generator: BlockGenerator = BlockGenerator.from_bytes( block_generator_bytes) assert block_generator.program == unfinished_block.transactions_generator npc_result: NPCResult = get_name_puzzle_conditions( block_generator, min(constants.MAX_BLOCK_COST_CLVM, unfinished_block.transactions_info.cost), cost_per_byte=constants.COST_PER_BYTE, mempool_mode=False, height=height, ) return bytes(npc_result) except ValidationError as e: return bytes(NPCResult(uint16(e.code.value), [], uint64(0))) except Exception: return bytes(NPCResult(uint16(Err.UNKNOWN.value), [], uint64(0)))
def get_name_puzzle_conditions_rust(generator: BlockGenerator, max_cost: int, *, cost_per_byte: int, safe_mode: bool) -> NPCResult: block_program, block_program_args = setup_generator_args(generator) max_cost -= len(bytes(generator.program)) * cost_per_byte if max_cost < 0: return NPCResult(uint16(Err.INVALID_BLOCK_COST.value), [], uint64(0)) flags = STRICT_MODE if safe_mode else 0 err, result, clvm_cost = GENERATOR_MOD.run_as_generator( max_cost, flags, block_program, block_program_args) if err is not None: return NPCResult(uint16(err), [], uint64(0)) else: npc_list = [] for r in result: conditions = [] for c in r.conditions: cwa = [] for cond_list in c[1]: cwa.append( ConditionWithArgs( ConditionOpcode(bytes([cond_list.opcode])), cond_list.vars)) conditions.append((ConditionOpcode(bytes([c[0]])), cwa)) npc_list.append(NPC(r.coin_name, r.puzzle_hash, conditions)) return NPCResult(None, npc_list, uint64(clvm_cost))
def get_name_puzzle_conditions(generator: BlockGenerator, max_cost: int, *, cost_per_byte: int, safe_mode: bool, rust_checker: bool) -> NPCResult: """ This executes the generator program and returns the coins and their conditions. If the cost of the program (size, CLVM execution and conditions) exceed max_cost, the function fails. In order to accurately take the size of the program into account when calculating cost, cost_per_byte must be specified. safe_mode determines whether the clvm program and conditions are executed in strict mode or not. When in safe/strict mode, unknow operations or conditions are considered failures. This is the mode when accepting transactions into the mempool. """ try: if rust_checker: return get_name_puzzle_conditions_rust(generator, max_cost, cost_per_byte=cost_per_byte, safe_mode=safe_mode) else: return get_name_puzzle_conditions_python( generator, max_cost, cost_per_byte=cost_per_byte, safe_mode=safe_mode) except ValidationError as e: return NPCResult(uint16(e.code.value), [], uint64(0)) except Exception as e: log.debug(f"get_name_puzzle_condition failed: {e}") return NPCResult(uint16(Err.GENERATOR_RUNTIME_ERROR.value), [], uint64(0))
async def start(self): self.store = await PoolStore.create() self.pending_point_partials = asyncio.Queue() print(self.config) self_hostname = self.config["self_hostname"] self.node_rpc_client = await FullNodeRpcClient.create( self_hostname, uint16(8555), DEFAULT_ROOT_PATH, self.config) self.wallet_rpc_client = await WalletRpcClient.create( self.config["self_hostname"], uint16(9256), DEFAULT_ROOT_PATH, self.config) await self.wallet_rpc_client.get_wallet_balance(self.wallet_id) self.scan_p2_singleton_puzzle_hashes = await self.store.get_pay_to_singleton_phs( ) self.confirm_partials_loop_task = asyncio.create_task( self.confirm_partials_loop()) self.collect_pool_rewards_loop_task = asyncio.create_task( self.collect_pool_rewards_loop()) self.create_payment_loop_task = asyncio.create_task( self.create_payment_loop()) self.submit_payment_loop_task = asyncio.create_task( self.submit_payment_loop()) self.pending_payments = asyncio.Queue()
def from_string(cls, peer_str: str): blobs = peer_str.split(" ") assert len(blobs) == 5 peer_info = TimestampedPeerInfo(blobs[0], uint16(int(blobs[1])), uint64(int(blobs[2]))) src_peer = PeerInfo(blobs[3], uint16(int(blobs[4]))) return cls(peer_info, src_peer)
async def wallets_prefarm(two_wallet_nodes): """ Sets up the node with 10 blocks, and returns a payer and payee wallet. """ farm_blocks = 10 buffer = 4 full_nodes, wallets = two_wallet_nodes full_node_api = full_nodes[0] full_node_server = full_node_api.server wallet_node_0, wallet_server_0 = wallets[0] wallet_node_1, wallet_server_1 = wallets[1] wallet_0 = wallet_node_0.wallet_state_manager.main_wallet wallet_1 = wallet_node_1.wallet_state_manager.main_wallet ph0 = await wallet_0.get_new_puzzlehash() ph1 = await wallet_1.get_new_puzzlehash() await wallet_server_0.start_client( PeerInfo("localhost", uint16(full_node_server._port)), None) await wallet_server_1.start_client( PeerInfo("localhost", uint16(full_node_server._port)), None) for i in range(0, farm_blocks): await full_node_api.farm_new_transaction_block( FarmNewBlockProtocol(ph0)) for i in range(0, farm_blocks): await full_node_api.farm_new_transaction_block( FarmNewBlockProtocol(ph1)) for i in range(0, buffer): await full_node_api.farm_new_transaction_block( FarmNewBlockProtocol(token_bytes())) return wallet_node_0, wallet_node_1, full_node_api
def get_name_puzzle_conditions( generator: BlockGenerator, max_cost: int, *, cost_per_byte: int, mempool_mode: bool ) -> NPCResult: block_program, block_program_args = setup_generator_args(generator) max_cost -= len(bytes(generator.program)) * cost_per_byte if max_cost < 0: return NPCResult(uint16(Err.INVALID_BLOCK_COST.value), [], uint64(0)) flags = MEMPOOL_MODE if mempool_mode else 0 try: err, result, clvm_cost = GENERATOR_MOD.run_as_generator(max_cost, flags, block_program, block_program_args) if err is not None: return NPCResult(uint16(err), [], uint64(0)) else: npc_list = [] for r in result: conditions = [] for c in r.conditions: cwa = [] for cond_list in c[1]: cwa.append(ConditionWithArgs(ConditionOpcode(bytes([cond_list.opcode])), cond_list.vars)) conditions.append((ConditionOpcode(bytes([c[0]])), cwa)) npc_list.append(NPC(r.coin_name, r.puzzle_hash, conditions)) return NPCResult(None, npc_list, uint64(clvm_cost)) except BaseException as e: log.debug(f"get_name_puzzle_condition failed: {e}") return NPCResult(uint16(Err.GENERATOR_RUNTIME_ERROR.value), [], uint64(0))
async def perform_handshake(self, network_id: str, protocol_version: str, server_port: int, local_type: NodeType): if self.is_outbound: outbound_handshake = make_msg( ProtocolMessageTypes.handshake, Handshake( network_id, protocol_version, chia_full_version_str(), uint16(server_port), uint8(local_type.value), [(uint16(Capability.BASE.value), "1")], ), ) assert outbound_handshake is not None await self._send_message(outbound_handshake) inbound_handshake_msg = await self._read_one_message() if inbound_handshake_msg is None: raise ProtocolError(Err.INVALID_HANDSHAKE) inbound_handshake = Handshake.from_bytes(inbound_handshake_msg.data) if ProtocolMessageTypes(inbound_handshake_msg.type) != ProtocolMessageTypes.handshake: raise ProtocolError(Err.INVALID_HANDSHAKE) if inbound_handshake.network_id != network_id: raise ProtocolError(Err.INCOMPATIBLE_NETWORK_ID) self.peer_server_port = inbound_handshake.server_port self.connection_type = NodeType(inbound_handshake.node_type) else: try: message = await self._read_one_message() except Exception: raise ProtocolError(Err.INVALID_HANDSHAKE) if message is None: raise ProtocolError(Err.INVALID_HANDSHAKE) inbound_handshake = Handshake.from_bytes(message.data) if ProtocolMessageTypes(message.type) != ProtocolMessageTypes.handshake: raise ProtocolError(Err.INVALID_HANDSHAKE) if inbound_handshake.network_id != network_id: raise ProtocolError(Err.INCOMPATIBLE_NETWORK_ID) outbound_handshake = make_msg( ProtocolMessageTypes.handshake, Handshake( network_id, protocol_version, chia_full_version_str(), uint16(server_port), uint8(local_type.value), [(uint16(Capability.BASE.value), "1")], ), ) await self._send_message(outbound_handshake) self.peer_server_port = inbound_handshake.server_port self.connection_type = NodeType(inbound_handshake.node_type) self.outbound_task = asyncio.create_task(self.outbound_handler()) self.inbound_task = asyncio.create_task(self.inbound_handler()) return True
async def test_generate_zero_val(self, two_wallet_nodes): num_blocks = 4 full_nodes, wallets = two_wallet_nodes full_node_api = full_nodes[0] full_node_server = full_node_api.server wallet_node, server_2 = wallets[0] wallet_node_2, server_3 = wallets[1] wallet = wallet_node.wallet_state_manager.main_wallet wallet2 = wallet_node_2.wallet_state_manager.main_wallet ph = await wallet.get_new_puzzlehash() await server_2.start_client(PeerInfo("localhost", uint16(full_node_server._port)), None) await server_3.start_client(PeerInfo("localhost", uint16(full_node_server._port)), None) for i in range(1, num_blocks): await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph)) funds = sum( [ calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks - 1) ] ) await time_out_assert(15, wallet.get_confirmed_balance, funds) cc_wallet: CCWallet = await CCWallet.create_new_cc(wallet_node.wallet_state_manager, wallet, uint64(100)) ph = await wallet2.get_new_puzzlehash() for i in range(1, num_blocks): await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph)) await time_out_assert(15, cc_wallet.get_confirmed_balance, 100) await time_out_assert(15, cc_wallet.get_unconfirmed_balance, 100) assert cc_wallet.cc_info.my_genesis_checker is not None colour = cc_wallet.get_colour() cc_wallet_2: CCWallet = await CCWallet.create_wallet_for_cc(wallet_node_2.wallet_state_manager, wallet2, colour) assert cc_wallet.cc_info.my_genesis_checker == cc_wallet_2.cc_info.my_genesis_checker spend_bundle = await cc_wallet_2.generate_zero_val_coin() await time_out_assert(15, tx_in_pool, True, full_node_api.full_node.mempool_manager, spend_bundle.name()) for i in range(1, num_blocks): await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph)) async def unspent_count(): unspent: List[WalletCoinRecord] = list( await cc_wallet_2.wallet_state_manager.get_spendable_coins_for_wallet(cc_wallet_2.id()) ) return len(unspent) await time_out_assert(15, unspent_count, 1) unspent: List[WalletCoinRecord] = list( await cc_wallet_2.wallet_state_manager.get_spendable_coins_for_wallet(cc_wallet_2.id()) ) assert unspent.pop().coin.amount == 0
async def validate_unfinished_block( self, block: UnfinishedBlock, skip_overflow_ss_validation=True ) -> PreValidationResult: if ( not self.contains_block(block.prev_header_hash) and not block.prev_header_hash == self.constants.GENESIS_CHALLENGE ): return PreValidationResult(uint16(Err.INVALID_PREV_BLOCK_HASH.value), None, None) unfinished_header_block = UnfinishedHeaderBlock( block.finished_sub_slots, block.reward_chain_block, block.challenge_chain_sp_proof, block.reward_chain_sp_proof, block.foliage, block.foliage_transaction_block, b"", ) prev_b = self.try_block_record(unfinished_header_block.prev_header_hash) sub_slot_iters, difficulty = get_next_sub_slot_iters_and_difficulty( self.constants, len(unfinished_header_block.finished_sub_slots) > 0, prev_b, self ) required_iters, error = validate_unfinished_header_block( self.constants, self, unfinished_header_block, False, difficulty, sub_slot_iters, skip_overflow_ss_validation, ) if error is not None: return PreValidationResult(uint16(error.code.value), None, None) prev_height = ( -1 if block.prev_header_hash == self.constants.GENESIS_CHALLENGE else self.block_record(block.prev_header_hash).height ) error_code, cost_result = await validate_block_body( self.constants, self, self.block_store, self.coin_store, self.get_peak(), block, uint32(prev_height + 1), None, ) if error_code is not None: return PreValidationResult(uint16(error_code.value), None, None) return PreValidationResult(None, required_iters, cost_result)
async def environment(simulation): harvester_service, farmer_service = simulation def stop_node_cb(): pass config = bt.config hostname = config["self_hostname"] daemon_port = config["daemon_port"] farmer_rpc_api = FarmerRpcApi(farmer_service._api.farmer) harvester_rpc_api = HarvesterRpcApi(harvester_service._node) rpc_port_farmer = uint16(21522) rpc_port_harvester = uint16(21523) rpc_cleanup = await start_rpc_server( farmer_rpc_api, hostname, daemon_port, rpc_port_farmer, stop_node_cb, bt.root_path, config, connect_to_daemon=False, ) rpc_cleanup_2 = await start_rpc_server( harvester_rpc_api, hostname, daemon_port, rpc_port_harvester, stop_node_cb, bt.root_path, config, connect_to_daemon=False, ) farmer_rpc_client = await FarmerRpcClient.create(self_hostname, rpc_port_farmer, bt.root_path, config) harvester_rpc_client = await HarvesterRpcClient.create( self_hostname, rpc_port_harvester, bt.root_path, config) async def have_connections(): return len(await farmer_rpc_client.get_connections()) > 0 await time_out_assert(15, have_connections, True) yield farmer_service, farmer_rpc_api, farmer_rpc_client, harvester_service, harvester_rpc_api, harvester_rpc_client farmer_rpc_client.close() harvester_rpc_client.close() await farmer_rpc_client.await_closed() await harvester_rpc_client.await_closed() await rpc_cleanup() await rpc_cleanup_2()
async def test_simulation_1(self, simulation, extra_node): node1, node2, _, _, _, _, _, _, _, sanitizer_server, server1 = simulation await server1.start_client(PeerInfo(self_hostname, uint16(21238))) # Use node2 to test node communication, since only node1 extends the chain. await time_out_assert(1500, node_height_at_least, True, node2, 7) await sanitizer_server.start_client( PeerInfo(self_hostname, uint16(21238))) async def has_compact(node1, node2): peak_height_1 = node1.full_node.blockchain.get_peak_height() headers_1 = await node1.full_node.blockchain.get_header_blocks_in_range( 0, peak_height_1 - 6) peak_height_2 = node2.full_node.blockchain.get_peak_height() headers_2 = await node2.full_node.blockchain.get_header_blocks_in_range( 0, peak_height_2 - 6) # Commented to speed up. # cc_eos = [False, False] # icc_eos = [False, False] # cc_sp = [False, False] # cc_ip = [False, False] has_compact = [False, False] for index, headers in enumerate([headers_1, headers_2]): for header in headers.values(): for sub_slot in header.finished_sub_slots: if sub_slot.proofs.challenge_chain_slot_proof.normalized_to_identity: # cc_eos[index] = True has_compact[index] = True if (sub_slot.proofs.infused_challenge_chain_slot_proof is not None and sub_slot.proofs. infused_challenge_chain_slot_proof. normalized_to_identity): # icc_eos[index] = True has_compact[index] = True if (header.challenge_chain_sp_proof is not None and header. challenge_chain_sp_proof.normalized_to_identity): # cc_sp[index] = True has_compact[index] = True if header.challenge_chain_ip_proof.normalized_to_identity: # cc_ip[index] = True has_compact[index] = True # return ( # cc_eos == [True, True] and icc_eos == [True, True] and cc_sp == [True, True] and cc_ip == [True, True] # ) return has_compact == [True, True] await time_out_assert(1500, has_compact, True, node1, node2) node3 = extra_node server3 = node3.full_node.server peak_height = max(node1.full_node.blockchain.get_peak_height(), node2.full_node.blockchain.get_peak_height()) await server3.start_client(PeerInfo(self_hostname, uint16(21237))) await server3.start_client(PeerInfo(self_hostname, uint16(21238))) await time_out_assert(600, node_height_at_least, True, node3, peak_height)
async def check_node_alive(node: Node) -> Tuple[bool, Node]: ssl_context = ssl_context_for_server('keys/chia_ca.crt', 'keys/chia_ca.key', 'keys/public_full_node.crt', 'keys/public_full_node.key') try: # TODO: connect and timeout in one shot, don't do it in two connections await asyncio.wait_for(websockets.connect(node.get_websocket_url(), ssl=ssl_context), timeout=10) async with websockets.connect(node.get_websocket_url(), ssl=ssl_context) as websocket: handshake = make_msg( ProtocolMessageTypes.handshake, Handshake( 'mainnet', protocol_version, '0.0.0', uint16(8884), uint8(NodeType.INTRODUCER), [(uint16(Capability.BASE.value), '1')], )) encoded_handshake = bytes(handshake) await websocket.send(encoded_handshake) message = await websocket.recv() if message is None: logging.warning('Node ' + node.ip + ' did not return anything') return False, node full_message_loaded = Message.from_bytes(message) inbound_handshake = Handshake.from_bytes(full_message_loaded.data) await websocket.close() if inbound_handshake.network_id != 'mainnet': logging.warning('Node ' + node.ip + ' is not on main net but is on mainnet port!') return False, node logging.info('Node ' + node.ip + ' is up.') return True, node except websockets.exceptions.ConnectionClosed as e: logging.warning('Node closed the connection') return False, node except asyncio.exceptions.TimeoutError as e: logging.warning('Node timeout : ' + node.ip) return False, node except websockets.exceptions.InvalidMessage as e: return False, node except OSError as e: return False, node except Exception as e: logging.error(e) traceback.print_exc() return False, node
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 create_request(self, message_no_id: Message, timeout: int) -> Optional[Message]: """Sends a message and waits for a response.""" if self.closed: return None # We will wait for this event, it will be set either by the response, or the timeout event = asyncio.Event() # The request nonce is an integer between 0 and 2**16 - 1, which is used to match requests to responses # If is_outbound, 0 <= nonce < 2^15, else 2^15 <= nonce < 2^16 request_id = self.request_nonce if self.is_outbound: self.request_nonce = uint16(self.request_nonce + 1) if self.request_nonce != ( 2**15 - 1) else uint16(0) else: self.request_nonce = (uint16(self.request_nonce + 1) if self.request_nonce != (2**16 - 1) else uint16(2**15)) message = Message(message_no_id.type, request_id, message_no_id.data) self.pending_requests[message.id] = event await self.outgoing_queue.put(message) # If the timeout passes, we set the event async def time_out(req_id, req_timeout): try: await asyncio.sleep(req_timeout) if req_id in self.pending_requests: self.pending_requests[req_id].set() except asyncio.CancelledError: if req_id in self.pending_requests: self.pending_requests[req_id].set() raise timeout_task = asyncio.create_task(time_out(message.id, timeout)) self.pending_timeouts[message.id] = timeout_task await event.wait() self.pending_requests.pop(message.id) result: Optional[Message] = None if message.id in self.request_results: result = self.request_results[message.id] assert result is not None self.log.debug( f"<- {ProtocolMessageTypes(result.type).name} from: {self.peer_host}:{self.peer_port}" ) self.request_results.pop(result.id) return result
async def start(self): self.store = await PoolStore.create() self.pending_point_partials = asyncio.Queue() self.full_node_client = await FullNodeRpcClient.create( self.config["self_hostname"], uint16(8555), DEFAULT_ROOT_PATH, self.config) self.confirm_partials_loop_task = asyncio.create_task( self.confirm_partials_loop()) self_hostname = self.config["self_hostname"] self.node_rpc_client = await FullNodeRpcClient.create( self_hostname, uint16(8555), DEFAULT_ROOT_PATH, self.config) self.scan_p2_singleton_puzzle_hashes = await self.store.get_pay_to_singleton_phs( )
async def test_wallet_send_to_three_peers(self, three_sim_two_wallets): num_blocks = 10 full_nodes, wallets = three_sim_two_wallets wallet_0, wallet_server_0 = wallets[0] full_node_api_0 = full_nodes[0] full_node_api_1 = full_nodes[1] full_node_api_2 = full_nodes[2] full_node_0 = full_node_api_0.full_node full_node_1 = full_node_api_1.full_node full_node_2 = full_node_api_2.full_node server_0 = full_node_0.server server_1 = full_node_1.server server_2 = full_node_2.server ph = await wallet_0.wallet_state_manager.main_wallet.get_new_puzzlehash() # wallet0 <-> sever0 await wallet_server_0.start_client(PeerInfo(self_hostname, uint16(server_0._port)), None) for i in range(0, num_blocks): await full_node_api_0.farm_new_transaction_block(FarmNewBlockProtocol(ph)) all_blocks = await full_node_api_0.get_all_full_blocks() for block in all_blocks: await full_node_1.respond_block(RespondBlock(block)) await full_node_2.respond_block(RespondBlock(block)) 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_0.wallet_state_manager.main_wallet.get_confirmed_balance, funds) tx = await wallet_0.wallet_state_manager.main_wallet.generate_signed_transaction(10, 32 * b"0", 0) await wallet_0.wallet_state_manager.main_wallet.push_transaction(tx) await time_out_assert_not_none(5, full_node_0.mempool_manager.get_spendbundle, tx.spend_bundle.name()) # wallet0 <-> sever1 await wallet_server_0.start_client(PeerInfo(self_hostname, uint16(server_1._port)), wallet_0.on_connect) await time_out_assert_not_none(5, full_node_1.mempool_manager.get_spendbundle, tx.spend_bundle.name()) # wallet0 <-> sever2 await wallet_server_0.start_client(PeerInfo(self_hostname, uint16(server_2._port)), wallet_0.on_connect) await time_out_assert_not_none(5, full_node_2.mempool_manager.get_spendbundle, tx.spend_bundle.name())
def batch_pre_validate_blocks( constants_dict: Dict, blocks_pickled: Dict[bytes, bytes], header_blocks_pickled: List[bytes], transaction_generators: List[Optional[bytes]], check_filter: bool, expected_difficulty: List[uint64], expected_sub_slot_iters: List[uint64], validate_transactions: bool, ) -> List[bytes]: assert len(header_blocks_pickled) == len(transaction_generators) blocks = {} for k, v in blocks_pickled.items(): blocks[k] = BlockRecord.from_bytes(v) results: List[PreValidationResult] = [] constants: ConsensusConstants = dataclass_from_dict( ConsensusConstants, constants_dict) for i in range(len(header_blocks_pickled)): try: header_block: HeaderBlock = HeaderBlock.from_bytes( header_blocks_pickled[i]) generator: Optional[bytes] = transaction_generators[i] required_iters, error = validate_finished_header_block( constants, BlockCache(blocks), header_block, check_filter, expected_difficulty[i], expected_sub_slot_iters[i], ) cost_result: Optional[CostResult] = None error_int: Optional[uint16] = None if error is not None: error_int = uint16(error.code.value) if constants_dict["NETWORK_TYPE"] == NetworkType.MAINNET.value: cost_result = None else: if not error and generator is not None and validate_transactions: cost_result = calculate_cost_of_program( SerializedProgram.from_bytes(generator), constants.CLVM_COST_RATIO_CONSTANT) results.append( PreValidationResult(error_int, required_iters, cost_result)) except Exception: error_stack = traceback.format_exc() log.error(f"Exception: {error_stack}") results.append( PreValidationResult(uint16(Err.UNKNOWN.value), None, None)) return [bytes(r) for r in results]
async def test_did_recovery_with_empty_set(self, two_wallet_nodes): num_blocks = 5 full_nodes, wallets = two_wallet_nodes full_node_1 = full_nodes[0] server_1 = full_node_1.server wallet_node, server_2 = wallets[0] wallet_node_2, server_3 = wallets[1] wallet = wallet_node.wallet_state_manager.main_wallet ph = await wallet.get_new_puzzlehash() await server_2.start_client( PeerInfo("localhost", uint16(server_1._port)), None) await server_3.start_client( PeerInfo("localhost", uint16(server_1._port)), None) for i in range(1, num_blocks): await full_node_1.farm_new_transaction_block( FarmNewBlockProtocol(ph)) funds = sum([ calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks - 1) ]) await time_out_assert(15, wallet.get_confirmed_balance, funds) async with wallet_node.wallet_state_manager.lock: did_wallet: DIDWallet = await DIDWallet.create_new_did_wallet( wallet_node.wallet_state_manager, wallet, uint64(101)) for i in range(1, num_blocks): await full_node_1.farm_new_transaction_block( FarmNewBlockProtocol(ph)) await time_out_assert(15, did_wallet.get_confirmed_balance, 101) await time_out_assert(15, did_wallet.get_unconfirmed_balance, 101) coins = await did_wallet.select_coins(1) coin = coins.pop() info = Program.to([]) pubkey = (await did_wallet.wallet_state_manager.get_unused_derivation_record( did_wallet.wallet_info.id)).pubkey spend_bundle = await did_wallet.recovery_spend( coin, ph, info, pubkey, SpendBundle([], AugSchemeMPL.aggregate([]))) additions = spend_bundle.additions() assert additions == []
async def get_peer_info(self) -> Optional[PeerInfo]: ip = None port = self._port # Use chia's service first. try: timeout = ClientTimeout(total=15) async with ClientSession(timeout=timeout) as session: async with session.get("https://ip.chia.net/") as resp: if resp.status == 200: ip = str(await resp.text()) ip = ip.rstrip() except Exception: ip = None # Fallback to `checkip` from amazon. if ip is None: try: timeout = ClientTimeout(total=15) async with ClientSession(timeout=timeout) as session: async with session.get( "https://checkip.amazonaws.com/") as resp: if resp.status == 200: ip = str(await resp.text()) ip = ip.rstrip() except Exception: ip = None if ip is None: return None peer = PeerInfo(ip, uint16(port)) if not peer.is_valid(): return None return peer
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 execute_with_wallet(wallet_rpc_port: int, fingerprint: int, extra_params: dict, function: Callable) -> None: try: config = load_config(DEFAULT_ROOT_PATH, "config.yaml") self_hostname = config["self_hostname"] if wallet_rpc_port is None: wallet_rpc_port = config["wallet"]["rpc_port"] wallet_client = await WalletRpcClient.create(self_hostname, uint16(wallet_rpc_port), DEFAULT_ROOT_PATH, config) wallet_client_f = await get_wallet(wallet_client, fingerprint=fingerprint) if wallet_client_f is None: wallet_client.close() await wallet_client.await_closed() return wallet_client, fingerprint = wallet_client_f await function(extra_params, wallet_client, fingerprint) except KeyboardInterrupt: pass except Exception as e: if isinstance(e, aiohttp.ClientConnectorError): print( f"Connection error. Check if wallet is running at {wallet_rpc_port}" ) else: print(f"Exception from 'wallet' {e}") wallet_client.close() await wallet_client.await_closed()
async def disconnect_all_and_reconnect(server: ChiaServer, reconnect_to: ChiaServer) -> bool: cons = list(server.all_connections.values())[:] for con in cons: await con.close() return await server.start_client( PeerInfo(self_hostname, uint16(reconnect_to._port)), None)
async def test_wallet_coinbase_reorg(self, wallet_node): num_blocks = 5 full_nodes, wallets = wallet_node full_node_api = full_nodes[0] fn_server = full_node_api.full_node.server wallet_node, server_2 = wallets[0] 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) for i in range(0, num_blocks): await full_node_api.farm_new_transaction_block( FarmNewBlockProtocol(ph)) 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) await full_node_api.reorg_from_index_to_new_index( ReorgProtocol(uint32(3), uint32(num_blocks + 6), 32 * b"0")) funds = sum([ calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks - 2) ]) await time_out_assert(5, wallet.get_confirmed_balance, funds)
async def test_get_wallet_for_colour(self, two_wallet_nodes): num_blocks = 3 full_nodes, wallets = two_wallet_nodes full_node_api = full_nodes[0] full_node_server = full_node_api.server wallet_node, server_2 = wallets[0] wallet = wallet_node.wallet_state_manager.main_wallet ph = await wallet.get_new_puzzlehash() await server_2.start_client( PeerInfo("localhost", uint16(full_node_server._port)), None) for i in range(1, num_blocks): await full_node_api.farm_new_transaction_block( FarmNewBlockProtocol(ph)) funds = sum([ calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks - 1) ]) await time_out_assert(15, wallet.get_confirmed_balance, funds) cc_wallet: CCWallet = await CCWallet.create_new_cc( wallet_node.wallet_state_manager, wallet, uint64(100)) for i in range(1, num_blocks): await full_node_api.farm_new_transaction_block( FarmNewBlockProtocol(32 * b"0")) colour = cc_wallet.get_colour() assert await wallet_node.wallet_state_manager.get_wallet_for_colour( colour) == cc_wallet
async def get_login_link(launcher_id_str: str) -> None: launcher_id: bytes32 = bytes32.from_hexstr(launcher_id_str) config = load_config(DEFAULT_ROOT_PATH, "config.yaml") self_hostname = config["self_hostname"] farmer_rpc_port = config["farmer"]["rpc_port"] farmer_client = await FarmerRpcClient.create(self_hostname, uint16(farmer_rpc_port), DEFAULT_ROOT_PATH, config) try: login_link: Optional[str] = await farmer_client.get_pool_login_link( launcher_id) if login_link is None: print("Was not able to get login link.") else: print(login_link) except Exception as e: if isinstance(e, aiohttp.ClientConnectorError): print( f"Connection error. Check if farmer is running at {farmer_rpc_port}." f" You can run the farmer by:\n chia start farmer-only") else: print(f"Exception from 'farmer' {e}") finally: farmer_client.close() await farmer_client.await_closed()
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 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)
def get_host_addr(host: Union[PeerInfo, str], prefer_ipv6: Optional[bool]) -> str: # If there was no preference passed in (from config), set the system-wise # default here. Not a great place to locate a default value, and we should # probabaly do something to write it into the config, but. For now... if prefer_ipv6 is None: prefer_ipv6 = False # Use PeerInfo.is_valid() to see if it's already an address if isinstance(host, PeerInfo): hoststr = host.host if host.is_valid(True): return hoststr else: hoststr = host if PeerInfo(hoststr, uint16(0)).is_valid(True): return hoststr addrset: List[Tuple["socket.AddressFamily", "socket.SocketKind", int, str, Union[Tuple[str, int], Tuple[str, int, int, int]]]] = socket.getaddrinfo( hoststr, None) # Addrset is never empty, an exception is thrown or data is returned. for t in addrset: if prefer_ipv6 and t[0] == socket.AF_INET6: return t[4][0] if not prefer_ipv6 and t[0] == socket.AF_INET: return t[4][0] # If neither matched preference, just return the first available return addrset[0][4][0]