Skip to content

How to Encode and Decode in Rlp

Juhyeong Park edited this page Jul 24, 2018 · 3 revisions

Using RlpStream

RlpStream is a struct that helps implementing serialize in Rlp format.

Rlp format can be considered boundless, since it does not fail when a mistake is made. However, this can result in an undesirable rlp encoding result. One should be especially cautious when differentiating append and append_single_value.

  1. Encoding a single value with rlp

Since it is not a list, use RlpStream::new() to create a new stream. Insert values into the stream by using append_single_value.

let mut stream = RlpStream::new();
stream.append_single_value(&"cat");
let out = stream.out();
assert_eq!(out, vec![0x83, b'c', b'a', b't']);
  1. Encoding multiple values with rlp

Allocate a list of desired length beforehand by using RlpStream::new_list(list_size). Use append to insert values into the stream.

let mut stream = RlpStream::new_list(3);
stream.append(&3_u8);
stream.append(&2_u8);
stream.append(&1_u8);
let out = stream.out();
assert_eq!(out, vec![0xc3, 3, 2, 1]);
  1. Implementing rlp::Encodable trait

When implementing rlp::Encodable, you must add the desired fields into the given streams. If struct only has a single value, add it into the stream by using append_single_value.

impl Encodable for Step {
   fn rlp_append(&self, s: &mut RlpStream) {
       s.append_single_value(&self.number());
   }
}

If struct has multiple values, use stream.begin_list(list_size) to reserve the size of the list beforehand, and then use stream.append to add values.

impl Encodable for Metadata {
   fn rlp_append(&self, s: &mut RlpStream) {
       s.begin_list(2).append(&PREFIX).append(&self.number_of_shards);
   }
}

Using UntrustedRlp

When decoding data that has been encoded using rlp, use UntrustedRlp.

  1. Decoding a single value

You can change a single value by using UntrustedRlp.as_val().

let encoded = vec![0x83, b'c', b'a', b't'];
let rlp = UntrustedRlp::new(encoded.as_ref());
assert_eq!(Ok("cat".to_string()), rlp.as_val());
  1. Decoding multiple values

When there are multiple values, use UntrustedRlp::at to choose the desired value(s). UntrustedRlp::at returns UntrustedRlp and it must be converted into the desired value type using as_val.

let encoded =  vec![0xc3, 3, 2, 1];
let rlp = UntrustedRlp::new(encoded.as_ref());

assert_eq!(Ok(3_u8), rlp.at(0).and_then(|e| UntrustedRlp::as_val(&e)));
assert_eq!(Ok(2_u8), rlp.at(1).and_then(|e| UntrustedRlp::as_val(&e)));
assert_eq!(Ok(1_u8), rlp.at(2).and_then(|e| UntrustedRlp::as_val(&e)));
  1. Implementing rlp::Decodable

The decode function receives UntrustedRlp and creates an object. By using functions that were used above, decode can be implemented easily.

impl Decodable for Block {
   fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
       Ok(Block {
           header: rlp.val_at(0)?,
           parcels: rlp.list_at(1)?,
       })
   }
}