async def main(): rpc_port = 8555 self_hostname = "localhost" path = DEFAULT_ROOT_PATH config = load_config(path, "config.yaml") client = await FullNodeRpcClient.create(self_hostname, rpc_port, path, config) try: farmer_prefarm = ( await client.get_block_record_by_height(1)).reward_claims_incorporated[1] pool_prefarm = ( await client.get_block_record_by_height(1)).reward_claims_incorporated[0] pool_amounts = int(calculate_pool_reward(uint32(0)) / 2) farmer_amounts = int(calculate_base_farmer_reward(uint32(0)) / 2) print(farmer_prefarm.amount, farmer_amounts) assert farmer_amounts == farmer_prefarm.amount // 2 assert pool_amounts == pool_prefarm.amount // 2 address1 = "txch15gx26ndmacfaqlq8m0yajeggzceu7cvmaz4df0hahkukes695rss6lej7h" # Gene wallet (m/12381/8444/2/42): address2 = ( "txch1c2cguswhvmdyz9hr3q6hak2h6p9dw4rz82g4707k2xy2sarv705qcce4pn" # Mariano address (m/12381/8444/2/0) ) ph1 = decode_puzzle_hash(address1) ph2 = decode_puzzle_hash(address2) p_farmer_2 = Program.to( binutils.assemble( f"(q . ((51 0x{ph1.hex()} {farmer_amounts}) (51 0x{ph2.hex()} {farmer_amounts})))" )) p_pool_2 = Program.to( binutils.assemble( f"(q . ((51 0x{ph1.hex()} {pool_amounts}) (51 0x{ph2.hex()} {pool_amounts})))" )) p_solution = Program.to(binutils.assemble("()")) sb_farmer = SpendBundle( [CoinSolution(farmer_prefarm, p_farmer_2, p_solution)], G2Element()) sb_pool = SpendBundle( [CoinSolution(pool_prefarm, p_pool_2, p_solution)], G2Element()) print(sb_pool, sb_farmer) # res = await client.push_tx(sb_farmer) res = await client.push_tx(sb_pool) print(res) up = await client.get_coin_records_by_puzzle_hash( farmer_prefarm.puzzle_hash, True) uf = await client.get_coin_records_by_puzzle_hash( pool_prefarm.puzzle_hash, True) print(up) print(uf) finally: client.close()
async def main(): rpc_port = 8555 self_hostname = "localhost" path = DEFAULT_ROOT_PATH config = load_config(path, "config.yaml") client = await FullNodeRpcClient.create(self_hostname, rpc_port, path, config) try: farmer_prefarm = ( await client.get_block_record_by_height(1)).reward_claims_incorporated[1] pool_prefarm = ( await client.get_block_record_by_height(1)).reward_claims_incorporated[0] pool_amounts = int(calculate_pool_reward(uint32(0)) / 2) farmer_amounts = int(calculate_base_farmer_reward(uint32(0)) / 2) print(farmer_prefarm.amount, farmer_amounts) assert farmer_amounts == farmer_prefarm.amount // 2 assert pool_amounts == pool_prefarm.amount // 2 address1 = "txch1k50glwkdffp2mrqq64rsgjtxj4waphuf72stqayz4qqk6mj9hd4qp7lrek" # Gene wallet (m/12381/8444/2/51): address2 = "txch1430mtj60hvzyuyz4t45dyxwjdjsvphhl2fgreyry362reca4zpkszhjd3e" # farmer1 key (m/12381/8444/2/51) ph1 = decode_puzzle_hash(address1) ph2 = decode_puzzle_hash(address2) p_farmer_2 = Program.to( binutils.assemble( f"(q . ((51 0x{ph1.hex()} {farmer_amounts}) (51 0x{ph2.hex()} {farmer_amounts})))" )) p_pool_2 = Program.to( binutils.assemble( f"(q . ((51 0x{ph1.hex()} {pool_amounts}) (51 0x{ph2.hex()} {pool_amounts})))" )) p_solution = Program.to(binutils.assemble("()")) sb_farmer = SpendBundle( [CoinSolution(farmer_prefarm, p_farmer_2, p_solution)], G2Element()) sb_pool = SpendBundle( [CoinSolution(pool_prefarm, p_pool_2, p_solution)], G2Element()) print(sb_pool, sb_farmer) # res = await client.push_tx(sb_farmer) # res = await client.push_tx(sb_pool) # print(res) up = await client.get_coin_records_by_puzzle_hash( farmer_prefarm.puzzle_hash, True) uf = await client.get_coin_records_by_puzzle_hash( pool_prefarm.puzzle_hash, True) print(up) print(uf) finally: client.close()
def __init__( self, farmer_config: Dict, pool_config: Dict, keychain: Keychain, consensus_constants: ConsensusConstants, ): self.config = farmer_config # Keep track of all sps, keyed on challenge chain signage point hash self.sps: Dict[bytes32, List[farmer_protocol.NewSignagePoint]] = {} # Keep track of harvester plot identifier (str), target sp index, and PoSpace for each challenge self.proofs_of_space: Dict[bytes32, List[Tuple[str, ProofOfSpace]]] = {} # Quality string to plot identifier and challenge_hash, for use with harvester.RequestSignatures self.quality_str_to_identifiers: Dict[bytes32, Tuple[str, bytes32, bytes32, bytes32]] = {} # number of responses to each signage point self.number_of_responses: Dict[bytes32, int] = {} # A dictionary of keys to time added. These keys refer to keys in the above 4 dictionaries. This is used # to periodically clear the memory self.cache_add_time: Dict[bytes32, uint64] = {} self.cache_clear_task: asyncio.Task self.constants = consensus_constants self._shut_down = False self.server: Any = None self.keychain = keychain self.state_changed_callback: Optional[Callable] = None self.log = log all_sks = self.keychain.get_all_private_keys() self._private_keys = [master_sk_to_farmer_sk(sk) for sk, _ in all_sks] + [ master_sk_to_pool_sk(sk) for sk, _ in all_sks ] if len(self.get_public_keys()) == 0: error_str = "No keys exist. Please run 'chia keys generate' or open the UI." raise RuntimeError(error_str) # This is the farmer configuration self.wallet_target = decode_puzzle_hash(self.config["xch_target_address"]) self.pool_public_keys = [G1Element.from_bytes(bytes.fromhex(pk)) for pk in self.config["pool_public_keys"]] # This is the pool configuration, which should be moved out to the pool once it exists self.pool_target = decode_puzzle_hash(pool_config["xch_target_address"]) self.pool_sks_map: Dict = {} for key in self.get_private_keys(): self.pool_sks_map[bytes(key.get_g1())] = key assert len(self.wallet_target) == 32 assert len(self.pool_target) == 32 if len(self.pool_sks_map) == 0: error_str = "No keys exist. Please run 'chia keys generate' or open the UI." raise RuntimeError(error_str)
def set_reward_targets(self, farmer_target_encoded: Optional[str], pool_target_encoded: Optional[str]): config = load_config(self._root_path, "config.yaml") if farmer_target_encoded is not None: self.farmer_target_encoded = farmer_target_encoded self.farmer_target = decode_puzzle_hash(farmer_target_encoded) config["farmer"]["xch_target_address"] = farmer_target_encoded if pool_target_encoded is not None: self.pool_target_encoded = pool_target_encoded self.pool_target = decode_puzzle_hash(pool_target_encoded) config["pool"]["xch_target_address"] = pool_target_encoded save_config(self._root_path, "config.yaml", config)
async def farm_block(self, request): raw_puzzle_hash = decode_puzzle_hash(request["address"]) request = FarmNewBlockProtocol(raw_puzzle_hash) msg = make_msg(ProtocolMessageTypes.farm_new_block, request) await self.service.server.send_to_all([msg], NodeType.FULL_NODE) return {}
async def send_transaction(self, request): assert self.service.wallet_state_manager is not None wallet_id = int(request["wallet_id"]) wallet = self.service.wallet_state_manager.wallets[wallet_id] if not isinstance(request["amount"], int) or not isinstance( request["amount"], int): raise ValueError( "An integer amount or fee is required (too many decimals)") amount: uint64 = uint64(request["amount"]) puzzle_hash: bytes32 = decode_puzzle_hash(request["address"]) if "fee" in request: fee = uint64(request["fee"]) else: fee = uint64(0) tx: TransactionRecord = await wallet.generate_signed_transaction( amount, puzzle_hash, fee) await wallet.push_transaction(tx) # Transaction may not have been included in the mempool yet. Use get_transaction to check. return { "transaction": tx, "transaction_id": tx.name, }
async def get_transactions( self, wallet_id: str, ) -> List[TransactionRecord]: res = await self.fetch( "get_transactions", {"wallet_id": wallet_id}, ) reverted_tx: List[TransactionRecord] = [] for modified_tx in res["transactions"]: # Server returns address instead of ph, but TransactionRecord requires ph modified_tx["to_puzzle_hash"] = decode_puzzle_hash(modified_tx["to_address"]).hex() del modified_tx["to_address"] reverted_tx.append(TransactionRecord.from_json_dict(modified_tx)) return reverted_tx
async def send_transaction(self, request): assert self.service.wallet_state_manager is not None if await self.service.wallet_state_manager.synced() is False: raise ValueError( "Wallet needs to be fully synced before sending transactions") if (self.service.wallet_state_manager.blockchain.get_peak_height() < self.service.constants.INITIAL_FREEZE_PERIOD): raise ValueError( f"No transactions before block height: {self.service.constants.INITIAL_FREEZE_PERIOD}" ) if self.service.constants.NETWORK_TYPE is NetworkType.MAINNET: raise ValueError( "Sending transactions not supported, please update your client." ) wallet_id = int(request["wallet_id"]) wallet = self.service.wallet_state_manager.wallets[wallet_id] if not isinstance(request["amount"], int) or not isinstance( request["amount"], int): raise ValueError( "An integer amount or fee is required (too many decimals)") amount: uint64 = uint64(request["amount"]) puzzle_hash: bytes32 = decode_puzzle_hash(request["address"]) if "fee" in request: fee = uint64(request["fee"]) else: fee = uint64(0) tx: TransactionRecord = await wallet.generate_signed_transaction( amount, puzzle_hash, fee) await wallet.push_transaction(tx) # Transaction may not have been included in the mempool yet. Use get_transaction to check. return { "transaction": tx, "transaction_id": tx.name, }
async def cc_spend(self, request): assert self.service.wallet_state_manager is not None wallet_id = int(request["wallet_id"]) wallet: CCWallet = self.service.wallet_state_manager.wallets[wallet_id] puzzle_hash: bytes32 = decode_puzzle_hash(request["inner_address"]) if not isinstance(request["amount"], int) or not isinstance(request["amount"], int): raise ValueError("An integer amount or fee is required (too many decimals)") amount: uint64 = uint64(request["amount"]) if "fee" in request: fee = uint64(request["fee"]) else: fee = uint64(0) tx: TransactionRecord = await wallet.generate_signed_transaction([amount], [puzzle_hash], fee) await wallet.wallet_state_manager.add_pending_transaction(tx) return { "transaction": tx, "transaction_id": tx.name, }
async def test1(self, simulation): test_rpc_port = uint16(21522) test_rpc_port_2 = uint16(21523) harvester, farmer_api = simulation def stop_node_cb(): pass def stop_node_cb_2(): pass config = bt.config hostname = config["self_hostname"] daemon_port = config["daemon_port"] farmer_rpc_api = FarmerRpcApi(farmer_api.farmer) harvester_rpc_api = HarvesterRpcApi(harvester) rpc_cleanup = await start_rpc_server( farmer_rpc_api, hostname, daemon_port, test_rpc_port, stop_node_cb, bt.root_path, config, connect_to_daemon=False, ) rpc_cleanup_2 = await start_rpc_server( harvester_rpc_api, hostname, daemon_port, test_rpc_port_2, stop_node_cb_2, bt.root_path, config, connect_to_daemon=False, ) try: client = await FarmerRpcClient.create(self_hostname, test_rpc_port, bt.root_path, config) client_2 = await HarvesterRpcClient.create(self_hostname, test_rpc_port_2, bt.root_path, config) async def have_connections(): return len(await client.get_connections()) > 0 await time_out_assert(15, have_connections, True) assert (await client.get_signage_point(std_hash(b"2"))) is None assert len(await client.get_signage_points()) == 0 async def have_signage_points(): return len(await client.get_signage_points()) > 0 sp = farmer_protocol.NewSignagePoint(std_hash(b"1"), std_hash(b"2"), std_hash(b"3"), uint64(1), uint64(1000000), uint8(2)) await farmer_api.new_signage_point(sp) await time_out_assert(5, have_signage_points, True) assert (await client.get_signage_point(std_hash(b"2"))) is not None async def have_plots(): return len((await client_2.get_plots())["plots"]) > 0 await time_out_assert(5, have_plots, True) res = await client_2.get_plots() num_plots = len(res["plots"]) assert num_plots > 0 plot_dir = get_plot_dir() / "subdir" plot_dir.mkdir(parents=True, exist_ok=True) plot_dir_sub = get_plot_dir() / "subdir" / "subsubdir" plot_dir_sub.mkdir(parents=True, exist_ok=True) plotter = DiskPlotter() filename = "test_farmer_harvester_rpc_plot.plot" filename_2 = "test_farmer_harvester_rpc_plot2.plot" plotter.create_plot_disk( str(plot_dir), str(plot_dir), str(plot_dir), filename, 18, stream_plot_info_pk(bt.pool_pk, bt.farmer_pk, AugSchemeMPL.key_gen(bytes([4] * 32))), token_bytes(32), 128, 0, 2000, 0, False, ) # Making a plot with a puzzle hash encoded into it instead of pk plot_id_2 = token_bytes(32) plotter.create_plot_disk( str(plot_dir), str(plot_dir), str(plot_dir), filename_2, 18, stream_plot_info_ph(std_hash(b"random ph"), bt.farmer_pk, AugSchemeMPL.key_gen(bytes([5] * 32))), plot_id_2, 128, 0, 2000, 0, False, ) # Making the same plot, in a different dir. This should not be farmed plotter.create_plot_disk( str(plot_dir_sub), str(plot_dir_sub), str(plot_dir_sub), filename_2, 18, stream_plot_info_ph(std_hash(b"random ph"), bt.farmer_pk, AugSchemeMPL.key_gen(bytes([5] * 32))), plot_id_2, 128, 0, 2000, 0, False, ) res_2 = await client_2.get_plots() assert len(res_2["plots"]) == num_plots assert len(await client_2.get_plot_directories()) == 1 await client_2.add_plot_directory(str(plot_dir)) await client_2.add_plot_directory(str(plot_dir_sub)) assert len(await client_2.get_plot_directories()) == 3 res_2 = await client_2.get_plots() assert len(res_2["plots"]) == num_plots + 2 await client_2.delete_plot(str(plot_dir / filename)) await client_2.delete_plot(str(plot_dir / filename_2)) res_3 = await client_2.get_plots() assert len(res_3["plots"]) == num_plots await client_2.remove_plot_directory(str(plot_dir)) assert len(await client_2.get_plot_directories()) == 2 targets_1 = await client.get_reward_targets(False) assert "have_pool_sk" not in targets_1 assert "have_farmer_sk" not in targets_1 targets_2 = await client.get_reward_targets(True) assert targets_2["have_pool_sk"] and targets_2["have_farmer_sk"] new_ph: bytes32 = create_puzzlehash_for_pk( master_sk_to_wallet_sk(bt.farmer_master_sk, uint32(10)).get_g1()) new_ph_2: bytes32 = create_puzzlehash_for_pk( master_sk_to_wallet_sk(bt.pool_master_sk, uint32(472)).get_g1()) await client.set_reward_targets( encode_puzzle_hash(new_ph, "xch"), encode_puzzle_hash(new_ph_2, "xch")) targets_3 = await client.get_reward_targets(True) assert decode_puzzle_hash(targets_3["farmer_target"]) == new_ph assert decode_puzzle_hash(targets_3["pool_target"]) == new_ph_2 assert targets_3["have_pool_sk"] and targets_3["have_farmer_sk"] new_ph_3: bytes32 = create_puzzlehash_for_pk( master_sk_to_wallet_sk(bt.pool_master_sk, uint32(1888)).get_g1()) await client.set_reward_targets( None, encode_puzzle_hash(new_ph_3, "xch")) targets_4 = await client.get_reward_targets(True) assert decode_puzzle_hash(targets_4["farmer_target"]) == new_ph assert decode_puzzle_hash(targets_4["pool_target"]) == new_ph_3 assert not targets_4["have_pool_sk"] and targets_3["have_farmer_sk"] root_path = farmer_api.farmer._root_path config = load_config(root_path, "config.yaml") assert config["farmer"][ "xch_target_address"] == encode_puzzle_hash(new_ph, "xch") assert config["pool"]["xch_target_address"] == encode_puzzle_hash( new_ph_3, "xch") new_ph_3_encoded = encode_puzzle_hash(new_ph_3, "xch") added_char = new_ph_3_encoded + "a" with pytest.raises(ValueError): await client.set_reward_targets(None, added_char) replaced_char = new_ph_3_encoded[0:-1] + "a" with pytest.raises(ValueError): await client.set_reward_targets(None, replaced_char) finally: # Checks that the RPC manages to stop the node client.close() client_2.close() await client.await_closed() await client_2.await_closed() await rpc_cleanup() await rpc_cleanup_2()
def create_plots(args, root_path, use_datetime=True, test_private_keys: Optional[List] = None): config_filename = config_path_for_filename(root_path, "config.yaml") config = load_config(root_path, config_filename) if args.tmp2_dir is None: args.tmp2_dir = args.tmp_dir farmer_public_key: G1Element if args.farmer_public_key is not None: farmer_public_key = G1Element.from_bytes( bytes.fromhex(args.farmer_public_key)) else: farmer_public_key = get_farmer_public_key(args.alt_fingerprint) pool_public_key: Optional[G1Element] = None pool_contract_puzzle_hash: Optional[bytes32] = None if args.pool_public_key is not None: if args.pool_contract_address is not None: raise RuntimeError( "Choose one of pool_contract_address and pool_public_key") pool_public_key = G1Element.from_bytes( bytes.fromhex(args.pool_public_key)) else: if args.pool_contract_address is None: # If nothing is set, farms to the provided key (or the first key) pool_public_key = get_pool_public_key(args.alt_fingerprint) else: # If the pool contract puzzle hash is set, use that pool_contract_puzzle_hash = decode_puzzle_hash( args.pool_contract_address) assert (pool_public_key is None) != (pool_contract_puzzle_hash is None) num = args.num if args.size < config["min_mainnet_k_size"] and test_private_keys is None: log.warning( f"Creating plots with size k={args.size}, which is less than the minimum required for mainnet" ) if args.size < 22: log.warning("k under 22 is not supported. Increasing k to 22") args.size = 22 if pool_public_key is not None: log.info( f"Creating {num} plots of size {args.size}, pool public key: " f"{bytes(pool_public_key).hex()} farmer public key: {bytes(farmer_public_key).hex()}" ) else: assert pool_contract_puzzle_hash is not None log.info( f"Creating {num} plots of size {args.size}, pool contract address: " f"{args.pool_contract_address} farmer public key: {bytes(farmer_public_key).hex()}" ) tmp_dir_created = False if not args.tmp_dir.exists(): mkdir(args.tmp_dir) tmp_dir_created = True tmp2_dir_created = False if not args.tmp2_dir.exists(): mkdir(args.tmp2_dir) tmp2_dir_created = True mkdir(args.final_dir) finished_filenames = [] for i in range(num): # Generate a random master secret key if test_private_keys is not None: assert len(test_private_keys) == num sk: PrivateKey = test_private_keys[i] else: sk = AugSchemeMPL.key_gen(token_bytes(32)) # The plot public key is the combination of the harvester and farmer keys plot_public_key = ProofOfSpace.generate_plot_public_key( master_sk_to_local_sk(sk).get_g1(), farmer_public_key) # The plot id is based on the harvester, farmer, and pool keys if pool_public_key is not None: plot_id: bytes32 = ProofOfSpace.calculate_plot_id_pk( pool_public_key, plot_public_key) plot_memo: bytes32 = stream_plot_info_pk(pool_public_key, farmer_public_key, sk) else: assert pool_contract_puzzle_hash is not None plot_id = ProofOfSpace.calculate_plot_id_ph( pool_contract_puzzle_hash, plot_public_key) plot_memo = stream_plot_info_ph(pool_contract_puzzle_hash, farmer_public_key, sk) if args.plotid is not None: log.info(f"Debug plot ID: {args.plotid}") plot_id = bytes32(bytes.fromhex(args.plotid)) if args.memo is not None: log.info(f"Debug memo: {args.memo}") plot_memo = bytes.fromhex(args.memo) # Uncomment next two lines if memo is needed for dev debug plot_memo_str: str = plot_memo.hex() log.info(f"Memo: {plot_memo_str}") dt_string = datetime.now().strftime("%Y-%m-%d-%H-%M") if use_datetime: filename: str = f"plot-k{args.size}-{dt_string}-{plot_id}.plot" else: filename = f"plot-k{args.size}-{plot_id}.plot" full_path: Path = args.final_dir / filename resolved_final_dir: str = str(Path(args.final_dir).resolve()) plot_directories_list: str = config["harvester"]["plot_directories"] if args.exclude_final_dir: log.info( f"NOT adding directory {resolved_final_dir} to harvester for farming" ) if resolved_final_dir in plot_directories_list: log.warning( f"Directory {resolved_final_dir} already exists for harvester, please remove it manually" ) else: if resolved_final_dir not in plot_directories_list: # Adds the directory to the plot directories if it is not present log.info( f"Adding directory {resolved_final_dir} to harvester for farming" ) config = add_plot_directory(resolved_final_dir, root_path) if not full_path.exists(): log.info(f"Starting plot {i + 1}/{num}") # Creates the plot. This will take a long time for larger plots. plotter: DiskPlotter = DiskPlotter() plotter.create_plot_disk( str(args.tmp_dir), str(args.tmp2_dir), str(args.final_dir), filename, args.size, plot_memo, plot_id, args.buffer, args.buckets, args.stripe_size, args.num_threads, args.nobitfield, ) finished_filenames.append(filename) else: log.info(f"Plot {filename} already exists") log.info("Summary:") if tmp_dir_created: try: args.tmp_dir.rmdir() except Exception: log.info( f"warning: did not remove primary temporary folder {args.tmp_dir}, it may not be empty." ) if tmp2_dir_created: try: args.tmp2_dir.rmdir() except Exception: log.info( f"warning: did not remove secondary temporary folder {args.tmp2_dir}, it may not be empty." ) log.info(f"Created a total of {len(finished_filenames)} new plots") for filename in finished_filenames: log.info(filename)
from clvm.casts import int_from_bytes from clvm_tools import binutils from src.types.blockchain_format.program import Program from src.types.condition_opcodes import ConditionOpcode from src.util.bech32m import decode_puzzle_hash, encode_puzzle_hash from src.util.condition_tools import parse_sexp_to_conditions from src.consensus.block_rewards import calculate_pool_reward, calculate_base_farmer_reward from src.util.ints import uint32 address1 = "txch15gx26ndmacfaqlq8m0yajeggzceu7cvmaz4df0hahkukes695rss6lej7h" # Gene wallet (m/12381/8444/2/42): address2 = "txch1c2cguswhvmdyz9hr3q6hak2h6p9dw4rz82g4707k2xy2sarv705qcce4pn" # Mariano address (m/12381/8444/2/0) ph1 = decode_puzzle_hash(address1) ph2 = decode_puzzle_hash(address2) pool_amounts = int(calculate_pool_reward(uint32(0)) / 2) farmer_amounts = int(calculate_base_farmer_reward(uint32(0)) / 2) assert pool_amounts * 2 == calculate_pool_reward(uint32(0)) assert farmer_amounts * 2 == calculate_base_farmer_reward(uint32(0)) def make_puzzle(amount: int) -> int: puzzle = f"(q . ((51 0x{ph1.hex()} {amount}) (51 0x{ph2.hex()} {amount})))" # print(puzzle) puzzle_prog = Program.to(binutils.assemble(puzzle)) print("Program: ", puzzle_prog) puzzle_hash = puzzle_prog.get_tree_hash()