-
Notifications
You must be signed in to change notification settings - Fork 51
How to Encode and Decode in Rlp
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.
- 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']);
- 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]);
- 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);
}
}
When decoding data that has been encoded using rlp, use UntrustedRlp.
- 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());
- 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)));
- 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)?,
})
}
}