Files
proto/zap_native/create_chain_tx.go
Hanzo AI 5f375f2db6 proto: lift zap_native from node/vms/platformvm/txs/ to proto/zap_native
Decouples the platformvm ZAP TxKind dispatch from luxfi/node so
proto/p can consume it directly for the codec rip (#101 Wave 1B).
Previously the package lived downstream of proto, making the proto/p
migration architecturally impossible.

Package name kept as zap_native (236 outer-luxfi/zap references would
otherwise need aliasing). Directory matches. Public sub-package (not
internal/) so node's 8 existing consumers can also import it via the
new path:

  github.com/luxfi/node/vms/platformvm/txs/zap_native
    ↓
  github.com/luxfi/proto/zap_native

Standalone tests pass:
  ok  github.com/luxfi/proto/zap_native
2026-06-05 14:40:27 -07:00

196 lines
7.0 KiB
Go

// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zap_native
import (
"github.com/luxfi/ids"
"github.com/luxfi/zap"
)
// CreateChainTx is the v3 create-blockchain envelope. It carries the
// BaseTxFull spending state, the parent network ID, the child VM ID, an
// optional genesis-data byte blob (variable; lives in the variable section),
// a single-address Owner stub, and the SHA-256 hash of the corresponding
// Warp message (when this CreateChain was originated via cross-network
// commit). The Warp message body itself is NOT embedded — only its hash —
// because the body lives in the signed Warp envelope outside this tx.
//
// Fixed-section layout (size 173 bytes):
//
// TxKind uint8 @ 0
// NetworkID uint32 @ 1
// BlockchainID 32B @ 5
// OutsList 8B @ 37
// InsList 8B @ 45
// CredsList 8B @ 53
// SigIndicesArr 8B @ 61
// SigArr 8B @ 69
// Memo 8B @ 77
// ParentNetwork 32B @ 85 (ids.ID; the parent network)
// VMID 32B @ 117 (ids.ID; the VM identifier)
// OwnerThreshold uint32 @ 149
// OwnerLocktime uint64 @ 153
// OwnerAddress 20B @ 161
// WarpMessageHash 32B @ 181 (sha256 of the originating Warp msg; zero if none)
// GenesisData bytes @ 213 (offset+length; variable)
// Size = 221
const (
OffsetCreateChainTx_NetworkID = 1
OffsetCreateChainTx_BlockchainID = 5
OffsetCreateChainTx_OutsList = 37
OffsetCreateChainTx_InsList = 45
OffsetCreateChainTx_CredsList = 53
OffsetCreateChainTx_SigIndicesArr = 61
OffsetCreateChainTx_SigArr = 69
OffsetCreateChainTx_Memo = 77
OffsetCreateChainTx_ParentNetwork = 85
OffsetCreateChainTx_VMID = 117
OffsetCreateChainTx_OwnerThreshold = 149
OffsetCreateChainTx_OwnerLocktime = 153
OffsetCreateChainTx_OwnerAddress = 161
OffsetCreateChainTx_WarpMessageHash = OffsetCreateChainTx_OwnerAddress + ids.ShortIDLen
OffsetCreateChainTx_GenesisData = OffsetCreateChainTx_WarpMessageHash + 32
SizeCreateChainTx = OffsetCreateChainTx_GenesisData + 8
)
// CreateChainTx is the zero-copy accessor.
type CreateChainTx struct {
msg *zap.Message
obj zap.Object
}
func (t CreateChainTx) NetworkID() uint32 { return t.obj.Uint32(OffsetCreateChainTx_NetworkID) }
func (t CreateChainTx) BlockchainID() ids.ID {
var out ids.ID
for i := 0; i < 32; i++ {
out[i] = t.obj.Uint8(OffsetCreateChainTx_BlockchainID + i)
}
return out
}
func (t CreateChainTx) ParentNetwork() ids.ID {
var out ids.ID
for i := 0; i < 32; i++ {
out[i] = t.obj.Uint8(OffsetCreateChainTx_ParentNetwork + i)
}
return out
}
func (t CreateChainTx) VMID() ids.ID {
var out ids.ID
for i := 0; i < 32; i++ {
out[i] = t.obj.Uint8(OffsetCreateChainTx_VMID + i)
}
return out
}
func (t CreateChainTx) Owner() (uint32, uint64, ids.ShortID) {
threshold := t.obj.Uint32(OffsetCreateChainTx_OwnerThreshold)
locktime := t.obj.Uint64(OffsetCreateChainTx_OwnerLocktime)
var addr ids.ShortID
for i := 0; i < ids.ShortIDLen; i++ {
addr[i] = t.obj.Uint8(OffsetCreateChainTx_OwnerAddress + i)
}
return threshold, locktime, addr
}
// WarpMessageHash returns the SHA-256 hash of the originating Warp message.
// Returns the zero ids.ID when this CreateChain was not originated via
// a cross-network commit.
func (t CreateChainTx) WarpMessageHash() ids.ID {
var out ids.ID
for i := 0; i < 32; i++ {
out[i] = t.obj.Uint8(OffsetCreateChainTx_WarpMessageHash + i)
}
return out
}
// GenesisData returns the chain's genesis bytes.
//
// READ-ONLY: see BaseTxFull.Memo for the aliasing contract.
func (t CreateChainTx) GenesisData() []byte {
return t.obj.Bytes(OffsetCreateChainTx_GenesisData)
}
func (t CreateChainTx) Outs() OutputList { return OutputListView(t.obj, OffsetCreateChainTx_OutsList) }
func (t CreateChainTx) Ins() InputList { return InputListView(t.obj, OffsetCreateChainTx_InsList) }
func (t CreateChainTx) Credentials() CredentialList {
return CredentialListView(t.obj, OffsetCreateChainTx_CredsList)
}
func (t CreateChainTx) SigIndicesArray() SigIndicesArray {
return SigIndicesArrayView(t.obj, OffsetCreateChainTx_SigIndicesArr)
}
func (t CreateChainTx) SignatureArray() SignatureArray {
return SignatureArrayView(t.obj, OffsetCreateChainTx_SigArr)
}
func (t CreateChainTx) Memo() []byte { return t.obj.Bytes(OffsetCreateChainTx_Memo) }
func (t CreateChainTx) Bytes() []byte { return t.msg.Bytes() }
func (t CreateChainTx) IsZero() bool { return t.msg == nil }
func WrapCreateChainTx(b []byte) (CreateChainTx, error) {
msg, obj, err := parseAndCheckKind(b, TxKindCreateChain)
if err != nil {
return CreateChainTx{}, err
}
return CreateChainTx{msg: msg, obj: obj}, nil
}
// CreateChainTxInput is the constructor input.
type CreateChainTxInput struct {
NetworkID uint32
BlockchainID ids.ID
Outs []OutputListEntry
Ins []InputListEntry
Credentials []CredentialListEntry
Memo []byte
ParentNetwork ids.ID
VMID ids.ID
Owner OwnerStub
WarpMessageHash ids.ID
GenesisData []byte
}
func NewCreateChainTx(in CreateChainTxInput) CreateChainTx {
cap := zap.HeaderSize + 16 + SizeCreateChainTx
cap += len(in.Outs) * SizeTransferableOutput
cap += len(in.Ins) * SizeTransferableInput
cap += len(in.Credentials) * SizeCredential
cap += len(in.Memo) + len(in.GenesisData)
b := zap.NewBuilder(cap)
outsOff, outsCount := WriteOutputList(b, in.Outs)
insOff, insCount, sigIndices := WriteInputList(b, in.Ins)
credsOff, credsCount, sigBlobs := WriteCredentialList(b, in.Credentials)
sigIdxArrOff, sigIdxArrCount := WriteSigIndicesArray(b, sigIndices)
sigArrOff, sigArrCount := WriteSignatureArray(b, sigBlobs)
ob := b.StartObject(SizeCreateChainTx)
ob.SetUint8(OffsetTxKind, uint8(TxKindCreateChain))
ob.SetUint32(OffsetCreateChainTx_NetworkID, in.NetworkID)
for i := 0; i < 32; i++ {
ob.SetUint8(OffsetCreateChainTx_BlockchainID+i, in.BlockchainID[i])
ob.SetUint8(OffsetCreateChainTx_ParentNetwork+i, in.ParentNetwork[i])
ob.SetUint8(OffsetCreateChainTx_VMID+i, in.VMID[i])
ob.SetUint8(OffsetCreateChainTx_WarpMessageHash+i, in.WarpMessageHash[i])
}
ob.SetList(OffsetCreateChainTx_OutsList, outsOff, outsCount)
ob.SetList(OffsetCreateChainTx_InsList, insOff, insCount)
ob.SetList(OffsetCreateChainTx_CredsList, credsOff, credsCount)
ob.SetList(OffsetCreateChainTx_SigIndicesArr, sigIdxArrOff, sigIdxArrCount)
ob.SetList(OffsetCreateChainTx_SigArr, sigArrOff, sigArrCount)
ob.SetBytes(OffsetCreateChainTx_Memo, in.Memo)
ob.SetUint32(OffsetCreateChainTx_OwnerThreshold, in.Owner.Threshold)
ob.SetUint64(OffsetCreateChainTx_OwnerLocktime, in.Owner.Locktime)
for i := 0; i < ids.ShortIDLen; i++ {
ob.SetUint8(OffsetCreateChainTx_OwnerAddress+i, in.Owner.Address[i])
}
ob.SetBytes(OffsetCreateChainTx_GenesisData, in.GenesisData)
ob.FinishAsRoot()
msg, _ := zap.Parse(b.Finish())
return CreateChainTx{msg: msg, obj: msg.Root()}
}