The Lux P-chain wire is ZAP. The Go struct IS the wire — there is no
codec, no marshal step, no encode or decode. An AdvanceTimeTx is a
buffer; accessors are offset reads on that buffer; Bytes() returns
the buffer.
Activated at the genesis of the new final Lux network:
2025-12-25 16:20 Pacific (unix 1766708400).
There is no other wire on this network. No legacy. No backwards
compatibility. The pre-Quasar Edition Lux network (2020–2025) is a
separate network and is out of scope.
type AdvanceTimeTx struct {
msg *zap.Message // the wire buffer itself
obj zap.Object // typed window into msg
}
func (t AdvanceTimeTx) Time() uint64 { return t.obj.Uint64(OffsetTime) } // offset read
func (t AdvanceTimeTx) Bytes() []byte { return t.msg.Bytes() } // return buffer
There is no Marshal. There is no Unmarshal. There is no Encode.
There is no Decode. There is no Serialize. Parse(b) wraps b in
a typed accessor — it does not copy and does not decode. Build(...)
writes fields into a buffer at known offsets and the buffer is the
wire bytes — there is no encoding pass over it.
This is the Cap'n-Proto / FlatBuffers invariant: **wire format is the
in-memory representation**.
tx.Bytes() returns the underlying buffer literally. Parse(b) wraps
b in a typed accessor. TxID = sha256(buffer). No re-encoding step
anywhere in the hot path.
~/work/lux/node/vms/platformvm/txs/zap_native/ is the package; one
file per tx type. Each Go struct embeds a *zap.Message; the buffer
IS the value.
Tx types in scope (P-chain platformvm):
AdvanceTimeTx
RewardValidatorTx
SetL1ValidatorWeightTx
IncreaseL1ValidatorBalanceTx
DisableL1ValidatorTx
BaseTx
RegisterL1ValidatorTx
SlashValidatorTx
TransferChainOwnershipTx
RemoveChainValidatorTx
AddValidatorTx
AddDelegatorTx
CreateNetworkTx
CreateChainTx
ImportTx
ExportTx
TransformChainTx
AddPermissionlessValidatorTx
AddPermissionlessDelegatorTx
ConvertNetworkToL1Tx
CreateSovereignL1Tx
CreateAssetTx
OperationTx
Variable-length fields (Memo, Outs, Ins, Credentials, Warp messages,
Evidence) use ZAP's length-prefixed nested-object protocol — still no
codec step, still a buffer with offset reads.
TxID = sha256.Sum256(tx.Bytes())
tx.Bytes() returns the ZAP buffer. No re-canonicalization. No
re-encoding. The hash domain consumes whatever the wire layer
presents.
Same shape — block bytes are the ZAP buffer for the block envelope;
block ID is sha256.Sum256(block.Bytes()).
Wires owned by other repositories:
luxfi/crypto/bls — BLS signature wire (embedded in signed txcredentials as opaque bytes)
luxfi/zap — ZAP itself (LP-022)External RPC surface:
luxd JSON-RPC API (/ext/bc/P, /ext/info, etc.) — JSON at theprocess boundary, not a P-chain wire surface.
One wire. Decomplection: the wire layer does exactly one job
(present typed accessors over a byte buffer). Multiple wires would
braid two unrelated concerns (which wire to read) with one job
(read the bytes).
ZAP because the struct IS the wire. Every other option — protobuf,
RLP, linearcodec, msgpack, hand-rolled binary — is a codec: serialize
on write, deserialize on read. ZAP eliminates the step. The buffer is
the value. tx.Bytes() returns it. sha256(tx.Bytes()) requires no
re-encoding. That is the property no other option offers.
Activation at the genesis of the new final Lux network. The new
generation came online 2026-05-31 (devnet) and 2026-06-01 (testnet,
mainnet). Activation timestamp predates every block on the new
generation. Every P-chain tx on the new final Lux network is a ZAP
tx by construction. The v1.10.x luxd binary running today not yet
implementing native ZAP wire is a binary defect to close in the next
release — not a chain-history fact to preserve.
None.
The new final Lux network has one P-chain wire, present in the binary
from the release that ships this LP. A node presenting non-ZAP bytes
for a P-chain tx is not a member of the network by definition.
The pre-Quasar Edition Lux network (2020–2025) used linearcodec for
P-chain. That network is separate and not migrated.
None. Activation predates every block on the network. There are no
pre-activation blocks to replay under a different wire.
None. The binary speaks ZAP. Byte input that fails ZAP parse is
rejected. No LUXD_ENABLE_LEGACY_CODEC knob, no dispatch by magic
byte, no runtime selection.
P-chain interop with non-Go consensus stubs follows the same rule as
LP-182: every reference implementation reads the schema definitions
in ~/work/lux/node/vms/platformvm/txs/zap_native/schemas.go as the
single source of truth, and CI gates byte-equality before any release.
Reference implementation lives in
~/work/lux/node/vms/platformvm/txs/zap_native/. The legacy
~/work/lux/codec/linearcodec package is removed from the P-chain
hot path — codec.Codec{Marshal, Unmarshal} is not called from the
new final Lux generation's P-chain code.
~/work/lux/node/vms/platformvm/txs/codec.go (the legacy multi-version
Manager) is deleted alongside the linearcodec callsites. There is no
multi-version anything. There is one wire.
TestAdvanceTimeTxBuildParseFieldEquality build → Bytes() → Parse → fields equal
TestAdvanceTimeTxBytesIsUnderlyingBuffer Bytes() returns msg buffer, no copy
TestAdvanceTimeTxParseRefusesNonZAP non-ZAP bytes reject at Parse
TestPChainTxIDStability sha256(Bytes()) byte-identical to fixture
TestCrossImpl_ByteEquality_AllTxTypes python/cpp/c/rust ≡ Go on every tx type
TestNoLegacyCodecInBinary grep build symbols — no Marshal*, no
linearcodec, no codec.Codec in platformvm
Lives in ~/work/lux/node/vms/platformvm/txs/zap_native/.
~/work/lux/node/vms/platformvm/txs/zap_native/ — lands in the luxd
release carrying this LP.
Every future Lux network-upgrade LP that changes the P-chain wire on
the new final Lux network MUST use the same activation marker as
this LP:
activates: 2025-12-25T16:20:00-08:00
activates-unix: 1766708400
Set once. Does not move.
Measured impact, Apple M1 Max, Go 1.24, real platformvm tx types
(parse only; build is one-time per-proposer and dwarfed by the L1
finality budget):
Geometric mean Parse speedup across 10 types: 8.5×. Parse is the
per-validator-per-block hot path.
The "Pre-LP" column is the cost of the codec step that no longer
exists on the new final Lux network.
Reproduce:
cd ~/work/lux/node/vms/platformvm/txs/zap_native && GOWORK=off go test -bench=. -benchmem -benchtime=2s
CC0.