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
0x02and votes carry version byte0x02. 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 onlyThe 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
| Type | Byte | Description |
|---|---|---|
send | 0x01 | Transfer funds to another account |
receive | 0x02 | Accept a pending send |
lease | 0x04 | Request a compute lease |
lease_accept | 0x05 | Provider accepts a lease |
lease_settle | 0x06 | Settle a completed lease |
genesis | 0x07 | Network genesis block |
multisig_open | 0x08 | Open a multisig account |
multisig_update | 0x09 | Rotate a multisig keyset |
lease_cancel | 0x0A | Cancel a lease before acceptance |
burn | 0x0B | Permanently destroy funds |
lease_force_settle | 0x0C | Consumer-driven settlement after the provider window closes |
mint | 0x0D | Authorized 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
| Offset | Size | Field |
|---|---|---|
| 90 | 32 | Destination (hex-decoded) |
| 122 | 8 | Amount (big-endian uint64) |
| 130 | 32 | Representative |
| 162 | 1 | Memo length (0..64) |
| 163 | N | Memo bytes (UTF-8) |
Total canonical size: 163 bytes + memo length.
Receive
| Offset | Size | Field |
|---|---|---|
| 90 | 32 | Source hash (hex-decoded) |
| 122 | 32 | Representative |
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
| Offset | Size | Field |
|---|---|---|
| 90 | 8 | Amount (big-endian uint64) |
| 98 | 32 | Representative |
| 130 | 1 | Memo length (0..64) |
| 131 | N | Memo bytes (UTF-8) |
Total canonical size: 131 bytes + memo length.
Mint
| Offset | Size | Field |
|---|---|---|
| 90 | 8 | Amount (big-endian uint64) |
| 98 | 32 | Representative |
Total canonical size: 130 bytes.
Lease
| Offset | Size | Field |
|---|---|---|
| 90 | 32 | Destination / provider (hex-decoded) |
| 122 | 8 | Amount (big-endian uint64) |
| 130 | 8 | vCPUs (big-endian uint64) |
| 138 | 8 | Memory MB (big-endian uint64) |
| 146 | 8 | Disk GB (big-endian uint64) |
| 154 | 8 | Duration seconds (big-endian uint64) |
| 162 | 32 | AccessPubKey (hex-decoded ed25519 public key; empty → 32 zero bytes) |
| 194 | 32 | Representative |
Total canonical size: 226 bytes.
LeaseAccept
| Offset | Size | Field |
|---|---|---|
| 90 | 32 | Source / lease hash (hex-decoded) |
| 122 | 8 | Amount (big-endian uint64) |
| 130 | 8 | LockedR (big-endian uint64) |
| 138 | 8 | LockedPayoutCap (big-endian uint64) |
| 146 | 8 | LockedTWAP (big-endian uint64) |
| 154 | 32 | Representative |
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
| Offset | Size | Field |
|---|---|---|
| 90 | 32 | Source / lease hash (hex-decoded) |
| 122 | 8 | Amount (big-endian uint64) |
| 130 | 32 | Representative |
Total canonical size: 162 bytes.
LeaseCancel / LeaseForceSettle
| Offset | Size | Field |
|---|---|---|
| 90 | 32 | Source / lease hash (hex-decoded) |
| 122 | 32 | Representative |
Total canonical size: 154 bytes.
MultisigOpen / MultisigUpdate
| Offset | Size | Field |
|---|---|---|
| 90 | 4 | Threshold (big-endian uint32) |
| 94 | 4 | Number of keys (big-endian uint32) |
| 98 | 32×N | Keys (sorted, hex-decoded, 32 bytes each) |
| 98+32N | 32 | Representative |
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
| Field | Encoding |
|---|---|
| Hex strings (account, previous, hashes) | Decoded to raw bytes (32 bytes each) |
| Asset | Left-aligned UTF-8, zero-padded to exactly 8 bytes |
Previous = "0" (open block) | 32 zero bytes |
| Balance, Amount | Big-endian uint64 |
| Timestamp | Big-endian int64 (unix nanoseconds) |
| PoW Nonce | Little-endian uint64 |
| Representative (empty) | 32 zero bytes |
| AccessPubKey (empty) | 32 zero bytes |
| Memo | 1-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 bytesThe 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:
| Function | Description |
|---|---|
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
- Cryptography -- hashing and signing over canonical bytes
- Proof of Work -- PoW computed over the block hash
- Block Types -- logical structure of each block type