diff --git a/frameworks/moveos-stdlib/sources/bcs.move b/frameworks/moveos-stdlib/sources/bcs.move index df64c10c3f..2e54319fea 100644 --- a/frameworks/moveos-stdlib/sources/bcs.move +++ b/frameworks/moveos-stdlib/sources/bcs.move @@ -12,10 +12,15 @@ module moveos_std::bcs{ friend moveos_std::any; friend moveos_std::copyable_any; + friend moveos_std::address; /// The request Move type is not match with input Move type. const ErrorTypeNotMatch: u64 = 1; const ErrorInvalidBytes: u64 = 2; + const ErrorInvalidLength: u64 = 3; + const ErrorInvalidBool: u64 = 4; + const ErrorOutOfRange: u64 = 5; + const ErrorLengthOutOfRange: u64 = 6; public fun to_bytes(v: &MoveValue): vector{ std::bcs::to_bytes(v) @@ -41,6 +46,327 @@ module moveos_std::bcs{ from_bytes
(v) } + /// Read `address` value from the bcs-serialized bytes. + public fun peel_address(v: vector): address { + assert!(vector::length(&v) >= address::length(), ErrorInvalidLength); + let i = 0; + let addr_bytes = vector::empty(); + while (i < address::length()) { + let byte = vector::pop_back(&mut v); + vector::push_back(&mut addr_bytes, byte); + i = i + 1; + }; + to_address(addr_bytes) + } + + /// Read a `bool` value from bcs-serialized bytes. + public fun peel_bool(v: vector): bool { + let value = peel_u8(v); + if (value == 0) { + return false + } else if (value == 1) { + return true + } else { + abort ErrorInvalidBool + } + } + + /// Read `u8` value from bcs-serialized bytes. + public fun peel_u8(v: vector): u8 { + assert!(vector::length(&v) >= 1, ErrorOutOfRange); + vector::pop_back(&mut v) + } + + /// Read `u16` value from bcs-serialized bytes. + public fun peel_u16(v: vector): u16 { + assert!(vector::length(&v) >= 2, ErrorOutOfRange); + let value = 0; + let i = 0; + let bits = 16u8; + while (i < bits) { + let byte = vector::pop_back(&mut v); + value = value + (byte << (i as u8)); + i = i + 8; + }; + + value + } + + /// Read `u32` value from bcs-serialized bytes. + public fun peel_u32(v: vector): u32 { + assert!(vector::length(&v) >= 4, ErrorOutOfRange); + let value = 0; + let i = 0; + let bits = 32u8; + while (i < bits) { + let byte = vector::pop_back(&mut v); + value = value + (byte << (i as u8)); + i = i + 8; + }; + + value + } + + /// Read `u64` value from bcs-serialized bytes. + public fun peel_u64(v: vector): u64 { + assert!(vector::length(&v) >= 8, ErrorOutOfRange); + let value = 0; + let i = 0; + let bits = 64u8; + while (i < bits) { + let byte = vector::pop_back(&mut v); + value = value + (byte << (i as u8)); + i = i + 8; + }; + + value + } + + /// Read `u128` value from bcs-serialized bytes. + public fun peel_u128(v: vector): u128 { + assert!(vector::length(&v) >= 16, ErrorOutOfRange); + let value = 0; + let i = 0; + let bits = 128u8; + while (i < bits) { + let byte = vector::pop_back(&mut v); + value = value + (byte << (i as u8)); + i = i + 8; + }; + + value + } + + /// Read `u256` value from bcs-serialized bytes. + public fun peel_u256(v: vector): u256 { + assert!(vector::length(&v) >= 32, ErrorOutOfRange); + let value = 0; + let i = 0; + let bits = 256u16; + while (i < bits) { + let byte = vector::pop_back(&mut v); + value = value + (byte << (i as u8)); + i = i + 8; + }; + + value + } + + // === Vector === + + /// Read ULEB bytes expecting a vector length. Result should + /// then be used to perform `peel_*` operation LEN times. + /// + /// In BCS `vector` length is implemented with ULEB128; + /// See more here: https://en.wikipedia.org/wiki/LEB128 + public fun peel_vec_length(v: vector): u64 { + let total = 0u64; + let shift = 0; + let len = 0; + loop { + assert!(len <= 4, ErrorLengthOutOfRange); + let byte = vector::pop_back(&mut v) as u64; + len = len + 1; + total = total | ((byte & 0x7f) << shift); + if ((byte & 0x80) == 0) { + break; + } + shift = shift + 7; + }; + total + } + + /// Peel a vector of `address` from serialized bytes. + public fun peel_vec_address(v: vector): vector
{ + let len = peel_vec_length(v); + let i = 0; + let addresses = vector::empty
(); + while (i < len) { + let address = peel_address(v); + vector::push_back(&mut addresses, address); + i = i + 1; + }; + addresses + } + + /// Peel a vector of `address` from serialized bytes. + public fun peel_vec_bool(v: vector): vector { + let len = peel_vec_length(v); + let i = 0; + let bools = vector::empty(); + while (i < len) { + let bool = peel_bool(v); + vector::push_back(&mut bools, bool); + i = i + 1; + }; + bools + } + + /// Peel a vector of `u8` (eg string) from serialized bytes. + public fun peel_vec_u8(v: vector): vector { + let len = peel_vec_length(v); + let i = 0; + let u8s = vector::empty(); + while (i < len) { + let u8 = peel_u8(v); + vector::push_back(&mut u8s, u8); + i = i + 1; + }; + u8s + } + + /// Peel a `vector>` (eg vec of string) from serialized bytes. + public fun peel_vec_vec_u8(v: vector): vector> { + let len = peel_vec_length(v); + let i = 0; + let vec_u8s = vector::empty>(); + while (i < len) { + let vec_u8 = peel_vec_u8(v); + vector::push_back(&mut vec_u8s, vec_u8); + i = i + 1; + }; + vec_u8s + } + + /// Peel a vector of `u16` from serialized bytes. + public fun peel_vec_u16(v: vector): vector { + let len = peel_vec_length(v); + let i = 0; + let u16s = vector::empty(); + while (i < len) { + let u16 = peel_u16(v); + vector::push_back(&mut u16s, u16); + i = i + 1; + }; + u16s + } + + /// Peel a vector of `u32` from serialized bytes. + public fun peel_vec_u32(v: vector): vector { + let len = peel_vec_length(v); + let i = 0; + let u32s = vector::empty(); + while (i < len) { + let u32 = peel_u32(v); + vector::push_back(&mut u32s, u32); + i = i + 1; + }; + u32s + } + + /// Peel a vector of `u64` from serialized bytes. + public fun peel_vec_u64(v: vector): vector { + let len = peel_vec_length(v); + let i = 0; + let u64s = vector::empty(); + while (i < len) { + let u64 = peel_u64(v); + vector::push_back(&mut u64s, u64); + i = i + 1; + }; + u64s + } + + /// Peel a vector of `u128` from serialized bytes. + public fun peel_vec_u128(v: vector): vector { + let len = peel_vec_length(v); + let i = 0; + let u128s = vector::empty(); + while (i < len) { + let u128 = peel_u128(v); + vector::push_back(&mut u128s, u128); + i = i + 1; + }; + u128s + } + + /// Peel a vector of `u256` from serialized bytes. + public fun peel_vec_u256(v: vector): vector { + let len = peel_vec_length(v); + let i = 0; + let u256s = vector::empty(); + while (i < len) { + let u256 = peel_u256(v); + vector::push_back(&mut u256s, u256); + i = i + 1; + }; + u256s + } + + // === Option === + + /// Peel `Option
` from serialized bytes. + public fun peel_option_address(v: vector): Option
{ + if (peel_bool(v)) { + option::some(peel_address(v)) + } else { + option::none() + } + } + + /// Peel `Option` from serialized bytes. + public fun peel_option_bool(v: vector): Option { + if (peel_bool(v)) { + option::some(peel_bool(v)) + } else { + option::none() + } + } + + /// Peel `Option` from serialized bytes. + public fun peel_option_u8(v: vector): Option { + if (peel_bool(v)) { + option::some(peel_u8(v)) + } else { + option::none() + } + } + + /// Peel `Option` from serialized bytes. + public fun peel_option_u16(v: vector): Option { + if (peel_bool(v)) { + option::some(peel_u16(v)) + } else { + option::none() + } + } + + /// Peel `Option` from serialized bytes. + public fun peel_option_u32(v: vector): Option { + if (peel_bool(v)) { + option::some(peel_u32(v)) + } else { + option::none() + } + } + + /// Peel `Option` from serialized bytes. + public fun peel_option_u64(v: vector): Option { + if (peel_bool(v)) { + option::some(peel_u64(v)) + } else { + option::none() + } + } + + /// Peel `Option` from serialized bytes. + public fun peel_option_u128(v: vector): Option { + if (peel_bool(v)) { + option::some(peel_u128(v)) + } else { + option::none() + } + } + + /// Peel `Option` from serialized bytes. + public fun peel_option_u256(v: vector): Option { + if (peel_bool(v)) { + option::some(peel_u256(v)) + } else { + option::none() + } + } + #[data_struct(T)] /// Function to deserialize a type T. /// Note the `data_struct` ensure the `T` must be a `#[data_struct]` type