def get_all_private_keys(self) -> List[Tuple[ExtendedPrivateKey, Optional[bytes]]]: """ Returns all private keys (both seed-derived keys and raw ExtendedPrivateKeys), and the second value in the tuple is the bytes seed if it exists, otherwise None. """ all_keys: List[Tuple[ExtendedPrivateKey, Optional[bytes]]] = [] # Keys that have a seed are added first index = 0 seed_hex = self._get_stored_entropy(self._get_private_key_seed_user(index)) while seed_hex is not None and len(seed_hex) > 0: key = ExtendedPrivateKey.from_seed(hexstr_to_bytes(seed_hex)) all_keys.append((key, hexstr_to_bytes(seed_hex))) index += 1 seed_hex = self._get_stored_entropy(self._get_private_key_seed_user(index)) # Keys without a seed are added after index = 0 key_hex = self._get_stored_entropy(self._get_private_key_user(index)) while key_hex is not None and len(key_hex) > 0: key = ExtendedPrivateKey.from_bytes(hexstr_to_bytes(key_hex)) all_keys.append((key, None)) index += 1 key_hex = self._get_stored_entropy(self._get_private_key_user(index)) return all_keys
def delete_key_by_fingerprint(self, fingerprint: int): """ Deletes all keys which have the given public key fingerprint. """ index = 0 key_hex = self._get_stored_entropy(self._get_private_key_user(index)) while key_hex is not None and len(key_hex) > 0: key = ExtendedPrivateKey.from_bytes(hexstr_to_bytes(key_hex)) if key.get_public_key().get_fingerprint() == fingerprint: keyring.delete_password( self._get_service(), self._get_private_key_user(index) ) index += 1 key_hex = self._get_stored_entropy(self._get_private_key_user(index)) index = 0 seed_hex = self._get_stored_entropy(self._get_private_key_seed_user(index)) while seed_hex is not None and len(seed_hex) > 0: key = ExtendedPrivateKey.from_seed(hexstr_to_bytes(seed_hex)) if key.get_public_key().get_fingerprint() == fingerprint: keyring.delete_password( self._get_service(), self._get_private_key_seed_user(index) ) index += 1 seed_hex = self._get_stored_entropy(self._get_private_key_seed_user(index))
def dataclass_from_dict(klass, d): """ Converts a dictionary based on a dataclass, into an instance of that dataclass. Recursively goes through lists, optionals, and dictionaries. """ if is_type_SpecificOptional(klass): # Type is optional, data is either None, or Any if not d: return None return dataclass_from_dict(get_args(klass)[0], d) elif is_type_Tuple(klass): return tuple(dataclass_from_dict(get_args(klass)[0], item) for item in d) elif dataclasses.is_dataclass(klass): # Type is a dataclass, data is a dictionary fieldtypes = {f.name: f.type for f in dataclasses.fields(klass)} return klass(**{f: dataclass_from_dict(fieldtypes[f], d[f]) for f in d}) elif is_type_List(klass): # Type is a list, data is a list return [dataclass_from_dict(get_args(klass)[0], item) for item in d] elif issubclass(klass, bytes): # Type is bytes, data is a hex string return klass(hexstr_to_bytes(d)) elif klass in unhashable_types: # Type is unhashable (bls type), so cast from hex string return klass.from_bytes(hexstr_to_bytes(d)) else: # Type is a primitive, cast with correct class return klass(d)
def test_overflow_atoms(self): b = hexstr_to_bytes(serialized_atom_overflow(0xFFFFFFFF)) try: cost, output = DESERIALIZE_MOD.run_with_cost([b]) except Exception: assert True else: assert False b = hexstr_to_bytes(serialized_atom_overflow(0x3FFFFFFFF)) try: cost, output = DESERIALIZE_MOD.run_with_cost([b]) except Exception: assert True else: assert False b = hexstr_to_bytes(serialized_atom_overflow(0xFFFFFFFFFF)) try: cost, output = DESERIALIZE_MOD.run_with_cost([b]) except Exception: assert True else: assert False b = hexstr_to_bytes(serialized_atom_overflow(0x1FFFFFFFFFF)) try: cost, output = DESERIALIZE_MOD.run_with_cost([b]) except Exception: assert True else: assert False
def open_backup_file(file_path, private_key): backup_file_text = file_path.read_text() backup_file_json = json.loads(backup_file_text) meta_data = backup_file_json["meta_data"] meta_data_bytes = json.dumps(meta_data).encode() sig = backup_file_json["signature"] backup_pk = master_sk_to_backup_sk(private_key) my_pubkey = backup_pk.get_g1() key_base_64 = base64.b64encode(bytes(backup_pk)) f = Fernet(key_base_64) encrypted_data = backup_file_json["data"].encode() msg = std_hash(encrypted_data) + std_hash(meta_data_bytes) signature = SignatureMPL.from_bytes(hexstr_to_bytes(sig)) pubkey = PublicKeyMPL.from_bytes(hexstr_to_bytes(meta_data["pubkey"])) sig_match_my = AugSchemeMPL.verify(my_pubkey, msg, signature) sig_match_backup = AugSchemeMPL.verify(pubkey, msg, signature) assert sig_match_my is True assert sig_match_backup is True data_bytes = f.decrypt(encrypted_data) data_text = data_bytes.decode() data_json = json.loads(data_text) unencrypted = {} unencrypted["data"] = data_json unencrypted["meta_data"] = meta_data return unencrypted
def validate_alert(text: str, pubkey: str) -> bool: json_obj = json.loads(text) data = json_obj["data"] message = bytes(data, "UTF-8") signature = json_obj["signature"] signature = SignatureMPL.from_bytes(hexstr_to_bytes(signature)) pubkey_bls = PublicKeyMPL.from_bytes(hexstr_to_bytes(pubkey)) sig_match_my = AugSchemeMPL.verify(pubkey_bls, message, signature) return sig_match_my
async def compare_block_headers(client, oldblock_hash, newblock_hash): """ Calculates the estimated space on the network given two block header hases # TODO: remove grubby hack of getting both blocks for get_total_miniters """ block_older_header = await client.get_header(hexstr_to_bytes(oldblock_hash)) block_newer_header = await client.get_header(hexstr_to_bytes(newblock_hash)) if block_older_header is not None: block_older_time_string = human_local_time(block_older_header.data.timestamp) block_newer_time_string = human_local_time(block_newer_header.data.timestamp) elapsed_time_seconds = ( block_newer_header.data.timestamp - block_older_header.data.timestamp ) time_delta = datetime.timedelta(seconds=elapsed_time_seconds) print( f"Older Block: {block_older_header.data.height}\n" f"Header Hash: 0x{oldblock_hash}\n" f"Timestamp: {block_older_time_string}\n" f"Weight: {block_older_header.data.weight}\n" f"Total VDF\n" f"Iterations: {block_older_header.data.total_iters}\n" ) print( f"Newer Block: {block_newer_header.data.height}\n" f"Header Hash: 0x{newblock_hash}\n" f"Timestamp: {block_newer_time_string}\n" f"Weight: {block_newer_header.data.weight}\n" f"Total VDF\n" f"Iterations: {block_newer_header.data.total_iters}\n" ) delta_weight = block_newer_header.data.weight - block_older_header.data.weight delta_iters = ( block_newer_header.data.total_iters - block_older_header.data.total_iters ) block_older = await client.get_block(hexstr_to_bytes(oldblock_hash)) block_newer = await client.get_block(hexstr_to_bytes(newblock_hash)) delta_iters -= await get_total_miniters(client, block_older, block_newer) weight_div_iters = delta_weight / delta_iters tips_adjustment_constant = 0.65 network_space_constant = 2 ** 32 # 2^32 network_space_bytes_estimate = ( weight_div_iters * network_space_constant * tips_adjustment_constant ) network_space_terrabytes_estimate = network_space_bytes_estimate / 1024 ** 4 print( f"The elapsed time between blocks is reported as {time_delta}.\n" f"The network has an estimated {network_space_terrabytes_estimate:.2f}TB" ) else: print("Block with header hash", oldblock_hash, "not found.")
def test_deserialization_simple_list(self): # ("hello" "friend") b = hexstr_to_bytes("ff8568656c6c6fff86667269656e6480") cost, output = DESERIALIZE_MOD.run_with_cost([b]) print(cost, output) prog = Program.to(output) assert prog == Program.from_bytes(b)
async def download_backup(host: str, private_key: PrivateKey): session = aiohttp.ClientSession() backup_privkey = master_sk_to_backup_sk(private_key) backup_pubkey = bytes(backup_privkey.get_g1()).hex() # Get nonce nonce_request = {"pubkey": backup_pubkey} nonce_url = f"{host}/get_download_nonce" nonce_response = await post(session, nonce_url, nonce_request) nonce = nonce_response["nonce"] # Sign nonce signature = bytes( AugSchemeMPL.sign(backup_privkey, std_hash(hexstr_to_bytes(nonce)))).hex() # Request backup url get_backup_url = f"{host}/download_backup" backup_request = {"pubkey": backup_pubkey, "signature": signature} backup_response = await post(session, get_backup_url, backup_request) # Download from s3 assert backup_response["success"] is True backup_url = backup_response["url"] backup_text = await get(session, backup_url) await session.close() return backup_text
async def get_transaction(args: dict, wallet_client: WalletRpcClient, fingerprint: int) -> None: wallet_id = args["id"] transaction_id = hexstr_to_bytes(args["tx_id"]) tx: TransactionRecord = await wallet_client.get_transaction( wallet_id, transaction_id=transaction_id) print_transaction(tx, verbose=(args["verbose"] > 0))
async def get_unspent_coins(self, request) -> web.Response: """ Retrieves the unspent coins for a given puzzlehash. """ request_data = await request.json() puzzle_hash = hexstr_to_bytes(request_data["puzzle_hash"]) if "header_hash" in request_data: header_hash = bytes32(hexstr_to_bytes(request_data["header_hash"])) header = self.full_node.blockchain.headers.get(header_hash) else: header = None coin_records = await self.full_node.blockchain.unspent_store.get_coin_records_by_puzzle_hash( puzzle_hash, header) return obj_to_response(coin_records)
async def get_additions_and_removals(self, request: Dict) -> Optional[Dict]: if "header_hash" not in request: raise ValueError("No header_hash in request") header_hash = hexstr_to_bytes(request["header_hash"]) block: Optional[ FullBlock] = await self.service.block_store.get_full_block( header_hash) if block is None: raise ValueError(f"Block {header_hash.hex()} not found") reward_additions = block.get_included_reward_coins() # TODO: optimize tx_removals, tx_additions = block.tx_removals_and_additions() removal_records = [] addition_records = [] for tx_removal in tx_removals: removal_records.append( await self.service.coin_store.get_coin_record(tx_removal)) for tx_addition in tx_additions + list(reward_additions): addition_records.append(await self.service.coin_store.get_coin_record( tx_addition.name())) return {"additions": addition_records, "removals": removal_records}
async def get_network_space(self, request: Dict) -> Optional[Dict]: """ Retrieves an estimate of total space validating the chain between two block header hashes. """ if ("newer_block_header_hash" not in request or "older_block_header_hash" not in request): return None newer_block_hex = request["newer_block_header_hash"] older_block_hex = request["older_block_header_hash"] if newer_block_hex == older_block_hex: return None newer_block_bytes = hexstr_to_bytes(newer_block_hex) older_block_bytes = hexstr_to_bytes(older_block_hex) newer_block = await self.service.block_store.get_block( newer_block_bytes) if newer_block is None: raise web.HTTPNotFound() older_block = await self.service.block_store.get_block( older_block_bytes) if older_block is None: raise web.HTTPNotFound() delta_weight = newer_block.header.data.weight - older_block.header.data.weight delta_iters = (newer_block.header.data.total_iters - older_block.header.data.total_iters) total_min_inters = await self.get_total_miniters( newer_block, older_block) if total_min_inters is None: raise web.HTTPNotFound() delta_iters -= total_min_inters weight_div_iters = delta_weight / delta_iters tips_adjustment_constant = 0.65 network_space_constant = 2**32 # 2^32 eligible_plots_filter_mult = ( 2**self.service.constants.NUMBER_ZERO_BITS_CHALLENGE_SIG) network_space_bytes_estimate = (weight_div_iters * network_space_constant * tips_adjustment_constant * eligible_plots_filter_mult) return { "success": True, "space": uint128(int(network_space_bytes_estimate)) }
async def get_header(self, request: Dict): if "header_hash" not in request: return None header_hash_str = request["header_hash"] header_hash = hexstr_to_bytes(header_hash_str) header: Optional[Header] = self.service.blockchain.headers.get( header_hash, None) return {"success": True, "header": header}
async def get_header(self, request: Dict): if "header_hash" not in request: raise ValueError("header_hash not in request") header_hash_str = request["header_hash"] header_hash = hexstr_to_bytes(header_hash_str) header: Optional[Header] = self.service.blockchain.headers.get( header_hash, None) return {"header": header}
def test_deserialization_password_coin(self): # (i (= (sha256 2) (q 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824)) (c (q 51) (c 5 (c (q 100) (q ())))) (q "wrong password")) # noqa b = hexstr_to_bytes( "ff04ffff0affff0bff0280ffff01ffa02cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b98248080ffff05ffff01ff3380ffff05ff05ffff05ffff01ff6480ffff01ff8080808080ffff01ff8e77726f6e672070617373776f72648080" # noqa ) # noqa cost, output = DESERIALIZE_MOD.run_with_cost([b]) print(cost, output) prog = Program.to(output) assert prog == Program.from_bytes(b)
def test_deserialization_large_numbers(self): # '(99999999999999999999999999999999999999999999999999999999999999999 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -99999999999999999999999999999999999999999999999999999999999999999999999999999)' # noqa b = hexstr_to_bytes( "ff9c00f316271c7fc3908a8bef464e3945ef7a253609ffffffffffffffffffb00fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1ff22ea0179500526edb610f148ec0c614155678491902d6000000000000000000180" # noqa ) # noqa cost, output = DESERIALIZE_MOD.run_with_cost([b]) print(cost, output) prog = Program.to(output) assert prog == Program.from_bytes(b)
def replace_str_to_bytes(self, **changes): """ Overrides str (hex) values with bytes. """ for k, v in changes.items(): if isinstance(v, str): changes[k] = hexstr_to_bytes(v) return dataclasses.replace(self, **changes)
async def get_unspent_coins(self, request: Dict) -> Optional[Dict]: """ Retrieves the unspent coins for a given puzzlehash. """ if "puzzle_hash" not in request: return None puzzle_hash = hexstr_to_bytes(request["puzzle_hash"]) header_hash = request.get("header_hash", None) if header_hash is not None: header_hash = bytes32(hexstr_to_bytes(header_hash)) header = self.service.blockchain.headers.get(header_hash) else: header = None coin_records = await self.service.blockchain.coin_store.get_coin_records_by_puzzle_hash( puzzle_hash, header) return {"success": True, "coin_records": coin_records}
async def close_connection(self, request: Dict): node_id = hexstr_to_bytes(request["node_id"]) if self.rpc_api.service.server is None: raise aiohttp.web.HTTPInternalServerError() connections_to_close = [c for c in self.rpc_api.service.server.get_connections() if c.peer_node_id == node_id] if len(connections_to_close) == 0: raise ValueError(f"Connection with node_id {node_id.hex()} does not exist") for connection in connections_to_close: await connection.close() return {}
async def get_mempool_item_by_tx_id(self, request: Dict) -> Optional[Dict]: if "tx_id" not in request: raise ValueError("No tx_id in request") tx_id: bytes32 = hexstr_to_bytes(request["tx_id"]) item = self.service.mempool_manager.get_mempool_item(tx_id) if item is None: raise ValueError(f"Tx id 0x{tx_id.hex()} not in the mempool") return {"mempool_item": item}
async def get_transaction(args: dict, wallet_client: WalletRpcClient, fingerprint: int) -> None: wallet_id = args["id"] transaction_id = hexstr_to_bytes(args["tx_id"]) config = load_config(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME) name = config["network_overrides"]["config"][ config["selected_network"]]["address_prefix"] tx: TransactionRecord = await wallet_client.get_transaction( wallet_id, transaction_id=transaction_id) print_transaction(tx, verbose=(args["verbose"] > 0), name=name)
async def cc_spend(self, request): wallet_id = int(request["wallet_id"]) wallet: CCWallet = self.wallet_node.wallet_state_manager.wallets[ wallet_id] puzzle_hash = hexstr_to_bytes(request["innerpuzhash"]) try: tx = await wallet.cc_spend(request["amount"], puzzle_hash) except BaseException as e: data = { "status": "FAILED", "reason": f"{e}", } return data if tx is None: data = { "status": "FAILED", "reason": "Failed to generate signed transaction", } return data self.log.error(tx) sent = False start = time.time() while time.time() - start < TIMEOUT: sent_to: List[Tuple[str, MempoolInclusionStatus, Optional[ str]]] = await self.wallet_node.wallet_state_manager.get_transaction_status( tx.name()) if len(sent_to) == 0: await asyncio.sleep(0.1) continue status, err = sent_to[0][1], sent_to[0][2] if status == MempoolInclusionStatus.SUCCESS: data = {"status": "SUCCESS"} sent = True break elif status == MempoolInclusionStatus.PENDING: assert err is not None data = {"status": "PENDING", "reason": err} sent = True break elif status == MempoolInclusionStatus.FAILED: assert err is not None data = {"status": "FAILED", "reason": err} sent = True break if not sent: data = { "status": "FAILED", "reason": "Timed out. Transaction may or may not have been sent.", } return data
async def get_block(self, request: Dict) -> Optional[Dict]: if "header_hash" not in request: raise ValueError("No header_hash in request") header_hash = hexstr_to_bytes(request["header_hash"]) block: Optional[FullBlock] = await self.service.block_store.get_block( header_hash) if block is None: raise ValueError(f"Block {header_hash.hex()} not found") return {"block": block}
async def get_block(self, request: Dict) -> Optional[Dict]: if "header_hash" not in request: return None header_hash = hexstr_to_bytes(request["header_hash"]) block: Optional[FullBlock] = await self.service.block_store.get_block( header_hash) if block is None: return None return {"success": True, "block": block}
async def cancel_trade(self, request: Dict): assert self.service.wallet_state_manager is not None wsm = self.service.wallet_state_manager secure = request["secure"] trade_id = hexstr_to_bytes(request["trade_id"]) if secure: await wsm.trade_manager.cancel_pending_offer_safely(trade_id) else: await wsm.trade_manager.cancel_pending_offer(trade_id) return {}
async def get_unspent_coins(self, request: Dict) -> Optional[Dict]: """ Retrieves the unspent coins for a given puzzlehash. """ if "puzzle_hash" not in request: raise ValueError("Puzzle hash not in request") puzzle_hash = hexstr_to_bytes(request["puzzle_hash"]) coin_records = await self.service.blockchain.coin_store.get_coin_records_by_puzzle_hash( puzzle_hash) return {"coin_records": coin_records}
async def get_block(self, request) -> web.Response: """ Retrieves a full block. """ request_data = await request.json() if "header_hash" not in request_data: raise web.HTTPBadRequest() header_hash = hexstr_to_bytes(request_data["header_hash"]) block: Optional[FullBlock] = await self.full_node.store.get_block(header_hash) if block is None: raise web.HTTPNotFound() return obj_to_response(block)
async def close_connection(self, request: Dict): node_id = hexstr_to_bytes(request["node_id"]) if self.service.global_connections is None: raise aiohttp.web.HTTPInternalServerError() connections_to_close = [ c for c in self.service.global_connections.get_connections() if c.node_id == node_id ] if len(connections_to_close) == 0: raise aiohttp.web.HTTPNotFound() for connection in connections_to_close: self.service.global_connections.close(connection) return {"success": True}
async def get_header(self, request) -> web.Response: """ Retrieves a Header. """ request_data = await request.json() if "header_hash" not in request_data: raise web.HTTPBadRequest() header_hash = hexstr_to_bytes(request_data["header_hash"]) header: Optional[Header] = self.full_node.blockchain.headers.get( header_hash, None) if header is None: raise web.HTTPNotFound() return obj_to_response(header)