use blockchain::common::binary_conversions::binary_to_string; use blockchain::common::cli_prompts::prompt_hidden_nonempty; use blockchain::common::network_startup::get_connections; use blockchain::env; use blockchain::json; use blockchain::records::memory::response_channels::generate_uid; use blockchain::standalone_tools::connections::handshake; use blockchain::to_string_pretty; fn decode_token_list(response: &[u8]) -> Option { // An empty binary payload means the peer has no token index entries. if response.is_empty() { return Some("{\n \"tokens\": []\n}".to_string()); } // Each token-list row is 15 bytes token name and 64 bytes token hash text. if response.len() % 79 != 0 { return None; } let mut tokens = Vec::new(); let mut offset = 0; while offset + 79 <= response.len() { // Convert fixed-width padded fields back into display strings. let token = binary_to_string(response[offset..offset + 15].to_vec()) .trim() .to_string(); let hash = binary_to_string(response[offset + 15..offset + 79].to_vec()) .trim() .to_string(); if !token.is_empty() && !hash.is_empty() { tokens.push(json!({ "token": token, "hash": hash, })); } offset += 79; } let output = json!({ "tokens": tokens, }); to_string_pretty(&output).ok() } #[tokio::main] async fn main() { // Command 31 asks a peer for the full token list. let hashmap_key = generate_uid(); let rpc_command = 31; // This lookup takes no user arguments beyond the wallet key used for handshake auth. let args: Vec = env::args().collect(); if args.len() != 1 { println!("Usage: ./token_list"); return; } let encryption_key = prompt_hidden_nonempty( "What is your wallet decryption key? ", "Wallet key cannot be empty. Please try again.", ) .await; // Try each configured peer until one returns a parsable token list or text error. let connections = get_connections().await; let mut connected = false; for conn in connections { if connected { break; } let socket_address = conn.parse().expect("Failed to parse the socket address"); let result = handshake::connect_and_handshake( socket_address, "".to_string(), rpc_command, handshake::HandshakeWallet::WalletKey(encryption_key.clone()), hashmap_key, ) .await; match result { Ok(response) => { // Prefer binary token-list decoding; otherwise print a text error if one was returned. if let Some(output) = decode_token_list(&response) { println!("{output}"); connected = true; } else { let response_text = String::from_utf8_lossy(&response); let trimmed = response_text.trim(); if !trimmed.is_empty() { println!("{trimmed}"); connected = true; } else { connected = false; } } } Err(_) => { connected = false; } } } if !connected { eprintln!("failed to connect"); } }