Binary Encoding

Binary Encoding

The XE network uses a deterministic binary encoding format for blocks and votes. This encoding is critical for hashing, signing, and network serialization -- all implementations must produce byte-identical output for the same logical data.

[!IMPORTANT] Version 2 is current Blocks carry version byte 0x02 and votes carry version byte 0x02. There is no dual-decode logic: a mismatched version byte is rejected outright.

Block canonical encoding

The canonical encoding is used for computing block hashes and signatures. It excludes the PoW nonce -- only the content that the account holder signs is included.

Field layout

Offset  Size  Field
──────  ────  ─────
0       1     Version byte (0x02)
1       1     Type byte
2       8     Asset (left-aligned UTF-8, zero-padded to 8 bytes)
10      32    Account (hex-decoded to raw 32 bytes)
42      32    Previous (hex-decoded; "0" → 32 zero bytes)
74      8     Balance (big-endian uint64)
82      8     Timestamp (big-endian int64)
90+     var   Type-specific tail (see below)
+32           Representative (32 zero bytes if empty)
+48           Genesis lease timing — genesis only, and only when pinned
+1+N          Memo length (1 byte, 0..64) then memo bytes — send and burn only

The fixed header is 90 bytes. The representative is appended after the type-specific tail, and the two optional trailers (genesis lease timing, memo) come after the representative.

Type bytes

TypeByteDescription
send0x01Transfer funds to another account
receive0x02Accept a pending send
lease0x04Request a compute lease
lease_accept0x05Provider accepts a lease
lease_settle0x06Settle a completed lease
genesis0x07Network genesis block
multisig_open0x08Open a multisig account
multisig_update0x09Rotate a multisig keyset
lease_cancel0x0ACancel a lease before acceptance
burn0x0BPermanently destroy funds
lease_force_settle0x0CConsumer-driven settlement after the provider window closes
mint0x0DAuthorized minter issues XUSD

0x03 is unused. It formerly encoded a permissionless claim block, which was removed along with PoW self-minting; XUSD is now issued by an authorized minter through mint.

Type-specific tails

Each block type appends additional fields after the common 90-byte header. Sizes below include the trailing 32-byte representative.

Send

OffsetSizeField
9032Destination (hex-decoded)
1228Amount (big-endian uint64)
13032Representative
1621Memo length (0..64)
163NMemo bytes (UTF-8)

Total canonical size: 163 bytes + memo length.

Receive

OffsetSizeField
9032Source hash (hex-decoded)
12232Representative

Total canonical size: 154 bytes.

Genesis

No type-specific tail. The representative follows the header directly.

Total canonical size: 122 bytes, or 170 bytes when the genesis pins lease timing (see below).

Burn

OffsetSizeField
908Amount (big-endian uint64)
9832Representative
1301Memo length (0..64)
131NMemo bytes (UTF-8)

Total canonical size: 131 bytes + memo length.

Mint

OffsetSizeField
908Amount (big-endian uint64)
9832Representative

Total canonical size: 130 bytes.

Lease

OffsetSizeField
9032Destination / provider (hex-decoded)
1228Amount (big-endian uint64)
1308vCPUs (big-endian uint64)
1388Memory MB (big-endian uint64)
1468Disk GB (big-endian uint64)
1548Duration seconds (big-endian uint64)
16232AccessPubKey (hex-decoded ed25519 public key; empty → 32 zero bytes)
19432Representative

Total canonical size: 226 bytes.

LeaseAccept

OffsetSizeField
9032Source / lease hash (hex-decoded)
1228Amount (big-endian uint64)
1308LockedR (big-endian uint64)
1388LockedPayoutCap (big-endian uint64)
1468LockedTWAP (big-endian uint64)
15432Representative

Total canonical size: 186 bytes.

The three locked emission parameters ride in the signed bytes so every node records identical settle-rate inputs regardless of which epoch it applies the accept in. lease_settle does not carry them -- it reads the lease record.

LeaseSettle

OffsetSizeField
9032Source / lease hash (hex-decoded)
1228Amount (big-endian uint64)
13032Representative

Total canonical size: 162 bytes.

LeaseCancel / LeaseForceSettle

OffsetSizeField
9032Source / lease hash (hex-decoded)
12232Representative

Total canonical size: 154 bytes.

MultisigOpen / MultisigUpdate

OffsetSizeField
904Threshold (big-endian uint32)
944Number of keys (big-endian uint32)
9832×NKeys (sorted, hex-decoded, 32 bytes each)
98+32N32Representative

Total canonical size: 130 + 32N bytes.

Keys are sorted lexicographically before encoding. This ensures the same keyset always produces the same canonical encoding and thus the same derived address.

Genesis lease-timing tail

A genesis block may pin the network's lease timing. When at least one of the six fields is non-zero, a 48-byte tail is appended after the representative:

Offset  Size  Field
──────  ────  ─────
+0      8     Lease minimum duration (seconds, big-endian uint64)
+8      8     Lease settle grace (nanoseconds, big-endian int64)
+16     8     Lease force-settle gap (nanoseconds, big-endian int64)
+24     8     Lease escrow expiry (nanoseconds, big-endian int64)
+32     8     Lease archive gap (nanoseconds, big-endian int64)
+40     8     Maximum attestation skew (nanoseconds, big-endian int64)

When every field is zero the tail is omitted entirely, so an all-default genesis hashes identically to one produced before the feature existed. These fields are rejected on any block type other than genesis.

Auxiliary hashed fields

Lease-family blocks (lease, lease_accept, lease_settle, lease_force_settle) carry two variable-length fields that are attached after the body and travel in the JSON wire form rather than the canonical bytes: the certificate hash and the timekeeper attestations. MarshalBlockAux encodes them separately -- each length-prefixed with an 8-byte big-endian length, attestations sorted by public key -- and the block hash covers that output as well. Reordering attestations does not change the hash; adding, removing, or swapping one does.

For every other block type -- including lease_cancel -- MarshalBlockAux returns nothing and the hash is unchanged.

Full block encoding

The full block encoding appends the PoW nonce after the canonical bytes:

[ canonical bytes ] [ 8 bytes PoW nonce (little-endian uint64) ]

This is the format used for storage and network transmission. The MarshalBlock function produces this format, and UnmarshalBlock parses it. UnmarshalBlock treats the nonce as optional: it is decoded only when exactly 8 trailing bytes are present.

Field encoding rules

FieldEncoding
Hex strings (account, previous, hashes)Decoded to raw bytes (32 bytes each)
AssetLeft-aligned UTF-8, zero-padded to exactly 8 bytes
Previous = "0" (open block)32 zero bytes
Balance, AmountBig-endian uint64
TimestampBig-endian int64 (unix nanoseconds)
PoW NonceLittle-endian uint64
Representative (empty)32 zero bytes
AccessPubKey (empty)32 zero bytes
Memo1-byte length (always present on send/burn) then UTF-8 bytes

[!WARNING] Endianness The PoW nonce uses little-endian encoding while all other numeric fields use big-endian. This is intentional and must be preserved across implementations.

Vote encoding

Votes are serialized for signing and network transmission:

Offset  Size  Field
──────  ────  ─────
0       1     Version byte (0x02)
1       32    Representative public key (hex-decoded)
33      32    Block hash (hex-decoded)
65      32    Conflict account (hex-decoded)
97      32    Conflict previous (hex-decoded; "0" → 32 zero bytes)
129     8     Timestamp (big-endian int64)
137     1     Final flag (0 = converge, 1 = final)
138     2     Signature length (big-endian uint16)
140     N     Signature bytes

The signed payload is the first 138 bytes; the signature length and signature follow it. The final flag is inside the signed payload, so a converge vote cannot be forged into a final vote by flipping the bit.

Functions

The encoding package exposes the following functions:

FunctionDescription
MarshalBlockCanonical(block)Encode a block for hashing/signing (no PoW nonce)
MarshalBlockAux(block)Encode the certificate hash and attestations bound into a lease-family block's hash
MarshalBlock(block)Full encoding including PoW nonce trailer
UnmarshalBlock(data)Decode a full block from bytes
EncodeVote(vote)Serialize a vote for signing/transmission
DecodeVote(data)Deserialize a vote from bytes

See also