def sign(args): if args.message is None: print("Please specify the message argument -d") quit() if args.fingerprint is None or args.hd_path is None: print( "Please specify the fingerprint argument -f and hd_path argument -t" ) quit() message = args.message assert message is not None k = Keychain() private_keys = k.get_all_private_keys() fingerprint = args.fingerprint assert fingerprint is not None hd_path = args.hd_path assert hd_path is not None path: List[uint32] = [ uint32(int(i)) for i in hd_path.split("/") if i != "m" ] for sk, _ in private_keys: if sk.get_g1().get_fingerprint() == fingerprint: for c in path: sk = AugSchemeMPL.derive_child_sk(sk, c) print("Public key:", sk.get_g1()) print("Signature:", AugSchemeMPL.sign(sk, bytes(message, "utf-8"))) return print(f"Fingerprint {fingerprint} not found in keychain")
def test_basic_add_delete(self): kc: Keychain = Keychain(testing=True) kc.delete_all_keys() assert kc._get_free_private_key_seed_index() == 0 assert kc._get_free_private_key_index() == 0 assert len(kc.get_all_private_keys()) == 0 mnemonic = generate_mnemonic() seed = seed_from_mnemonic(mnemonic) mnemonic_2 = generate_mnemonic() seed_2 = seed_from_mnemonic(mnemonic_2) kc.add_private_key_seed(seed) assert kc._get_free_private_key_seed_index() == 1 assert kc._get_free_private_key_index() == 0 assert len(kc.get_all_private_keys()) == 1 kc.add_private_key_seed(seed_2) kc.add_private_key_seed(seed_2) # checks to not add duplicates assert kc._get_free_private_key_seed_index() == 2 assert kc._get_free_private_key_index() == 0 assert len(kc.get_all_private_keys()) == 2 raw = ExtendedPrivateKey.from_seed(b"123") kc.add_private_key(raw) kc.add_private_key(raw) kc.add_private_key(raw) kc.add_private_key(raw) # Checks to not add duplicates raw_2 = ExtendedPrivateKey.from_seed(b"1234") kc.add_private_key(raw_2) assert kc._get_free_private_key_seed_index() == 2 assert kc._get_free_private_key_index() == 2 assert len(kc.get_all_private_keys()) == 4 assert len(kc.get_all_public_keys()) == 4 assert raw in [k for (k, s) in kc.get_all_private_keys()] kc.delete_key_by_fingerprint(raw_2.get_public_key().get_fingerprint()) assert kc._get_free_private_key_index() == 1 assert len(kc.get_all_private_keys()) == 3 seed_key_2 = ExtendedPrivateKey.from_seed(seed_2) kc.delete_key_by_fingerprint(seed_key_2.get_public_key().get_fingerprint()) assert kc._get_free_private_key_seed_index() == 1 assert len(kc.get_all_private_keys()) == 2 kc.delete_all_keys() assert kc._get_free_private_key_seed_index() == 0 assert kc._get_free_private_key_index() == 0 assert len(kc.get_all_private_keys()) == 0 kc.add_private_key_not_extended(raw_2.get_private_key()) assert kc._get_free_private_key_seed_index() == 0 assert kc._get_free_private_key_index() == 1 assert len(kc.get_all_private_keys()) == 1 assert raw_2 not in [k for (k, s) in kc.get_all_private_keys()] assert raw_2.get_private_key() in [ k.get_private_key() for (k, s) in kc.get_all_private_keys() ]
def service_kwargs_for_farmer(root_path): service_name = "farmer" config = load_config_cli(root_path, "config.yaml", service_name) keychain = Keychain() connect_peers = [ PeerInfo(config["full_node_peer"]["host"], config["full_node_peer"]["port"]) ] # TOD: Remove once we have pool server config_pool = load_config_cli(root_path, "config.yaml", "pool") api = Farmer(config, config_pool, keychain, constants) kwargs = dict( root_path=root_path, api=api, node_type=NodeType.FARMER, advertised_port=config["port"], service_name=service_name, server_listen_ports=[config["port"]], connect_peers=connect_peers, auth_connect_peers=False, on_connect_callback=api._on_connect, ) if config["start_rpc_server"]: kwargs["rpc_info"] = (FarmerRpcApi, config["rpc_port"]) return kwargs
def main(): config = load_config_cli(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME) config_pool = load_config_cli(DEFAULT_ROOT_PATH, "config.yaml", "pool") keychain = Keychain() kwargs = service_kwargs_for_farmer(DEFAULT_ROOT_PATH, config, config_pool, keychain, DEFAULT_CONSTANTS) return run_service(**kwargs)
async def async_main(): root_path = DEFAULT_ROOT_PATH net_config = load_config(root_path, "config.yaml") config = load_config_cli(root_path, "config.yaml", "farmer") # TOD: Remove once we have pool server config_pool = load_config_cli(root_path, "config.yaml", "pool") initialize_logging("Farmer %(name)-25s", config["logging"], root_path) log = logging.getLogger(__name__) setproctitle("chia_farmer") keychain = Keychain() farmer = Farmer(config, config_pool, keychain) ping_interval = net_config.get("ping_interval") network_id = net_config.get("network_id") assert ping_interval is not None assert network_id is not None server = ChiaServer( config["port"], farmer, NodeType.FARMER, ping_interval, network_id, root_path, config, ) try: asyncio.get_running_loop().add_signal_handler(signal.SIGINT, server.close_all) asyncio.get_running_loop().add_signal_handler(signal.SIGTERM, server.close_all) except NotImplementedError: log.info("signal handlers unsupported") _ = await server.start_server(farmer._on_connect) farmer.set_server(server) rpc_cleanup = None if config["start_rpc_server"]: # Starts the RPC server rpc_cleanup = await start_farmer_rpc_server(farmer, server.close_all, config["rpc_port"]) await asyncio.sleep(10) # Allows full node to startup farmer._start_bg_tasks() await server.await_closed() farmer._shut_down = True # Waits for the rpc server to close if rpc_cleanup is not None: await rpc_cleanup() log.info("Closed RPC server.") log.info("Farmer fully closed.")
def check_keys(new_root): keychain: Keychain = Keychain() all_sks = keychain.get_all_private_keys() if len(all_sks) == 0: print("No keys are present in the keychain. Generate them with 'chia keys generate'") return config: Dict = load_config(new_root, "config.yaml") pool_child_pubkeys = [master_sk_to_pool_sk(sk).get_g1() for sk, _ in all_sks] all_targets = [] stop_searching_for_farmer = "xch_target_address" not in config["farmer"] stop_searching_for_pool = "xch_target_address" not in config["pool"] number_of_ph_to_search = 500 selected = config["selected_network"] prefix = config["network_overrides"]["config"][selected]["address_prefix"] for i in range(number_of_ph_to_search): if stop_searching_for_farmer and stop_searching_for_pool and i > 0: break for sk, _ in all_sks: all_targets.append( encode_puzzle_hash(create_puzzlehash_for_pk(master_sk_to_wallet_sk(sk, uint32(i)).get_g1()), prefix) ) if all_targets[-1] == config["farmer"].get("xch_target_address"): stop_searching_for_farmer = True if all_targets[-1] == config["pool"].get("xch_target_address"): stop_searching_for_pool = True # Set the destinations if "xch_target_address" not in config["farmer"]: print(f"Setting the xch destination address for coinbase fees reward to {all_targets[0]}") config["farmer"]["xch_target_address"] = all_targets[0] elif config["farmer"]["xch_target_address"] not in all_targets: print( f"WARNING: using a farmer address which we don't have the private" f" keys for. We searched the first {number_of_ph_to_search} addresses. Consider overriding " f"{config['farmer']['xch_target_address']} with {all_targets[0]}" ) if "pool" not in config: config["pool"] = {} if "xch_target_address" not in config["pool"]: print(f"Setting the xch destination address for coinbase reward to {all_targets[0]}") config["pool"]["xch_target_address"] = all_targets[0] elif config["pool"]["xch_target_address"] not in all_targets: print( f"WARNING: using a pool address which we don't have the private" f" keys for. We searched the first {number_of_ph_to_search} addresses. Consider overriding " f"{config['pool']['xch_target_address']} with {all_targets[0]}" ) # Set the pool pks in the farmer pool_pubkeys_hex = set(bytes(pk).hex() for pk in pool_child_pubkeys) if "pool_public_keys" in config["farmer"]: for pk_hex in config["farmer"]["pool_public_keys"]: # Add original ones in config pool_pubkeys_hex.add(pk_hex) config["farmer"]["pool_public_keys"] = pool_pubkeys_hex save_config(new_root, "config.yaml", config)
def get_default_pool_public_key() -> G1Element: keychain: Keychain = Keychain() sk_ent = keychain.get_first_private_key() if sk_ent is None: raise RuntimeError( "No keys, please run 'chia keys generate' or provide a public key with -f" ) return master_sk_to_pool_sk(sk_ent[0]).get_g1()
async def setup_wallet_node( port, consensus_constants: ConsensusConstants, full_node_port=None, introducer_port=None, key_seed=None, starting_height=None, ): config = bt.config["wallet"] config["port"] = port config["rpc_port"] = port + 1000 if starting_height is not None: config["starting_height"] = starting_height config["initial_num_public_keys"] = 5 entropy = token_bytes(32) keychain = Keychain(entropy.hex(), True) keychain.add_private_key(bytes_to_mnemonic(entropy), "") first_pk = keychain.get_first_public_key() assert first_pk is not None db_path_key_suffix = str(first_pk.get_fingerprint()) db_name = f"test-wallet-db-{port}" db_path = bt.root_path / f"test-wallet-db-{port}-{db_path_key_suffix}" if db_path.exists(): db_path.unlink() config["database_path"] = str(db_name) config["testing"] = True config["introducer_peer"]["host"] = self_hostname if introducer_port is not None: config["introducer_peer"]["port"] = introducer_port config["peer_connect_interval"] = 10 if full_node_port is not None: config["full_node_peer"] = {} config["full_node_peer"]["host"] = self_hostname config["full_node_peer"]["port"] = full_node_port else: del config["full_node_peer"] kwargs = service_kwargs_for_wallet(bt.root_path, config, consensus_constants, keychain) kwargs.update( parse_cli_args=False, connect_to_daemon=False, ) service = Service(**kwargs) await service.start(new_wallet=True) yield service._node, service._node.server service.stop() await service.wait_closed() if db_path.exists(): db_path.unlink() keychain.delete_all_keys()
def get_pool_public_key(alt_fingerprint: Optional[int] = None) -> G1Element: sk_ent: Optional[Tuple[PrivateKey, bytes]] keychain: Keychain = Keychain() if alt_fingerprint is not None: sk_ent = keychain.get_private_key_by_fingerprint(alt_fingerprint) else: sk_ent = keychain.get_first_private_key() if sk_ent is None: raise RuntimeError("No keys, please run 'chia keys add', 'chia keys generate' or provide a public key with -p") return master_sk_to_pool_sk(sk_ent[0]).get_g1()
async def start_websocket_server(): """ Starts WalletNode, WebSocketServer, and ChiaServer """ setproctitle("chia-wallet") keychain = Keychain(testing=False) websocket_server = WebSocketServer(keychain, DEFAULT_ROOT_PATH) await websocket_server.start() log.info("Wallet fully closed")
async def setup_wallet_node(port, introducer_port=None, key_seed=b"setup_wallet_node", dic={}): config = load_config(root_path, "config.yaml", "wallet") if "starting_height" in dic: config["starting_height"] = dic["starting_height"] keychain = Keychain(key_seed.hex(), True) keychain.add_private_key_seed(key_seed) private_key = keychain.get_all_private_keys()[0][0] test_constants_copy = test_constants.copy() for k in dic.keys(): test_constants_copy[k] = dic[k] db_path = root_path / f"test-wallet-db-{port}.db" if db_path.exists(): db_path.unlink() config["database_path"] = str(db_path) net_config = load_config(root_path, "config.yaml") ping_interval = net_config.get("ping_interval") network_id = net_config.get("network_id") wallet = await WalletNode.create( config, private_key, root_path, override_constants=test_constants_copy, name="wallet1", ) assert ping_interval is not None assert network_id is not None server = ChiaServer( port, wallet, NodeType.WALLET, ping_interval, network_id, root_path, config, "wallet-server", ) wallet.set_server(server) yield (wallet, server) server.close_all() await wallet.wallet_state_manager.clear_all_stores() await wallet.wallet_state_manager.close_all_stores() wallet.wallet_state_manager.unlink_db() await server.await_closed()
def main(): config = load_config_cli(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME) # This is simulator local_test = config["testing"] if local_test is True: constants = test_constants current = config["database_path"] config["database_path"] = f"{current}_simulation" else: constants = DEFAULT_CONSTANTS keychain = Keychain(testing=False) kwargs = service_kwargs_for_wallet(DEFAULT_ROOT_PATH, config, constants, keychain) return run_service(**kwargs)
def sign(message: str, fingerprint: int, hd_path: str): k = Keychain() private_keys = k.get_all_private_keys() path: List[uint32] = [ uint32(int(i)) for i in hd_path.split("/") if i != "m" ] for sk, _ in private_keys: if sk.get_g1().get_fingerprint() == fingerprint: for c in path: sk = AugSchemeMPL.derive_child_sk(sk, c) print("Public key:", sk.get_g1()) print("Signature:", AugSchemeMPL.sign(sk, bytes(message, "utf-8"))) return print(f"Fingerprint {fingerprint} not found in keychain")
def test_bip39_eip2333_test_vector(self): kc: Keychain = Keychain(testing=True) kc.delete_all_keys() mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" passphrase = "TREZOR" print("entropy to seed:", mnemonic_to_seed(mnemonic, passphrase).hex()) master_sk = kc.add_private_key(mnemonic, passphrase) tv_master_int = 5399117110774477986698372024995405256382522670366369834617409486544348441851 tv_child_int = 11812940737387919040225825939013910852517748782307378293770044673328955938106 assert master_sk == PrivateKey.from_bytes( tv_master_int.to_bytes(32, "big")) child_sk = AugSchemeMPL.derive_child_sk(master_sk, 0) assert child_sk == PrivateKey.from_bytes( tv_child_int.to_bytes(32, "big"))
def service_kwargs_for_wallet(root_path): service_name = "wallet" config = load_config_cli(root_path, "config.yaml", service_name) keychain = Keychain(testing=False) wallet_constants = consensus_constants if config["testing"] is True: config["database_path"] = "test_db_wallet.db" wallet_constants = test_constants api = WalletNode(config, keychain, root_path, consensus_constants=wallet_constants) if "full_node_peer" in config: connect_peers = [ PeerInfo(config["full_node_peer"]["host"], config["full_node_peer"]["port"]) ] else: connect_peers = [] async def start_callback(): await api._start() def stop_callback(): api._close() async def await_closed_callback(): await api._await_closed() kwargs = dict( root_path=root_path, api=api, node_type=NodeType.WALLET, advertised_port=config["port"], service_name=service_name, server_listen_ports=[config["port"]], on_connect_callback=api._on_connect, stop_callback=stop_callback, start_callback=start_callback, await_closed_callback=await_closed_callback, rpc_info=(WalletRpcApi, config["rpc_port"]), connect_peers=connect_peers, auth_connect_peers=False, ) return kwargs
def check_keys(new_root): keychain: Keychain = Keychain() all_pubkeys = keychain.get_all_public_keys() if len(all_pubkeys) == 0: print( "No keys are present in the keychain. Generate them with 'chia keys generate_and_add'" ) return all_targets = [ create_puzzlehash_for_pk( BLSPublicKey(bytes(epk.public_child(0).get_public_key())) ).hex() for epk in all_pubkeys ] config: Dict = load_config(new_root, "config.yaml") # Set the destinations if ( "xch_target_puzzle_hash" not in config["farmer"] or config["farmer"]["xch_target_puzzle_hash"] not in all_targets ): print( f"Setting the xch destination address for coinbase fees reward to {all_targets[0]}" ) config["farmer"]["xch_target_puzzle_hash"] = all_targets[0] if "pool" in config: if ( "xch_target_puzzle_hash" not in config["pool"] or config["pool"]["xch_target_puzzle_hash"] not in all_targets ): print( f"Setting the xch destination address for coinbase reward to {all_targets[0]}" ) config["pool"]["xch_target_puzzle_hash"] = all_targets[0] # Set the pool pks in the farmer all_pubkeys_hex = set([bytes(pk.get_public_key()).hex() for pk in all_pubkeys]) if "pool_public_keys" in config["farmer"]: for pk_hex in config["farmer"]["pool_public_keys"]: # Add original ones in config all_pubkeys_hex.add(pk_hex) config["farmer"]["pool_public_keys"] = all_pubkeys_hex save_config(new_root, "config.yaml", config)
def main(): config = load_config_cli(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME) # This is simulator local_test = config["testing"] if local_test is True: constants = test_constants current = config["database_path"] config["database_path"] = f"{current}_simulation" else: constants = DEFAULT_CONSTANTS genesis_challenge = bytes32( bytes.fromhex(config["network_genesis_challenges"][ config["selected_network"]])) constants = constants.replace(GENESIS_CHALLENGE=genesis_challenge) keychain = Keychain(testing=False) kwargs = service_kwargs_for_wallet(DEFAULT_ROOT_PATH, config, constants, keychain) return run_service(**kwargs)
def __init__( self, constants: ConsensusConstants = test_constants, root_path: Optional[Path] = None, ): self._tempdir = None if root_path is None: self._tempdir = tempfile.TemporaryDirectory() root_path = Path(self._tempdir.name) self.root_path = root_path self.constants = constants create_default_chia_config(root_path) self.keychain = Keychain("testing-1.8.0", True) self.keychain.delete_all_keys() self.farmer_master_sk = self.keychain.add_private_key( bytes_to_mnemonic(std_hash(b"block_tools farmer key")), "" ) self.pool_master_sk = self.keychain.add_private_key(bytes_to_mnemonic(std_hash(b"block_tools pool key")), "") self.farmer_pk = master_sk_to_farmer_sk(self.farmer_master_sk).get_g1() self.pool_pk = master_sk_to_pool_sk(self.pool_master_sk).get_g1() self.init_plots(root_path) initialize_ssl(root_path) self.farmer_ph: bytes32 = create_puzzlehash_for_pk( master_sk_to_wallet_sk(self.farmer_master_sk, uint32(0)).get_g1() ) self.pool_ph: bytes32 = create_puzzlehash_for_pk( master_sk_to_wallet_sk(self.pool_master_sk, uint32(0)).get_g1() ) self.all_sks: List[PrivateKey] = [sk for sk, _ in self.keychain.get_all_private_keys()] self.pool_pubkeys: List[G1Element] = [master_sk_to_pool_sk(sk).get_g1() for sk in self.all_sks] farmer_pubkeys: List[G1Element] = [master_sk_to_farmer_sk(sk).get_g1() for sk in self.all_sks] if len(self.pool_pubkeys) == 0 or len(farmer_pubkeys) == 0: raise RuntimeError("Keys not generated. Run `chia generate keys`") _, loaded_plots, _, _ = load_plots({}, {}, farmer_pubkeys, self.pool_pubkeys, None, root_path) self.plots: Dict[Path, PlotInfo] = loaded_plots self._config = load_config(self.root_path, "config.yaml")
def migrate_to_keychain(old_root, new_root): # Transfer the keys from the old root config folder into the keychain. # Also set the right public keys in the config files for farming. print("\nMigrating keys.yaml to keychain") keychain: Keychain = Keychain() # Migrate wallet sk try: keys_config = load_config(old_root, "keys.yaml", exit_on_error=False) wallet_key_bytes = bytes.fromhex(keys_config["wallet_sk"]) wallet_sk = ExtendedPrivateKey.from_bytes(wallet_key_bytes) keychain.add_private_key(wallet_sk) # Migrate pool sks pool_sks_bytes = [bytes.fromhex(h) for h in keys_config["pool_sks"]] for k_bytes in pool_sks_bytes: keychain.add_private_key_not_extended(PrivateKey.from_bytes(k_bytes)) except ValueError: print("No keys.yaml to migrate from.") check_keys(new_root)
type=int, default=None, help="Enter the fingerprint of the key you want to delete", ) parser.add_argument( "command", help=f"Command can be any one of {command_list}", type=str, nargs="?", ) parser.set_defaults(function=handler) parser.print_help = lambda self=parser: help_message() keychain: Keychain = Keychain() def generate_and_print(): """ Generates a seed for a private key, and prints the mnemonic to the terminal. """ mnemonic = generate_mnemonic() mnemonics_string = mnemonic_to_string(mnemonic) print("Generating private key. Mnemonic:") print(mnemonics_string) print( "Note that this key has not been added to the keychain. Run chia keys add_seed -m [MNEMONICS] to add" ) return mnemonic
def check_plots(args, root_path): config = load_config(root_path, "config.yaml") if args.num is not None: num = args.num else: num = 20 if args.grep_string is not None: match_str = args.grep_string else: match_str = None v = Verifier() log.info("Loading plots in config.yaml using plot_tools loading code\n") kc: Keychain = Keychain() pks = [ master_sk_to_farmer_sk(sk).get_g1() for sk, _ in kc.get_all_private_keys() ] pool_public_keys = [ G1Element.from_bytes(bytes.fromhex(pk)) for pk in config["farmer"]["pool_public_keys"] ] _, provers, failed_to_open_filenames, no_key_filenames = load_plots( {}, {}, pks, pool_public_keys, match_str, root_path, open_no_key_filenames=True, ) if len(provers) > 0: log.info("") log.info("") log.info(f"Starting to test each plot with {num} challenges each\n") total_good_plots: Counter = Counter() total_bad_plots = 0 total_size = 0 for plot_path, plot_info in provers.items(): pr = plot_info.prover log.info(f"Testing plot {plot_path} k={pr.get_size()}") log.info(f"\tPool public key: {plot_info.pool_public_key}") log.info(f"\tFarmer public key: {plot_info.farmer_public_key}") log.info(f"\tLocal sk: {plot_info.local_sk}") total_proofs = 0 try: for i in range(num): challenge = std_hash(i.to_bytes(32, "big")) for index, quality_str in enumerate( pr.get_qualities_for_challenge(challenge)): proof = pr.get_full_proof(challenge, index) total_proofs += 1 ver_quality_str = v.validate_proof(pr.get_id(), pr.get_size(), challenge, proof) assert quality_str == ver_quality_str except BaseException as e: if isinstance(e, KeyboardInterrupt): log.warning("Interrupted, closing") return log.error( f"{type(e)}: {e} error in proving/verifying for plot {plot_path}" ) if total_proofs > 0: log.info( f"\tProofs {total_proofs} / {num}, {round(total_proofs/float(num), 4)}" ) total_good_plots[pr.get_size()] += 1 total_size += plot_path.stat().st_size else: total_bad_plots += 1 log.error( f"\tProofs {total_proofs} / {num}, {round(total_proofs/float(num), 4)}" ) log.info("") log.info("") log.info("Summary") total_plots: int = sum(list(total_good_plots.values())) log.info( f"Found {total_plots} valid plots, total size {total_size / (1024 * 1024 * 1024 * 1024):.5f} TiB" ) for (k, count) in sorted(dict(total_good_plots).items()): log.info(f"{count} plots of size {k}") grand_total_bad = total_bad_plots + len(failed_to_open_filenames) if grand_total_bad > 0: log.warning(f"{grand_total_bad} invalid plots") if len(no_key_filenames) > 0: log.warning( f"There are {len(no_key_filenames)} plots with a farmer or pool public key that " f"is not on this machine. The farmer private key must be in the keychain in order to " f"farm them, use 'chia keys' to transfer keys. The pool public keys must be in the config.yaml" )
def test_basic_add_delete(self): kc: Keychain = Keychain(testing=True) kc.delete_all_keys() assert kc._get_free_private_key_index() == 0 assert len(kc.get_all_private_keys()) == 0 assert kc.get_first_private_key() is None assert kc.get_first_public_key() is None mnemonic = generate_mnemonic() entropy = bytes_from_mnemonic(mnemonic) assert bytes_to_mnemonic(entropy) == mnemonic mnemonic_2 = generate_mnemonic() kc.add_private_key(mnemonic, "") assert kc._get_free_private_key_index() == 1 assert len(kc.get_all_private_keys()) == 1 kc.add_private_key(mnemonic_2, "") kc.add_private_key(mnemonic_2, "") # checks to not add duplicates assert kc._get_free_private_key_index() == 2 assert len(kc.get_all_private_keys()) == 2 assert kc._get_free_private_key_index() == 2 assert len(kc.get_all_private_keys()) == 2 assert len(kc.get_all_public_keys()) == 2 assert kc.get_all_private_keys()[0] == kc.get_first_private_key() assert kc.get_all_public_keys()[0] == kc.get_first_public_key() assert len(kc.get_all_private_keys()) == 2 seed_2 = mnemonic_to_seed(mnemonic, "") seed_key_2 = AugSchemeMPL.key_gen(seed_2) kc.delete_key_by_fingerprint(seed_key_2.get_g1().get_fingerprint()) assert kc._get_free_private_key_index() == 0 assert len(kc.get_all_private_keys()) == 1 kc.delete_all_keys() assert kc._get_free_private_key_index() == 0 assert len(kc.get_all_private_keys()) == 0 kc.add_private_key(bytes_to_mnemonic(token_bytes(32)), "my passphrase") kc.add_private_key(bytes_to_mnemonic(token_bytes(32)), "") kc.add_private_key(bytes_to_mnemonic(token_bytes(32)), "third passphrase") assert len(kc.get_all_public_keys()) == 3 assert len(kc.get_all_private_keys()) == 1 assert len(kc.get_all_private_keys(["my passphrase", ""])) == 2 assert len( kc.get_all_private_keys( ["my passphrase", "", "third passphrase", "another"])) == 3 assert len(kc.get_all_private_keys(["my passhrase wrong"])) == 0 assert kc.get_first_private_key() is not None assert kc.get_first_private_key(["bad passphrase"]) is None assert kc.get_first_public_key() is not None kc.delete_all_keys() kc.add_private_key(bytes_to_mnemonic(token_bytes(32)), "my passphrase") assert kc.get_first_public_key() is not None
def __init__( self, root_path: Path = TEST_ROOT_PATH, real_plots: bool = False, ): create_default_chia_config(root_path) initialize_ssl(root_path) self.root_path = root_path self.n_wesolowski = uint8(0) self.real_plots = real_plots if not real_plots: # No real plots supplied, so we will use the small test plots self.use_any_pos = True self.plot_config: Dict = {"plots": {}} # Can't go much lower than 19, since plots start having no solutions k: uint8 = uint8(19) # Uses many plots for testing, in order to guarantee proofs of space at every height num_plots = 40 # Use the empty string as the seed for the private key self.keychain = Keychain("testing", True) self.keychain.delete_all_keys() self.keychain.add_private_key_seed(b"block_tools") pool_sk: PrivateKey = self.keychain.get_all_private_keys( )[0][0].get_private_key() pool_pk: PublicKey = pool_sk.get_public_key() plot_sks: List[PrivateKey] = [ PrivateKey.from_seed(pn.to_bytes(4, "big")) for pn in range(num_plots) ] plot_pks: List[PublicKey] = [ sk.get_public_key() for sk in plot_sks ] plot_seeds: List[bytes32] = [ ProofOfSpace.calculate_plot_seed(pool_pk, plot_pk) for plot_pk in plot_pks ] plot_dir = get_plot_dir(root_path) mkdir(plot_dir) filenames: List[str] = [ f"genesis-plots-{k}{std_hash(int.to_bytes(i, 4, 'big')).hex()}.dat" for i in range(num_plots) ] done_filenames = set() temp_dir = plot_dir / "plot.tmp" mkdir(temp_dir) try: for pn, filename in enumerate(filenames): if not (plot_dir / filename).exists(): plotter = DiskPlotter() plotter.create_plot_disk( str(plot_dir), str(plot_dir), str(plot_dir), filename, k, b"genesis", plot_seeds[pn], ) done_filenames.add(filename) self.plot_config["plots"][str(plot_dir / filename)] = { "pool_pk": bytes(pool_pk).hex(), "sk": bytes(plot_sks[pn]).hex(), "pool_sk": bytes(pool_sk).hex(), } save_config(self.root_path, "plots.yaml", self.plot_config) except KeyboardInterrupt: for filename in filenames: if (filename not in done_filenames and (plot_dir / filename).exists()): (plot_dir / filename).unlink() sys.exit(1) else: try: plot_config = load_config(DEFAULT_ROOT_PATH, "plots.yaml") normal_config = load_config(DEFAULT_ROOT_PATH, "config.yaml") except FileNotFoundError: raise RuntimeError( "Plots not generated. Run chia-create-plots") self.keychain = Keychain(testing=False) private_keys: List[PrivateKey] = [ k.get_private_key() for (k, _) in self.keychain.get_all_private_keys() ] pool_pubkeys: List[PublicKey] = [ sk.get_public_key() for sk in private_keys ] if len(private_keys) == 0: raise RuntimeError( "Keys not generated. Run `chia generate keys`") self.prover_dict, _, _ = load_plots(normal_config["harvester"], plot_config, pool_pubkeys, DEFAULT_ROOT_PATH) new_plot_config: Dict = {"plots": {}} for key, value in plot_config["plots"].items(): for sk in private_keys: if (bytes(sk.get_public_key()).hex() == value["pool_pk"] and key in self.prover_dict): new_plot_config["plots"][key] = value new_plot_config["plots"][key]["pool_sk"] = bytes( sk).hex() self.plot_config = new_plot_config self.use_any_pos = False a = self.plot_config["plots"] print(f"Using {len(a)} reals plots to initialize block_tools") private_key = self.keychain.get_all_private_keys()[0][0] self.fee_target = create_puzzlehash_for_pk( BLSPublicKey(bytes(private_key.public_child(1).get_public_key())))
def check_plots(root_path, num, challenge_start, grep_string, list_duplicates, debug_show_memo): config = load_config(root_path, "config.yaml") if num is not None: if num == 0: log.warning("Not opening plot files") else: if num < 5: log.warning( f"{num} challenges is too low, setting it to the minimum of 5" ) num = 5 if num < 30: log.warning( "Use 30 challenges (our default) for balance of speed and accurate results" ) else: num = 30 if challenge_start is not None: num_start = challenge_start num_end = num_start + num else: num_start = 0 num_end = num challenges = num_end - num_start if grep_string is not None: match_str = grep_string else: match_str = None if list_duplicates: log.warning("Checking for duplicate Plot IDs") log.info("Plot filenames expected to end with -[64 char plot ID].plot") show_memo: bool = debug_show_memo if list_duplicates: plot_filenames: Dict[Path, List[Path]] = get_plot_filenames( config["harvester"]) all_filenames: List[Path] = [] for paths in plot_filenames.values(): all_filenames += paths find_duplicate_plot_IDs(all_filenames) if num == 0: return v = Verifier() log.info("Loading plots in config.yaml using plot_tools loading code\n") kc: Keychain = Keychain() pks = [ master_sk_to_farmer_sk(sk).get_g1() for sk, _ in kc.get_all_private_keys() ] pool_public_keys = [ G1Element.from_bytes(bytes.fromhex(pk)) for pk in config["farmer"]["pool_public_keys"] ] _, provers, failed_to_open_filenames, no_key_filenames = load_plots( {}, {}, pks, pool_public_keys, match_str, show_memo, root_path, open_no_key_filenames=True, ) if len(provers) > 0: log.info("") log.info("") log.info(f"Starting to test each plot with {num} challenges each\n") total_good_plots: Counter = Counter() total_bad_plots = 0 total_size = 0 bad_plots_list: List[Path] = [] for plot_path, plot_info in provers.items(): pr = plot_info.prover log.info(f"Testing plot {plot_path} k={pr.get_size()}") log.info(f"\tPool public key: {plot_info.pool_public_key}") # Look up local_sk from plot to save locked memory ( pool_public_key_or_puzzle_hash, farmer_public_key, local_master_sk, ) = parse_plot_info(pr.get_memo()) local_sk = master_sk_to_local_sk(local_master_sk) log.info(f"\tFarmer public key: {farmer_public_key}") log.info(f"\tLocal sk: {local_sk}") total_proofs = 0 caught_exception: bool = False for i in range(num_start, num_end): challenge = std_hash(i.to_bytes(32, "big")) # Some plot errors cause get_qualities_for_challenge to throw a RuntimeError try: for index, quality_str in enumerate( pr.get_qualities_for_challenge(challenge)): # Other plot errors cause get_full_proof or validate_proof to throw an AssertionError try: proof = pr.get_full_proof(challenge, index) total_proofs += 1 ver_quality_str = v.validate_proof( pr.get_id(), pr.get_size(), challenge, proof) assert quality_str == ver_quality_str except AssertionError as e: log.error( f"{type(e)}: {e} error in proving/verifying for plot {plot_path}" ) caught_exception = True except BaseException as e: if isinstance(e, KeyboardInterrupt): log.warning("Interrupted, closing") return log.error( f"{type(e)}: {e} error in getting challenge qualities for plot {plot_path}" ) caught_exception = True if caught_exception is True: break if total_proofs > 0 and caught_exception is False: log.info( f"\tProofs {total_proofs} / {challenges}, {round(total_proofs/float(challenges), 4)}" ) total_good_plots[pr.get_size()] += 1 total_size += plot_path.stat().st_size else: total_bad_plots += 1 log.error( f"\tProofs {total_proofs} / {challenges}, {round(total_proofs/float(challenges), 4)}" ) bad_plots_list.append(plot_path) log.info("") log.info("") log.info("Summary") total_plots: int = sum(list(total_good_plots.values())) log.info( f"Found {total_plots} valid plots, total size {total_size / (1024 * 1024 * 1024 * 1024):.5f} TiB" ) for (k, count) in sorted(dict(total_good_plots).items()): log.info(f"{count} plots of size {k}") grand_total_bad = total_bad_plots + len(failed_to_open_filenames) if grand_total_bad > 0: log.warning(f"{grand_total_bad} invalid plots found:") for bad_plot_path in bad_plots_list: log.warning(f"{bad_plot_path}") if len(no_key_filenames) > 0: log.warning( f"There are {len(no_key_filenames)} plots with a farmer or pool public key that " f"is not on this machine. The farmer private key must be in the keychain in order to " f"farm them, use 'chia keys' to transfer keys. The pool public keys must be in the config.yaml" )
def main(): config = load_config_cli(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME) keychain = Keychain(testing=False) kwargs = service_kwargs_for_wallet(DEFAULT_ROOT_PATH, config, DEFAULT_CONSTANTS, keychain) return run_service(**kwargs)
def main(): """ Script for creating plots and adding them to the plot config file. """ root_path = DEFAULT_ROOT_PATH plot_config_filename = config_path_for_filename(root_path, "plots.yaml") parser = argparse.ArgumentParser(description="Chia plotting script.") parser.add_argument("-k", "--size", help="Plot size", type=int, default=26) parser.add_argument( "-n", "--num_plots", help="Number of plots", type=int, default=1 ) parser.add_argument( "-i", "--index", help="First plot index", type=int, default=None ) parser.add_argument( "-p", "--pool_pub_key", help="Hex public key of pool", type=str, default="" ) parser.add_argument( "-s", "--sk_seed", help="Secret key seed in hex", type=str, default=None ) parser.add_argument( "-t", "--tmp_dir", help="Temporary directory for plotting files", type=Path, default=Path("."), ) parser.add_argument( "-2", "--tmp2_dir", help="Second temporary directory for plotting files", type=Path, default=Path("."), ) new_plots_root = path_from_root( root_path, load_config(root_path, "config.yaml") .get("harvester", {}) .get("new_plot_root", "plots"), ) parser.add_argument( "-d", "--final_dir", help="Final directory for plots (relative or absolute)", type=Path, default=new_plots_root, ) args = parser.parse_args() if args.sk_seed is None and args.index is not None: log( f"You have specified the -i (index) argument without the -s (sk_seed) argument." f" The program has changes, so that the sk_seed is now generated randomly, so -i is no longer necessary." f" Please run the program without -i." ) quit() if args.index is None: args.index = 0 # The seed is what will be used to generate a private key for each plot if args.sk_seed is not None: sk_seed: bytes = bytes.fromhex(args.sk_seed) log(f"Using the provided sk_seed {sk_seed.hex()}.") else: sk_seed = token_bytes(32) log( f"Using sk_seed {sk_seed.hex()}. Note that sk seed is now generated randomly, as opposed " f"to from keys.yaml. If you want to use a specific seed, use the -s argument." ) pool_pk: PublicKey if len(args.pool_pub_key) > 0: # Use the provided pool public key, useful for using an external pool pool_pk = PublicKey.from_bytes(bytes.fromhex(args.pool_pub_key)) else: # Use the pool public key from the config, useful for solo farming keychain = Keychain() all_public_keys = keychain.get_all_public_keys() if len(all_public_keys) == 0: raise RuntimeError( "There are no private keys in the keychain, so we cannot create a plot. " "Please generate keys using 'chia keys generate' or pass in a pool pk with -p" ) pool_pk = all_public_keys[0].get_public_key() log( f"Creating {args.num_plots} plots, from index {args.index} to " f"{args.index + args.num_plots - 1}, of size {args.size}, sk_seed {sk_seed.hex()} ppk {pool_pk}" ) mkdir(args.tmp_dir) mkdir(args.tmp2_dir) mkdir(args.final_dir) finished_filenames = [] for i in range(args.index, args.index + args.num_plots): # Generate a sk based on the seed, plot size (k), and index sk: PrivateKey = PrivateKey.from_seed( sk_seed + args.size.to_bytes(1, "big") + i.to_bytes(4, "big") ) # The plot seed is based on the pool and plot pks plot_seed: bytes32 = ProofOfSpace.calculate_plot_seed( pool_pk, sk.get_public_key() ) dt_string = datetime.now().strftime("%Y-%m-%d-%H-%M") filename: str = f"plot-k{args.size}-{dt_string}-{plot_seed}.dat" full_path: Path = args.final_dir / filename plot_config = load_config(root_path, plot_config_filename) plot_config_plots_new = deepcopy(plot_config.get("plots", [])) filenames = [Path(k).name for k in plot_config_plots_new.keys()] already_in_config = any(plot_seed.hex() in fname for fname in filenames) if already_in_config: log(f"Plot {filename} already exists (in config)") continue if not full_path.exists(): # 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, bytes([]), plot_seed, ) finished_filenames.append(filename) else: log(f"Plot {filename} already exists") # Updates the config if necessary. plot_config = load_config(root_path, plot_config_filename) plot_config_plots_new = deepcopy(plot_config.get("plots", [])) plot_config_plots_new[str(full_path)] = { "sk": bytes(sk).hex(), "pool_pk": bytes(pool_pk).hex(), } plot_config["plots"].update(plot_config_plots_new) # Dumps the new config to disk. save_config(root_path, plot_config_filename, plot_config) log("") log("Summary:") try: args.tmp_dir.rmdir() except Exception: log( f"warning: did not remove primary temporary folder {args.tmp_dir}, it may not be empty." ) try: args.tmp2_dir.rmdir() except Exception: log( f"warning: did not remove secondary temporary folder {args.tmp2_dir}, it may not be empty." ) log(f"Created a total of {len(finished_filenames)} new plots") for filename in finished_filenames: log(filename)
def __init__( self, root_path: Optional[Path] = None, real_plots: bool = False, ): self._tempdir = None if root_path is None: self._tempdir = tempfile.TemporaryDirectory() root_path = Path(self._tempdir.name) self.root_path = root_path self.real_plots = real_plots if not real_plots: create_default_chia_config(root_path) initialize_ssl(root_path) # No real plots supplied, so we will use the small test plots self.use_any_pos = True self.keychain = Keychain("testing-1.8.0", True) self.keychain.delete_all_keys() self.farmer_master_sk = self.keychain.add_private_key( bytes_to_mnemonic(std_hash(b"block_tools farmer key")), "") self.pool_master_sk = self.keychain.add_private_key( bytes_to_mnemonic(std_hash(b"block_tools pool key")), "") self.farmer_pk = master_sk_to_farmer_sk( self.farmer_master_sk).get_g1() self.pool_pk = master_sk_to_pool_sk(self.pool_master_sk).get_g1() plot_dir = get_plot_dir() mkdir(plot_dir) temp_dir = plot_dir / "tmp" mkdir(temp_dir) args = Namespace() # Can't go much lower than 18, since plots start having no solutions args.size = 18 # Uses many plots for testing, in order to guarantee proofs of space at every height args.num = 40 args.buffer = 32 args.farmer_public_key = bytes(self.farmer_pk).hex() args.pool_public_key = bytes(self.pool_pk).hex() args.tmp_dir = temp_dir args.tmp2_dir = plot_dir args.final_dir = plot_dir args.plotid = None args.memo = None test_private_keys = [ AugSchemeMPL.key_gen(std_hash(bytes([i]))) for i in range(args.num) ] try: # No datetime in the filename, to get deterministic filenames and not replot create_plots( args, root_path, use_datetime=False, test_private_keys=test_private_keys, ) except KeyboardInterrupt: shutil.rmtree(plot_dir, ignore_errors=True) sys.exit(1) else: initialize_ssl(root_path) self.keychain = Keychain() self.use_any_pos = False sk_and_ent = self.keychain.get_first_private_key() assert sk_and_ent is not None self.farmer_master_sk = sk_and_ent[0] self.pool_master_sk = sk_and_ent[0] self.farmer_ph = create_puzzlehash_for_pk( master_sk_to_wallet_sk(self.farmer_master_sk, uint32(0)).get_g1()) self.pool_ph = create_puzzlehash_for_pk( master_sk_to_wallet_sk(self.pool_master_sk, uint32(0)).get_g1()) self.all_sks = self.keychain.get_all_private_keys() self.pool_pubkeys: List[G1Element] = [ master_sk_to_pool_sk(sk).get_g1() for sk, _ in self.all_sks ] farmer_pubkeys: List[G1Element] = [ master_sk_to_farmer_sk(sk).get_g1() for sk, _ in self.all_sks ] if len(self.pool_pubkeys) == 0 or len(farmer_pubkeys) == 0: raise RuntimeError("Keys not generated. Run `chia generate keys`") _, self.plots, _, _ = load_plots({}, {}, farmer_pubkeys, self.pool_pubkeys, root_path)
async def setup_wallet_node( port, consensus_constants: ConsensusConstants, full_node_port=None, introducer_port=None, key_seed=None, starting_height=None, ): config = load_config(bt.root_path, "config.yaml", "wallet") if starting_height is not None: config["starting_height"] = starting_height config["initial_num_public_keys"] = 5 entropy = token_bytes(32) keychain = Keychain(entropy.hex(), True) keychain.add_private_key(bytes_to_mnemonic(entropy), "") first_pk = keychain.get_first_public_key() assert first_pk is not None db_path_key_suffix = str(first_pk.get_fingerprint()) db_name = f"test-wallet-db-{port}" db_path = bt.root_path / f"test-wallet-db-{port}-{db_path_key_suffix}" if db_path.exists(): db_path.unlink() config["database_path"] = str(db_name) config["testing"] = True api = WalletNode( config, keychain, bt.root_path, consensus_constants=consensus_constants, name="wallet1", ) periodic_introducer_poll = None if introducer_port is not None: periodic_introducer_poll = ( PeerInfo(self_hostname, introducer_port), 30, config["target_peer_count"], ) connect_peers: List[PeerInfo] = [] if full_node_port is not None: connect_peers = [PeerInfo(self_hostname, full_node_port)] started = asyncio.Event() async def start_callback(): await api._start(new_wallet=True) nonlocal started started.set() def stop_callback(): api._close() async def await_closed_callback(): await api._await_closed() service = Service( root_path=bt.root_path, api=api, node_type=NodeType.WALLET, advertised_port=port, service_name="wallet", server_listen_ports=[port], connect_peers=connect_peers, auth_connect_peers=False, on_connect_callback=api._on_connect, start_callback=start_callback, stop_callback=stop_callback, await_closed_callback=await_closed_callback, periodic_introducer_poll=periodic_introducer_poll, parse_cli_args=False, ) run_task = asyncio.create_task(service.run()) await started.wait() yield api, api.server service.stop() await run_task if db_path.exists(): db_path.unlink() keychain.delete_all_keys()