How do I convert Base58-encoded data to a Vec<u8> and then into a String?


Keywords:rust 


Question: 

I am trying to convert a Vec to a String for display. I have tried to use from_uf8 and from_iter with no luck.

use rust_base58::{ToBase58, FromBase58};

let address = String::from("1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH");
let _hash160 = address.from_base58();
let mut s = String::from_utf8(_hash160).unwrap();
//let s = String::from_iter(_hash160);
s.remove(0);
s.pop();
s.pop();
s.pop();
s.pop();
println!("{}", s);

2 Answers: 

.from_base58()

returns

Result<Vec<u8>, FromBase58Error>

because the conversion can fail if the data isn't valid Base 58.

Assuming you want to ignore the error like you did for from_utf8, you'll need to .unwrap() that to get the Vec<u8> that you are looking for, e.g.

let hash160 = address.from_base58().unwrap();
let mut s = String::from_utf8(hash160).unwrap();

and the rest should compile fine, following the instructions laid out in How do I convert a Vector of bytes (u8) to a string.

When you're making the code production-ready, definitely make sure to handle the errors without .unwrap() though.



The error tells you part of the problem.

 --> src/main.rs:7:35
  |
7 |     let mut s = String::from_utf8(_hash160).unwrap();
  |                                   ^^^^^^^^ expected struct `std::vec::Vec`, found enum `std::result::Result`
  |
  = note: expected type `std::vec::Vec<_>`
             found type `std::result::Result<std::vec::Vec<_>, rust_base58::base58::FromBase58Error>`
  = help: here are some functions which might fulfill your needs:
          - .unwrap()
          - .unwrap_or_default()

You're trying to use _hash160 as a Vec<u8>. But from_base58 returns a Result<Vec<u8>, FromBase58Error>. You have to deal with that Result. A full program would have error handling, but for now we can use unwrap which will error if the _hash160 is an error.

let _hash160 = address.from_base58().unwrap();

_hash160 is fine, but we get an error from String::from_utf8(_hash160).unwrap();.

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: FromUtf8Error { bytes: [0, 117, 30, 118, 232, 25, 145, 150, 212, 84, 148, 28, 69, 209, 179, 163, 35, 241, 67, 59, 214, 81, 13, 22, 52], error: Utf8Error { valid_up_to: 4, error_len: Some(1) } }'

Utf8Error tells us that the 5th byte is invalid. The sequence of bytes in hash160 is not a valid UTF8 string.

If we try String::from_utf8_lossy...

println!("{}", String::from_utf8_lossy(&_hash160));

...we get a bunch of nonsense.

4v����T�Eѳ�#�C;�Q

It's not a valid ASCII string either, 232 is too high. We can check this explicitly with std::ascii::AsciiExt::is_ascii.

use std::ascii::AsciiExt;

...

# false
println!("{}", _hash160.is_ascii());

You'll likely just have to treat this as a sequence of bytes. You can print it in debug mode.

println!("{:?}", _hash160);

Which gives:

[0, 117, 30, 118, 232, 25, 145, 150, 212, 84, 148, 28, 69, 209, 179, 163, 35, 241, 67, 59, 214, 81, 13, 22, 52]