schemas: PVM + Warp ZAP schemas (pvm/{txs,block,state}.zap, warp/message.zap)

- pvm/txs.zap: 23 structs, TxKind 1-23 mirrored from proto/zap_native/kind.go.
  Includes CreateNetworkTx, CreateChainTx, ConvertNetworkToL1Tx (L1-bootstrap
  path used by liquidity-network-bootstrap), AddValidator/Delegator/Subnet
  variants, RegisterL1ValidatorTx, ImportTx/ExportTx (X<->P), reward + advance-time.
- pvm/block.zap: 14 structs, v1 canonical (CommonBlock + 4 variants) + v0
  read-only (Apricot + Banff variants for history parsing).
- pvm/state.zap: 12 structs, L1Validator, validator/delegator metadata,
  ExpiryEntry, ChainIDNodeID, ValidatorWeightDiff, HeightRange, TxBytesAndStatus,
  NetToL1Conversion.
- warp/message.zap: 17 structs, UnsignedMessage + 4 sig variants (BLS,
  CoronaSignature, HybridBLSCoronaSignature, EncryptedWarpPayload), 2 payload
  types (AddressedCall, Hash), 4 L1 lifecycle messages, PChainOwner, 3 Teleport.

Documentation-first per existing utxo.zap convention. shape_kind=0xNN
annotation aspirational; current zapgen rejects (matches utxo.zap).
Offsets cross-checked against proto/zap_native constants for txs.zap.
This commit is contained in:
Hanzo AI
2026-06-07 11:27:10 -07:00
parent a928e46c75
commit a0acc0b8ae
4 changed files with 2194 additions and 0 deletions
+311
View File
@@ -0,0 +1,311 @@
# Copyright (C) 2026, Lux Industries Inc. All rights reserved.
# See the file LICENSE for licensing terms.
#
# P-chain (platformvm) block envelope schemas.
#
# Consumed by: github.com/luxfi/proto/p/block and downstream node
# package github.com/luxfi/node/vms/platformvm/block. Codegen emits
# *_zap.go siblings next to the generated Go consumers.
#
# Wire envelope convention: [TypeKind:1][ShapeKind:1][ZAP message: N].
# Block envelopes carry their own TypeKind on the outer envelope; the
# inner Txs/Tx fields carry signed-tx envelopes that dispatch on the
# tx ShapeKind set declared in pvm/txs.zap.
#
# Block parser dispatch (node/vms/platformvm/block/parse.go) reads the
# 2-byte codec version prefix and routes either to v0Codec (legacy
# Apricot/Banff layout) or to the current v1 Codec — there is no single
# discriminator that distinguishes Standard / Proposal / Commit / Abort
# above the codec slot map. The schema below mirrors that, declaring
# each block kind as a standalone struct.
#
# Two eras coexist:
#
# - v1 (current write target) — block/codec.go registers
# ProposalBlock, AbortBlock, CommitBlock, StandardBlock under
# CodecVersionV1. Every block produced post-codec-v1 is one of
# these four kinds.
# - v0 (read-only) — block/v0/types.go declares the historical
# Apricot/Banff layout still on disk + still parsed for chain
# history. ApricotAtomicBlock is dead on the modern P-only network
# but appears in pre-Banff archives.
#
# Source mapping:
# node/vms/platformvm/block/common_block.go -> CommonBlock
# node/vms/platformvm/block/standard_block.go -> StandardBlock
# node/vms/platformvm/block/proposal_block.go -> ProposalBlock
# node/vms/platformvm/block/commit_block.go -> CommitBlock
# node/vms/platformvm/block/abort_block.go -> AbortBlock
# node/vms/platformvm/block/v0/types.go -> Apricot*/Banff*
package block
# ----------------------------------------------------------------------
# Primitive aliases
# ----------------------------------------------------------------------
type id32 = bytes_fixed[32]
# ----------------------------------------------------------------------
# CommonBlock — shared parent-id + height fields
# ----------------------------------------------------------------------
#
# Embedded by every block kind (v0 and v1). Wire-equal across eras.
# BlockID is derived (hash(blockBytes)) — NOT serialised — so it does
# not appear here.
#
# Fixed section: 32 (PrntID) + 8 (Hght) = 40
struct CommonBlock
shape_kind = 0x50 # ShapeKindPCommonBlock
{
# PrntID is the 32-byte BlockID of the parent block.
PrntID id32 @0
# Hght is the block height. Genesis is at height 0.
Hght u64 @32
}
# ======================================================================
# v1 canonical blocks (block/codec.go CodecVersionV1)
# ======================================================================
#
# Each v1 block carries an in-header Time field (Banff-style) and one
# of: a tx list (StandardBlock), a tx list + proposal Tx (ProposalBlock),
# or no payload (CommitBlock / AbortBlock).
# ----------------------------------------------------------------------
# StandardBlock — N decision txs, carries the chain timestamp
# ----------------------------------------------------------------------
#
# Carries an ordered list of standard txs (Add*Validator, CreateChain,
# Import/Export, ...). The block's Time field replaces the legacy
# AdvanceTimeTx flow.
#
# Wire field order matches the embedded-CommonBlock layout the codec
# emits: Time, then CommonBlock fields, then Transactions.
#
# Fixed section: 8 (Time) + 40 (CommonBlock) + 8 (Transactions) = 56
struct StandardBlock
shape_kind = 0x51 # ShapeKindPStandardBlock
{
# Time is the unix-seconds timestamp this block proposes the
# chain advance to.
Time u64 @0
# CommonBlock fields are embedded inline.
PrntID id32 @8
Hght u64 @40
# Transactions is the ordered list of signed-tx envelopes carried
# by this block.
Transactions bytes @48
}
# ----------------------------------------------------------------------
# ProposalBlock — one proposal tx + tail of decision txs
# ----------------------------------------------------------------------
#
# Carries exactly one proposal Tx (AdvanceTimeTx pre-Banff;
# RewardValidatorTx Banff+) plus a tail of decision Txs that commit
# atomically with the proposal outcome.
#
# A ProposalBlock MUST be followed by either a CommitBlock (the
# proposal's effect is accepted) or an AbortBlock (rejected).
#
# Fixed section: 8 (Time) + 8 (Transactions) + 40 (CommonBlock) +
# 4 (Tx) = 60
struct ProposalBlock
shape_kind = 0x52 # ShapeKindPProposalBlock
{
Time u64 @0
# Transactions is the decision-tx tail. May be empty.
Transactions bytes @8
# CommonBlock fields are embedded inline.
PrntID id32 @16
Hght u64 @48
# Tx is the single proposal Tx. Dispatch on the inner Tx
# ShapeKind: RewardValidatorTx (0x33) on Banff+, AdvanceTimeTx
# (0x34) on pre-Banff archives.
Tx bytes @56
}
# ----------------------------------------------------------------------
# CommitBlock — accept the parent ProposalBlock's proposal
# ----------------------------------------------------------------------
#
# Carries no payload — its acceptance is the proposal outcome.
#
# Fixed section: 8 (Time) + 40 (CommonBlock) = 48
struct CommitBlock
shape_kind = 0x53 # ShapeKindPCommitBlock
{
Time u64 @0
PrntID id32 @8
Hght u64 @40
}
# ----------------------------------------------------------------------
# AbortBlock — reject the parent ProposalBlock's proposal
# ----------------------------------------------------------------------
#
# Carries no payload.
#
# Fixed section: 8 (Time) + 40 (CommonBlock) = 48
struct AbortBlock
shape_kind = 0x54 # ShapeKindPAbortBlock
{
Time u64 @0
PrntID id32 @8
Hght u64 @40
}
# ======================================================================
# v0 read-only blocks (block/v0/types.go CodecVersionV0)
# ======================================================================
#
# These shapes are decoded ONLY — block/codec.go gcV0 codec is read-only,
# write paths target v1 exclusively. The schemas below mirror the
# pre-codec-v1 v1.23.x Apricot/Banff layout still on disk. Block IDs
# derived from these bytes remain stable across the v0->v1 migration.
# ----------------------------------------------------------------------
# ApricotProposalBlock — pre-Banff proposal block (slot 0)
# ----------------------------------------------------------------------
#
# Apricot-era proposal block. No header timestamp — pre-Banff blocks
# advance time only via the embedded AdvanceTimeTx proposal Tx.
#
# Fixed section: 40 (CommonBlock) + 4 (Tx) = 44
struct ApricotProposalBlock
shape_kind = 0x55 # ShapeKindPApricotProposalBlock
{
PrntID id32 @0
Hght u64 @32
# Tx is the single proposal Tx (typically AdvanceTimeTx in
# Apricot history).
Tx bytes @40
}
# ----------------------------------------------------------------------
# ApricotAbortBlock — pre-Banff abort block (slot 1)
# ----------------------------------------------------------------------
#
# Fixed section: 40 (CommonBlock) = 40
struct ApricotAbortBlock
shape_kind = 0x56 # ShapeKindPApricotAbortBlock
{
PrntID id32 @0
Hght u64 @32
}
# ----------------------------------------------------------------------
# ApricotCommitBlock — pre-Banff commit block (slot 2)
# ----------------------------------------------------------------------
#
# Fixed section: 40 (CommonBlock) = 40
struct ApricotCommitBlock
shape_kind = 0x57 # ShapeKindPApricotCommitBlock
{
PrntID id32 @0
Hght u64 @32
}
# ----------------------------------------------------------------------
# ApricotStandardBlock — pre-Banff standard block (slot 3)
# ----------------------------------------------------------------------
#
# Pre-Banff standard block: no header timestamp, just the embedded
# tx list.
#
# Fixed section: 40 (CommonBlock) + 8 (Transactions) = 48
struct ApricotStandardBlock
shape_kind = 0x58 # ShapeKindPApricotStandardBlock
{
PrntID id32 @0
Hght u64 @32
Transactions bytes @40
}
# ----------------------------------------------------------------------
# ApricotAtomicBlock — pre-Banff atomic block (slot 4, DEAD)
# ----------------------------------------------------------------------
#
# Atomic-block flow is dead on the modern P-only network — these
# blocks only appear in pre-Banff archive history. Retained here only
# to keep historical bytes decoding.
#
# Fixed section: 40 (CommonBlock) + 4 (Tx) = 44
struct ApricotAtomicBlock
shape_kind = 0x59 # ShapeKindPApricotAtomicBlock
{
PrntID id32 @0
Hght u64 @32
# Tx is the single atomic Tx (ImportTx or ExportTx).
Tx bytes @40
}
# ----------------------------------------------------------------------
# BanffProposalBlock — Banff-era proposal block (slot 29)
# ----------------------------------------------------------------------
#
# Wraps an ApricotProposalBlock with a Banff-era per-block Time
# header + a tail of decision Txs (Transactions). On-wire field order
# is Time, then Transactions, then the embedded ApricotProposalBlock.
#
# Fixed section: 8 (Time) + 8 (Transactions) + 44 (ApricotProposalBlock) = 60
struct BanffProposalBlock
shape_kind = 0x5A # ShapeKindPBanffProposalBlock
{
Time u64 @0
Transactions bytes @8
# ApricotProposalBlock embedded inline (PrntID, Hght, Tx).
PrntID id32 @16
Hght u64 @48
Tx bytes @56
}
# ----------------------------------------------------------------------
# BanffAbortBlock — Banff-era abort block (slot 30)
# ----------------------------------------------------------------------
#
# Fixed section: 8 (Time) + 40 (ApricotAbortBlock) = 48
struct BanffAbortBlock
shape_kind = 0x5B # ShapeKindPBanffAbortBlock
{
Time u64 @0
PrntID id32 @8
Hght u64 @40
}
# ----------------------------------------------------------------------
# BanffCommitBlock — Banff-era commit block (slot 31)
# ----------------------------------------------------------------------
#
# Fixed section: 8 (Time) + 40 (ApricotCommitBlock) = 48
struct BanffCommitBlock
shape_kind = 0x5C # ShapeKindPBanffCommitBlock
{
Time u64 @0
PrntID id32 @8
Hght u64 @40
}
# ----------------------------------------------------------------------
# BanffStandardBlock — Banff-era standard block (slot 32)
# ----------------------------------------------------------------------
#
# Fixed section: 8 (Time) + 48 (ApricotStandardBlock) = 56
struct BanffStandardBlock
shape_kind = 0x5D # ShapeKindPBanffStandardBlock
{
Time u64 @0
PrntID id32 @8
Hght u64 @40
Transactions bytes @48
}
+342
View File
@@ -0,0 +1,342 @@
# Copyright (C) 2026, Lux Industries Inc. All rights reserved.
# See the file LICENSE for licensing terms.
#
# P-chain (platformvm) state-value schemas.
#
# These are the on-disk state records the platformvm writes to its
# state DB. Distinct from txs.zap (wire/tx envelopes) and block.zap
# (block envelopes) — these are KV-store value shapes only.
#
# Consumed by: github.com/luxfi/proto/p/state and downstream node
# package github.com/luxfi/node/vms/platformvm/state. Codegen emits
# *_zap.go siblings next to the generated Go consumers.
#
# Wire envelope convention: [TypeKind:1][ShapeKind:1][ZAP message: N].
# State values use TypeKindReserved (0x00) on the outer envelope.
#
# UTXO values are referenced — full UTXO schema lives in
# utxo/utxo.zap. Per-validator-set indexing uses the (chainID, nodeID)
# compound key; the layout below records that key shape so the on-disk
# format is documented in one place.
#
# Source mapping:
# node/vms/platformvm/state/l1_validator.go -> L1Validator
# node/vms/platformvm/state/expiry.go -> ExpiryEntry
# node/vms/platformvm/state/chain_id_node_id.go -> ChainIDNodeID
# node/vms/platformvm/state/metadata_validator.go -> ValidatorMetadata + variants
# node/vms/platformvm/state/metadata_delegator.go -> DelegatorMetadata
# node/vms/platformvm/state/state.go ~L255 -> StateBlk (legacy)
# node/vms/platformvm/state/state.go ~L481 -> HeightRange
# node/vms/platformvm/state/state.go ~L486 -> ValidatorWeightDiff
# node/vms/platformvm/state/state.go ~L516 -> TxBytesAndStatus
# node/vms/platformvm/state/state.go ~L531 -> NetToL1Conversion
package state
# ----------------------------------------------------------------------
# Primitive aliases
# ----------------------------------------------------------------------
type id32 = bytes_fixed[32]
type id20 = bytes_fixed[20]
# ----------------------------------------------------------------------
# L1Validator — LP-77 L1 validator on-disk record
# ----------------------------------------------------------------------
#
# Stored under the L1 active/inactive prefixes keyed by ValidationID.
# ValidationID is the KV key and is NOT serialised inside the value.
#
# For a given ValidationID, the constant fields (ChainID, NodeID,
# PublicKey, RemainingBalanceOwner, DeactivationOwner, StartTime) MUST
# remain unchanged across writes (state.ErrMutatedL1Validator otherwise).
#
# Fixed section: 32 (ChainID) + 20 (NodeID) + 8 (PublicKey) +
# 8 (RemainingBalanceOwner) + 8 (DeactivationOwner) + 8 (StartTime) +
# 8 (Weight) + 8 (MinNonce) + 8 (EndAccumulatedFee) = 108
struct L1Validator
shape_kind = 0x70 # ShapeKindPStateL1Validator
{
# ChainID is the 32-byte L1 chain ID this validator is in.
ChainID id32 @0
# NodeID is the 20-byte short-id of the validator's node.
NodeID id20 @32
# PublicKey is the validator's uncompressed BLS public key.
# Guaranteed populated for active L1 validators.
PublicKey bytes @52
# RemainingBalanceOwner is the codec-marshalled fx.Owner that
# receives the validator's remaining balance after fee accrual,
# at the time the validator is removed from the set.
RemainingBalanceOwner bytes @60
# DeactivationOwner is the codec-marshalled fx.Owner authorised
# to manually deactivate this validator.
DeactivationOwner bytes @68
# StartTime is the unix-seconds timestamp this validator was
# added to the set.
StartTime u64 @76
# Weight is the validator's sampling weight. Updates require
# MinNonce++. Setting Weight=0 removes the validator (and uses
# the reserved MaxUint64 nonce).
Weight u64 @84
# MinNonce is the smallest nonce the next weight-update may use.
# Reserved MaxUint64 = removal-only.
MinNonce u64 @92
# EndAccumulatedFee is the total accrued fees per validator at
# which this validator must be deactivated. 0 = inactive.
EndAccumulatedFee u64 @100
}
# ----------------------------------------------------------------------
# ExpiryEntry — RegisterL1Validator replay-protection record
# ----------------------------------------------------------------------
#
# Stored under ExpiryReplayProtectionPrefix. The (Timestamp,
# ValidationID) pair forms both the key AND value identity — values
# are written empty; the key bytes are this struct's marshal.
#
# Fixed section: 8 (Timestamp) + 32 (ValidationID) = 40
struct ExpiryEntry
shape_kind = 0x71 # ShapeKindPStateExpiryEntry
{
# Timestamp is the unix-seconds expiry deadline.
Timestamp u64 @0
# ValidationID is the hashed-payload ID of the
# RegisterL1Validator warp message this expiry guards.
ValidationID id32 @8
}
# ----------------------------------------------------------------------
# ChainIDNodeID — (chainID, nodeID) compound key
# ----------------------------------------------------------------------
#
# Compound key for the per-chain validator-set index
# (L1Validators.HasL1Validator lookup, chain validator state
# membership). Total 52 bytes (chainID 32 + nodeID 20).
#
# Fixed section: 32 (ChainID) + 20 (NodeID) = 52
struct ChainIDNodeID
shape_kind = 0x72 # ShapeKindPStateChainIDNodeID
{
ChainID id32 @0
NodeID id20 @32
}
# ----------------------------------------------------------------------
# ValidatorMetadata — v1+ validator on-chain stats record
# ----------------------------------------------------------------------
#
# Stored per (txID -> validatorMetadata) under the current-validator
# linkedDB. Holds uptime + reward accumulators + the staker-start
# timestamp.
#
# Parse path tolerates four historical sizes (parseValidatorMetadata):
# 0 — nothing stored (legacy nil)
# 8 (Uint64Size) — PotentialReward only
# preDelegateeRewardSize — UpDuration + LastUpdated + PotentialReward
# preStakerStartTimeSize — adds PotentialDelegateeReward
# default (v1+) — adds StakerStartTime
#
# The struct below is the v1+ wire layout. The legacy short forms are
# declared as separate structs so codegen accessors exist for both.
#
# Fixed section: 8 (UpDuration) + 8 (LastUpdated) +
# 8 (PotentialReward) + 8 (PotentialDelegateeReward) +
# 8 (StakerStartTime) = 40
struct ValidatorMetadata
shape_kind = 0x73 # ShapeKindPStateValidatorMetadata
{
# UpDuration is the cumulative uptime in nanoseconds (Go
# time.Duration). LastUpdated tracks when this was last bumped.
UpDuration u64 @0
LastUpdated u64 @8
# PotentialReward is the accrued validation reward (in nLUX) the
# validator is eligible for at exit-time, contingent on uptime
# meeting reward.Calculator's UptimeRequirement.
PotentialReward u64 @16
# PotentialDelegateeReward is the validator's share of accrued
# delegation rewards.
PotentialDelegateeReward u64 @24
# StakerStartTime is the unix-seconds time the validator entered
# the active set. Distinct from the Validator.Start field on the
# original AddValidatorTx (which may pre-date the actual entry
# for pending validators).
StakerStartTime u64 @32
}
# ----------------------------------------------------------------------
# PreDelegateeRewardMetadata — pre-PotentialDelegateeReward layout
# ----------------------------------------------------------------------
#
# Apricot-era validator metadata. Lacks PotentialDelegateeReward and
# StakerStartTime. Decoded read-only by parseValidatorMetadata when
# the stored value has size preDelegateeRewardSize.
#
# Fixed section: 8 (UpDuration) + 8 (LastUpdated) +
# 8 (PotentialReward) = 24
struct PreDelegateeRewardMetadata
shape_kind = 0x74 # ShapeKindPStatePreDelegateeRewardMetadata
{
UpDuration u64 @0
LastUpdated u64 @8
PotentialReward u64 @16
}
# ----------------------------------------------------------------------
# PreStakerStartTimeMetadata — pre-StakerStartTime layout
# ----------------------------------------------------------------------
#
# Banff-era validator metadata with delegatee reward but without
# StakerStartTime. Decoded read-only by parseValidatorMetadata when
# the stored value has size preStakerStartTimeSize.
#
# Fixed section: 8 (UpDuration) + 8 (LastUpdated) +
# 8 (PotentialReward) + 8 (PotentialDelegateeReward) = 32
struct PreStakerStartTimeMetadata
shape_kind = 0x75 # ShapeKindPStatePreStakerStartTimeMetadata
{
UpDuration u64 @0
LastUpdated u64 @8
PotentialReward u64 @16
PotentialDelegateeReward u64 @24
}
# ----------------------------------------------------------------------
# DelegatorMetadata — delegator on-chain stats record
# ----------------------------------------------------------------------
#
# Stored per (txID -> delegatorMetadata) under the current-delegator
# linkedDB. Parse path also tolerates the legacy 8-byte-only form
# (PotentialReward as a bare uint64) for pre-StakerStartTime
# delegators.
#
# Fixed section: 8 (PotentialReward) + 8 (StakerStartTime) = 16
struct DelegatorMetadata
shape_kind = 0x76 # ShapeKindPStateDelegatorMetadata
{
# PotentialReward is the accrued delegation reward (in nLUX) the
# delegator is eligible for at exit-time.
PotentialReward u64 @0
# StakerStartTime is the unix-seconds time the delegator entered
# the active set.
StakerStartTime u64 @8
}
# ----------------------------------------------------------------------
# ValidatorWeightDiff — per-height validator-set weight diff
# ----------------------------------------------------------------------
#
# Stored under ValidatorWeightDiffsPrefix keyed by (chainID + height +
# nodeID). Replays let ApplyValidatorWeightDiffs reconstruct a past
# validator set from a future one.
#
# Fixed section: 1 (Decrease) + 8 (Amount) + 32 (ValidationID) = 41
struct ValidatorWeightDiff
shape_kind = 0x77 # ShapeKindPStateValidatorWeightDiff
{
# Decrease=1 means the diff subtracts Amount from the validator's
# weight; =0 means it adds.
Decrease u8 @0
# Amount is the absolute weight delta.
Amount u64 @1
# ValidationID preserves the originating tx/validation ID across
# diff replays so the validator-set entry remains keyed correctly.
ValidationID id32 @9
}
# ----------------------------------------------------------------------
# HeightRange — indexed-heights span singleton value
# ----------------------------------------------------------------------
#
# Stored at HeightsIndexedKey. Marks the (lower, upper) inclusive
# range of heights for which the validator-diff index is consistent
# and safe to use the native DB iterator over.
#
# Fixed section: 8 (LowerBound) + 8 (UpperBound) = 16
struct HeightRange
shape_kind = 0x78 # ShapeKindPStateHeightRange
{
LowerBound u64 @0
UpperBound u64 @8
}
# ----------------------------------------------------------------------
# TxBytesAndStatus — stored tx value (bytes + acceptance status)
# ----------------------------------------------------------------------
#
# Stored under TxPrefix keyed by TxID. Carries the raw signed-tx
# bytes plus the platformvm/status.Status enum (Aborted=1, Committed=2,
# Processing=3, Unknown=4, Dropped=5 — see node/vms/platformvm/status).
#
# Fixed section: 8 (Tx) + 4 (Status) = 12
struct TxBytesAndStatus
shape_kind = 0x79 # ShapeKindPStateTxBytesAndStatus
{
# Tx is the full signed-tx bytes — these are the exact bytes the
# producer wrote (byte-preserving). Decoding routes through the
# codec version prefix on the bytes themselves.
Tx bytes @0
# Status is the acceptance state of this tx (a uint32 enum from
# node/vms/platformvm/status).
Status u32 @8
}
# ----------------------------------------------------------------------
# StateBlk — LEGACY pre-PR-#1719 block-storage envelope (read-only)
# ----------------------------------------------------------------------
#
# Stored under the legacy block KV prefix in pre-v1.14.x state DBs.
# RegisterStateBlockType registers this on block.GenesisCodec so
# parseStoredBlock can fall back to it for old DB upgrades.
#
# Modern (post-PR-#1719) block storage writes raw block bytes — this
# envelope is read-only legacy.
#
# Fixed section: 8 (Bytes) + 4 (Status) = 12
struct StateBlk
shape_kind = 0x7A # ShapeKindPStateBlk
{
# Bytes is the legacy-wrapped block-bytes payload.
Bytes bytes @0
# Status is the legacy choices.Status enum value.
Status u32 @8
}
# ----------------------------------------------------------------------
# NetToL1Conversion — chain-to-L1 conversion summary record
# ----------------------------------------------------------------------
#
# Stored under NetToL1ConversionPrefix keyed by chainID. Captures the
# canonical conversion ID + manager-chain handoff for a chain that
# went through ConvertNetworkToL1Tx.
#
# Fixed section: 32 (ConversionID) + 32 (ChainID) + 8 (Addr) = 72
struct NetToL1Conversion
shape_kind = 0x7B # ShapeKindPStateNetToL1Conversion
{
# ConversionID is the hash-derived ID over the conversion's
# canonical data (see warp.ChainToL1ConversionID).
ConversionID id32 @0
# ChainID is the manager-chain ID (where the validator-manager
# contract lives post-conversion).
ChainID id32 @32
# Addr is the validator-manager contract address on ChainID.
Addr bytes @64
}
+1015
View File
File diff suppressed because it is too large Load Diff
+526
View File
@@ -0,0 +1,526 @@
# Copyright (C) 2026, Lux Industries Inc. All rights reserved.
# See the file LICENSE for licensing terms.
#
# Lux Interchain Messaging (Warp) message schemas.
#
# Consumed by: github.com/luxfi/proto/p/warp and downstream node
# package github.com/luxfi/node/vms/platformvm/warp + Warp-using
# VMs (coreth atomic, xvm import/export). Codegen emits *_zap.go
# siblings next to the generated Go consumers.
#
# Wire envelope convention: [TypeKind:1][ShapeKind:1][ZAP message: N].
# Warp outer envelopes carry their own TypeKind on the discriminator;
# the inner Payload bytes carry an AddressedCall / Hash discriminator
# from the payload codec.
#
# Two layered codec slot maps coexist:
#
# - Warp signature codec (warp/codec.go) registers (in order):
# 0x00 BitSetSignature
# 0x01 CoronaSignature
# 0x02 EncryptedWarpPayload
# 0x03 HybridBLSCoronaSignature (DEPRECATED)
# 0x04 TeleportMessage
# 0x05 TeleportTransferPayload
# 0x06 TeleportAttestPayload
#
# - Warp message codec (warp/message/codec.go) registers (in order):
# 0x00 ChainToL1Conversion
# 0x01 RegisterL1Validator
# 0x02 L1ValidatorRegistration
# 0x03 L1ValidatorWeight
#
# - Warp payload codec (warp/payload/codec.go) registers (in order):
# 0x00 Hash
# 0x01 AddressedCall
#
# Each ShapeKind value below names the underlying wire type. Reordering
# any of the upstream codec lines is a hard fork — append-only.
#
# Source mapping:
# node/vms/platformvm/warp/unsigned_message.go -> UnsignedMessage
# node/vms/platformvm/warp/signature.go -> BitSetSignature, CoronaSignature,
# HybridBLSCoronaSignature, EncryptedWarpPayload
# node/vms/platformvm/warp/teleport.go -> TeleportMessage, TeleportTransferPayload,
# TeleportAttestPayload
# node/vms/platformvm/warp/payload/addressed_call.go -> AddressedCall
# node/vms/platformvm/warp/payload/hash.go -> Hash
# node/vms/platformvm/warp/message/chain_to_l1_conversion.go -> ChainToL1Conversion + data
# node/vms/platformvm/warp/message/register_l1_validator.go -> RegisterL1Validator + PChainOwner
# node/vms/platformvm/warp/message/l1_validator_registration.go -> L1ValidatorRegistration
# node/vms/platformvm/warp/message/l1_validator_weight.go -> L1ValidatorWeight
package message
# ----------------------------------------------------------------------
# Primitive aliases
# ----------------------------------------------------------------------
type id32 = bytes_fixed[32]
type id20 = bytes_fixed[20]
type bls48 = bytes_fixed[48] # bls.PublicKey compressed (G1)
type sig96 = bytes_fixed[96] # bls.Signature (G2)
# ======================================================================
# Unsigned + signed Warp messages
# ======================================================================
# ----------------------------------------------------------------------
# UnsignedMessage — outer Warp envelope before signature aggregation
# ----------------------------------------------------------------------
#
# The canonical bytes that BLS / Corona aggregate signatures cover.
# ID = hash(Bytes) where Bytes is the codec marshal of this struct
# under warp.CodecVersion.
#
# Fixed section: 4 (NetworkID) + 32 (SourceChainID) + 8 (Payload) = 44
struct UnsignedMessage
shape_kind = 0x80 # ShapeKindWarpUnsignedMessage
{
# NetworkID is the Lux primary network ID the message was emitted
# on. Verification rejects messages with NetworkID != local
# (warp.ErrWrongNetworkID).
NetworkID u32 @0
# SourceChainID is the 32-byte chain ID the message originated
# on. Determines which canonical validator set verifies the
# aggregate signature.
SourceChainID id32 @4
# Payload is the application-level bytes — typically an
# AddressedCall or Hash payload (see payload codec slots above).
Payload bytes @36
}
# ----------------------------------------------------------------------
# BitSetSignature — Warp 1.0 classical BLS aggregate signature
# ----------------------------------------------------------------------
#
# typeID 0x00 in the warp codec slot map. Classical BLS aggregate
# signature with a signer-bitset selector indexing into the canonical
# validator set at the message's SourceChainID + height.
#
# Fixed section: 8 (Signers) + 96 (Signature) = 104
struct BitSetSignature
shape_kind = 0x81 # ShapeKindWarpBitSetSignature
{
# Signers is a big-endian byte slice encoding a bitmap of which
# canonical validators contributed to the aggregate. Length MUST
# equal len(set.BitsFromBytes(Signers).Bytes()) — no extraneous
# leading-zero padding.
Signers bytes @0
# Signature is the 96-byte BLS aggregate signature (G2) over the
# UnsignedMessage bytes.
Signature sig96 @8
}
# ----------------------------------------------------------------------
# CoronaSignature — Warp 1.5 post-quantum lattice signature
# ----------------------------------------------------------------------
#
# typeID 0x01 in the warp codec slot map. Lattice-based threshold
# signature (LWE / Ring-LWE; ref github.com/luxfi/corona). Replaces
# BitSetSignature for new Warp messages.
#
# Fixed section: 8 (Signers) + 8 (Signature) = 16
struct CoronaSignature
shape_kind = 0x82 # ShapeKindWarpCoronaSignature
{
# Signers is a big-endian bitmap of contributing validators.
Signers bytes @0
# Signature is the Corona threshold-signature blob. Variable
# length — depends on threshold parameters (M, N, Dbar, Kappa).
# Carries (c challenge polynomial, z response vector, Delta hint
# vector) per the Corona protocol.
Signature bytes @8
}
# ----------------------------------------------------------------------
# HybridBLSCoronaSignature — DEPRECATED transitional hybrid
# ----------------------------------------------------------------------
#
# typeID 0x03 in the warp codec slot map. Both BLS and Corona
# signatures MUST verify for the hybrid to be accepted.
#
# Deprecated: use CoronaSignature. Retained because the typeID is
# committed to history — reordering this line is a hard fork.
#
# Fixed section: 8 (Signers) + 96 (BLSSignature) +
# 8 (CoronaSignature) + 8 (CoronaPublicKeys) = 120
struct HybridBLSCoronaSignature
shape_kind = 0x83 # ShapeKindWarpHybridBLSCoronaSignature
{
Signers bytes @0
# BLSSignature is the 96-byte BLS aggregate signature.
BLSSignature sig96 @8
# CoronaSignature is the aggregated Corona lattice signature.
CoronaSignature bytes @104
# CoronaPublicKeys is the list of per-signer Corona public keys,
# in the same order as the Signers bitset enumerates. Needed
# because validators may have distinct Corona vs BLS keys.
CoronaPublicKeys bytes @112
}
# ----------------------------------------------------------------------
# EncryptedWarpPayload — ML-KEM-768 + AES-256-GCM sealed payload
# ----------------------------------------------------------------------
#
# typeID 0x02 in the warp codec slot map. Wraps a confidential
# cross-chain payload (private bridges, sealed bids, MEV-protected
# intents). Carried inside a TeleportMessage when
# MessageType=TeleportPrivate.
#
# Fixed section: 8 (EncapsulatedKey) + 8 (Nonce) +
# 8 (Ciphertext) + 8 (RecipientKeyID) = 32
struct EncryptedWarpPayload
shape_kind = 0x84 # ShapeKindWarpEncryptedPayload
{
# EncapsulatedKey is the ML-KEM-768 ciphertext carrying the
# encapsulated shared secret. Length MUST equal 1088 bytes
# (MLKEM768CiphertextLen) at runtime.
EncapsulatedKey bytes @0
# Nonce is the 12-byte AES-GCM nonce.
Nonce bytes @8
# Ciphertext is the AES-256-GCM encrypted payload, including the
# trailing 16-byte authentication tag.
Ciphertext bytes @16
# RecipientKeyID identifies the recipient's ML-KEM public key
# (typically a hash of the public key) so recipients know which
# private key to use for decryption.
RecipientKeyID bytes @24
}
# ======================================================================
# Payload codec slot map (warp/payload/codec.go)
# ======================================================================
# ----------------------------------------------------------------------
# AddressedCall — addressed cross-chain call payload
# ----------------------------------------------------------------------
#
# typeID 0x01 in the warp payload codec. Carries a source address +
# arbitrary application payload. Destination address (if any) is
# encoded inside Payload, not at this layer.
#
# Fixed section: 8 (SourceAddress) + 8 (Payload) = 16
struct AddressedCall
shape_kind = 0x85 # ShapeKindWarpAddressedCall
{
# SourceAddress is the issuing address on the source chain
# (chain-specific encoding).
SourceAddress bytes @0
# Payload is the inner application payload bytes.
Payload bytes @8
}
# ----------------------------------------------------------------------
# Hash — finality-relay block-hash payload
# ----------------------------------------------------------------------
#
# typeID 0x00 in the warp payload codec. Single-field payload carrying
# a block hash to attest finality of.
#
# Fixed section: 32 (Hash) = 32
struct Hash
shape_kind = 0x86 # ShapeKindWarpHash
{
# Hash is the 32-byte block-hash being attested.
Hash id32 @0
}
# ======================================================================
# Message codec slot map (warp/message/codec.go) — L1 lifecycle messages
# ======================================================================
# ----------------------------------------------------------------------
# ChainToL1Conversion — primary-net summary of a chain conversion
# ----------------------------------------------------------------------
#
# typeID 0x00 in the warp message codec. P-chain emits this message
# after a successful ConvertNetworkToL1Tx, communicating the conversion
# to the receiving L1.
#
# Carried payload is the ID (hash of the ChainToL1ConversionData blob).
#
# Fixed section: 32 (ID) = 32
struct ChainToL1Conversion
shape_kind = 0x87 # ShapeKindWarpChainToL1Conversion
{
# ID is the canonical conversion ID — hash(ChainToL1ConversionData
# bytes). Receiving L1s compute the same hash from their stored
# conversion data to verify.
ID id32 @0
}
# ----------------------------------------------------------------------
# ChainToL1ConversionData — payload hashed into ChainToL1Conversion.ID
# ----------------------------------------------------------------------
#
# Not a wire-codec slot — this is the canonical pre-image whose hash
# becomes ChainToL1Conversion.ID. Both sides marshal this and compare
# the hash to verify.
#
# Fixed section: 32 (ChainID) + 32 (ManagerChainID) +
# 8 (ManagerAddress) + 8 (Validators) = 80
struct ChainToL1ConversionData
shape_kind = 0x88 # ShapeKindWarpChainToL1ConversionData
{
ChainID id32 @0
ManagerChainID id32 @32
ManagerAddress bytes @64
# Validators: list of ChainToL1ConversionValidatorData.
Validators bytes @72
}
# ----------------------------------------------------------------------
# ChainToL1ConversionValidatorData — one validator entry
# ----------------------------------------------------------------------
#
# Per-validator data hashed into the conversion ID. Wire-encoded as a
# JSONByteSlice NodeID + fixed-length BLS pubkey + weight.
#
# Fixed section: 8 (NodeID) + 48 (BLSPublicKey) + 8 (Weight) = 64
struct ChainToL1ConversionValidatorData
shape_kind = 0x89 # ShapeKindWarpChainToL1ConversionValidatorData
{
# NodeID is the 20-byte short-id carried as variable bytes
# (JSONByteSlice in the Go type).
NodeID bytes @0
# BLSPublicKey is the validator's 48-byte compressed BLS public
# key. Fixed-length wire field.
BLSPublicKey bls48 @8
# Weight is the validator's sampling weight at conversion time.
Weight u64 @56
}
# ----------------------------------------------------------------------
# RegisterL1Validator — request to add a validator to an L1
# ----------------------------------------------------------------------
#
# typeID 0x01 in the warp message codec. Issued by an L1's
# validator-manager contract to request a new validator be registered
# on the P-chain. Carried as the inner payload of an AddressedCall
# carried by a Warp UnsignedMessage carried as the Message field of a
# RegisterL1ValidatorTx.
#
# ValidationID = hash(this payload bytes) — used to key the L1Validator
# state record.
#
# Fixed section: 32 (ChainID) + 8 (NodeID) + 48 (BLSPublicKey) +
# 8 (Expiry) + 12 (RemainingBalanceOwner) + 12 (DisableOwner) +
# 8 (Weight) = 128
struct RegisterL1Validator
shape_kind = 0x8A # ShapeKindWarpRegisterL1Validator
{
# ChainID is the L1 chain ID this validator is being registered
# on. MUST NOT be PrimaryNetworkID (warp.ErrInvalidChainID).
ChainID id32 @0
# NodeID is the validator's 20-byte short-id (variable-length
# JSONByteSlice in the Go type).
NodeID bytes @32
# BLSPublicKey is the validator's 48-byte compressed BLS public
# key.
BLSPublicKey bls48 @40
# Expiry is the unix-seconds deadline after which this
# registration request becomes invalid (replay-protected via the
# state ExpiryEntry record).
Expiry u64 @88
# RemainingBalanceOwner is the PChainOwner that receives leftover
# balance when the validator exits the set.
RemainingBalanceOwner bytes @96
# DisableOwner is the PChainOwner with authority to manually
# deactivate this validator.
DisableOwner bytes @108
# Weight is the validator's sampling weight. MUST be > 0
# (warp.ErrInvalidWeight).
Weight u64 @120
}
# ----------------------------------------------------------------------
# PChainOwner — threshold + addresses owner record (warp side)
# ----------------------------------------------------------------------
#
# Carried inside RegisterL1Validator (twice — RemainingBalanceOwner +
# DisableOwner) and on the P-chain by ConvertNetworkToL1Validator.
# Identical shape and semantics to pvm/txs.PChainOwner.
#
# Fixed section: 4 (Threshold) + 8 (Addresses) = 12
struct PChainOwner
shape_kind = 0x8B # ShapeKindWarpPChainOwner
{
Threshold u32 @0
# Addresses is the list of 20-byte ShortIDs authorised on this
# owner. Sorted+unique.
Addresses bytes @4
}
# ----------------------------------------------------------------------
# L1ValidatorRegistration — registration ack from the P-chain
# ----------------------------------------------------------------------
#
# typeID 0x02 in the warp message codec. P-chain emits this to ack
# whether a ValidationID is currently a validator on the P-chain side.
#
# Registered=false is FINAL — that ValidationID can never become a
# validator on the P-chain (the request has expired or been replaced).
# It is still possible that ValidationID was previously a validator.
#
# Fixed section: 32 (ValidationID) + 1 (Registered) = 33
struct L1ValidatorRegistration
shape_kind = 0x8C # ShapeKindWarpL1ValidatorRegistration
{
ValidationID id32 @0
# Registered: 1 = currently registered, 0 = never will be.
# Encoded as a Go bool / wire u8.
Registered u8 @32
}
# ----------------------------------------------------------------------
# L1ValidatorWeight — bidirectional weight-update message
# ----------------------------------------------------------------------
#
# typeID 0x03 in the warp message codec.
#
# When the P-chain RECEIVES this from an L1's manager: treat as a
# command to set the validator's weight to Weight at nonce Nonce.
#
# When the P-chain SENDS this to an L1 / observer: report the current
# Nonce+Weight pair.
#
# Reserved: Nonce == MaxUint64 is removal-only (Weight MUST be 0).
# Verify() returns ErrNonceReservedForRemoval otherwise.
#
# Fixed section: 32 (ValidationID) + 8 (Nonce) + 8 (Weight) = 48
struct L1ValidatorWeight
shape_kind = 0x8D # ShapeKindWarpL1ValidatorWeight
{
ValidationID id32 @0
Nonce u64 @32
Weight u64 @40
}
# ======================================================================
# Teleport: cross-chain bridge messages (warp codec slots 0x04-0x06)
# ======================================================================
# ----------------------------------------------------------------------
# TeleportMessage — Warp wrapper for cross-chain bridge ops
# ----------------------------------------------------------------------
#
# typeID 0x04 in the warp codec slot map. High-level cross-chain
# messaging primitive sitting on top of Warp signatures.
#
# Version is currently TeleportVersion=1; MessageType selects the
# operation kind. When Encrypted=1 (TeleportPrivate), Payload is
# a codec-marshalled EncryptedWarpPayload.
#
# Fixed section: 1 (Version) + 1 (MessageType) + 32 (SourceChainID) +
# 32 (DestChainID) + 8 (Nonce) + 8 (Payload) + 1 (Encrypted) = 83
struct TeleportMessage
shape_kind = 0x8E # ShapeKindWarpTeleportMessage
{
# Version is the Teleport protocol version (currently 1).
Version u8 @0
# MessageType selects the cross-chain operation:
# 0 Transfer — standard asset transfer
# 1 Swap — atomic swap
# 2 Lock — lock on source
# 3 Unlock — unlock on destination
# 4 Attest — oracle attestation
# 5 Governance — cross-chain governance
# 6 Private — encrypted transfer
MessageType u8 @1
SourceChainID id32 @2
DestChainID id32 @34
# Nonce prevents replay across (Source, Dest) pairs.
Nonce u64 @66
# Payload is the application payload — bytes of an
# EncryptedWarpPayload when Encrypted=1, otherwise free-form.
Payload bytes @74
# Encrypted: 1 indicates Payload is an EncryptedWarpPayload, 0
# plain bytes.
Encrypted u8 @82
}
# ----------------------------------------------------------------------
# TeleportTransferPayload — asset-transfer Teleport payload
# ----------------------------------------------------------------------
#
# typeID 0x05 in the warp codec slot map. Carried as the Payload of a
# TeleportMessage when MessageType=TeleportTransfer.
#
# Fixed section: 32 (AssetID) + 8 (Amount) + 8 (Sender) +
# 8 (Recipient) + 8 (Fee) + 8 (Memo) = 72
struct TeleportTransferPayload
shape_kind = 0x8F # ShapeKindWarpTeleportTransferPayload
{
# AssetID is the 32-byte asset ID being transferred.
AssetID id32 @0
# Amount is the quantity being transferred (asset-defined units).
Amount u64 @32
# Sender is the chain-specific source address bytes.
Sender bytes @40
# Recipient is the chain-specific destination address bytes.
Recipient bytes @48
# Fee paid for the bridge operation.
Fee u64 @56
# Memo is optional metadata.
Memo bytes @64
}
# ----------------------------------------------------------------------
# TeleportAttestPayload — oracle-attestation Teleport payload
# ----------------------------------------------------------------------
#
# typeID 0x06 in the warp codec slot map. Carried as the Payload of a
# TeleportMessage when MessageType=TeleportAttest (oracle feed,
# compute attestation, ...).
#
# Fixed section: 1 (AttestationType) + 8 (Timestamp) + 8 (Data) +
# 20 (AttesterID) = 37
struct TeleportAttestPayload
shape_kind = 0x90 # ShapeKindWarpTeleportAttestPayload
{
# AttestationType identifies what is being attested
# (application-defined; e.g. 1=price feed, 2=compute result, ...).
AttestationType u8 @0
# Timestamp is the unix-seconds time of the attestation.
Timestamp u64 @1
# Data is the application-defined attestation payload (price,
# compute result, ...).
Data bytes @9
# AttesterID is the NodeID of the attesting validator.
AttesterID id20 @17
}