Primitives and Basic Serialization Rules
CLValue
CLValue
describes data that is used by smart contracts. This could be a local state variable, input argument, or return value. A CLValue
consists of two parts: a CLType
describing the type of the value and an array of bytes representing the data in our serialization format.
CLType
is described by the following recursive data type:
enum CLType {
Bool, // boolean primitive
I32, // signed 32-bit integer primitive
I64, // signed 64-bit integer primitive
U8, // unsigned 8-bit integer primitive
U32, // unsigned 32-bit integer primitive
U64, // unsigned 64-bit integer primitive
U128, // unsigned 128-bit integer primitive
U256, // unsigned 256-bit integer primitive
U512, // unsigned 512-bit integer primitive
Unit, // singleton value without additional semantics
String, // e.g. "Hello, World!"
URef, // unforgeable reference (see above)
Key, // global state key (see above)
PublicKey // A Casper system PublicKey type
Option(CLType), // optional value of the given type
List(CLType), // list of values of the given type (e.g. Vec in rust)
ByteArray(CLType, u32), // same as `List` above, but number of elements
// is statically known (e.g. arrays in rust)
Result(CLType, CLType), // co-product of the given types;
// one variant meaning success, the other failure
Map(CLType, CLType), // key-value association where keys and values have the given types
Tuple1(CLType), // single value of the given type
Tuple2(CLType, CLType), // pair consisting of elements of the given types
Tuple3(CLType, CLType, CLType), // triple consisting of elements of the given types
Any // Indicates the type is not known
}
All data that can be assigned a (non-Any
) CLType
can be serialized according to the following rules, which define the Casper serialization format:
Boolean
Boolean values serialize as a single byte; true
maps to 1
, while false
maps to 0
.
Numeric
Numeric values consisting of 64 bits or less serialize in the two's complement representation with little-endian byte order, and the appropriate number of bytes for the bit-width.
-
E.g.
7u8
serializes as0x07
-
E.g.
7u32
serializes as0x07000000
-
E.g.
1024u32
serializes as0x00040000
-
Wider numeric values (i.e.
U128
,U256
,U512
) serialize as one byte given the length of the next number (in bytes), followed by the two's complement representation with little-endian byte order. The number of bytes should be chosen as small as possible to represent the given number. This reduces the serialization size when small numbers are represented within a wide data type. -
E.g.
U512::from(7)
serializes as0x0107
-
E.g.
U512::from(1024)
serializes as0x020004
-
E.g.
U512::from("123456789101112131415")
serializes as0x0957ff1ada959f4eb106
Unit
Unit serializes to an empty byte array.
String
Strings serialize as a 32-bit integer representing the length in bytes (that might be different than the number of characters since special characters, such as emojis, take more than one byte), followed by the UTF-8 encoding of the characters in the string.
- E.g.
"Hello, World!"
serializes as0x0d00000048656c6c6f2c20576f726c6421