Files
go/cmd/zapgen/testdata/owner_zap.go.golden
zeekay d9bcc8711f The generator can say what the chains actually put on the wire
A list's encoding was one thing for every element type: a run of
{length, payload} pairs. The Lux chains write four different runs — a
run of numbers, a run of fixed-width byte records, a run of struct
payloads back to back, and a run of relative pointers to payloads
written elsewhere — and none of them was that one. So both chains that
have a C++ port wrote their own accessors by hand, and the generator
could not have replaced them.

The shape is now derived from the element type rather than fixed. A
number is a run of numbers at its own width; bytes_fixed[N] is those
runs back to back; a struct with no tail is its payload back to back at
its own width; a struct WITH a tail cannot sit in a run at all, because
its tail has nowhere to go between two neighbours, so it becomes a
pointer. The schema never spells any of this, which is what stops two
authors spelling one list two ways. bytes and text have no width, so a
run of them is refused rather than invented.

Order is the wire, too. Every payload a struct points at is written
before the struct's own object, because SetList needs an offset that
already exists — the order the reference has always written in, and the
one the emitted builder had backwards. An empty list now writes nothing
at all: the alignment pad that a start-then-discard would leave behind
moves every byte after it.

Three entry points per struct, because there are three places a struct
sits: New for a message of its own, Append for an object inside somebody
else's message, Encode for one element of an inline run. A nested struct
field is the nested type's own Input, not a pre-built buffer the caller
hands over unchecked.

Readers take the stride the schema knows, so a lying length word is
refused once instead of at every element, and a list of records answers
with the record's type instead of an offset the caller has to know.

Both backends emit version 2. That is the header every vector in the
chain corpus opens with, and the one the hardened runtime writes; a
generated builder that wrote version 1 wrote a header no chain has.

The Go runtime gains the pointer list it was missing — AddObjectPtr,
ObjectPtr and the strided read — so both backends can express the same
wire rather than one of them refusing.

Proven: one schema, both backends, byte-identical output over all four
list shapes, a bytes tail and a pointer list.
2026-09-06 09:09:54 -07:00

127 lines
3.4 KiB
Plaintext

// Code generated by zapgen; DO NOT EDIT.
// source: basetx.zap
package xvm
import (
zap "github.com/zap-proto/go"
)
const (
ownerLocktimeOff = 0
ownerThresholdOff = 8
ownerAddrsOff = 12
ownerSigsOff = 20
ownerEntriesOff = 28
ownerSize = 36
)
// Owner is a zero-copy view into a ZAP-encoded Owner message.
type Owner struct{ o zap.Object }
// WrapOwner parses b and returns a typed view. Returns an error if the
// wire-level checks (magic, version, size) fail.
func WrapOwner(b []byte) (Owner, error) {
m, err := zap.Parse(b)
if err != nil {
return Owner{}, err
}
return Owner{o: m.Root()}, nil
}
func (t Owner) Locktime() uint64 { return t.o.Uint64(ownerLocktimeOff) }
func (t Owner) Threshold() uint32 { return t.o.Uint32(ownerThresholdOff) }
func (t Owner) Addrs() zap.List { return t.o.ListStride(ownerAddrsOff, 20) }
func (t Owner) AddrsAt(i int) [20]byte {
var out [20]byte
copy(out[:], t.Addrs().Object(i, 20).BytesFixed(0, 20))
return out
}
func (t Owner) Sigs() zap.List { return t.o.ListStride(ownerSigsOff, 4) }
func (t Owner) Entries() zap.List { return t.o.ListStride(ownerEntriesOff, 44) }
func (t Owner) EntriesAt(i int) Entry { return Entry{o: t.Entries().Object(i, 44)} }
// OwnerInput collects the field values for NewOwner.
type OwnerInput struct {
Locktime uint64
Threshold uint32
Addrs [][20]byte
Sigs []uint32
Entries []EntryInput
}
// AppendOwner writes one Owner object into b — every payload it points at first,
// then the object itself — and returns the object's offset.
func AppendOwner(b *zap.Builder, in OwnerInput) int {
addrsOff := 0
if len(in.Addrs) > 0 {
lb := b.StartList(20)
for _, elem := range in.Addrs {
lb.AddBytes(elem[:])
}
addrsOff = lb.FinishOffset()
}
sigsOff := 0
if len(in.Sigs) > 0 {
lb := b.StartList(4)
for _, elem := range in.Sigs {
lb.AddUint32(elem)
}
sigsOff = lb.FinishOffset()
}
entriesOff := 0
if len(in.Entries) > 0 {
lb := b.StartList(44)
for _, elem := range in.Entries {
payload := EncodeEntry(elem)
lb.AddBytes(payload[:])
}
entriesOff = lb.FinishOffset()
}
ob := b.StartObject(ownerSize)
ob.SetUint64(ownerLocktimeOff, in.Locktime)
ob.SetUint32(ownerThresholdOff, in.Threshold)
ob.SetList(ownerAddrsOff, addrsOff, len(in.Addrs))
ob.SetList(ownerSigsOff, sigsOff, len(in.Sigs))
ob.SetList(ownerEntriesOff, entriesOff, len(in.Entries))
return ob.Finish()
}
// NewOwner builds a ZAP-encoded Owner message from in and returns the bytes.
func NewOwner(in OwnerInput) []byte {
b := zap.NewBuilderV2(256)
addrsOff := 0
if len(in.Addrs) > 0 {
lb := b.StartList(20)
for _, elem := range in.Addrs {
lb.AddBytes(elem[:])
}
addrsOff = lb.FinishOffset()
}
sigsOff := 0
if len(in.Sigs) > 0 {
lb := b.StartList(4)
for _, elem := range in.Sigs {
lb.AddUint32(elem)
}
sigsOff = lb.FinishOffset()
}
entriesOff := 0
if len(in.Entries) > 0 {
lb := b.StartList(44)
for _, elem := range in.Entries {
payload := EncodeEntry(elem)
lb.AddBytes(payload[:])
}
entriesOff = lb.FinishOffset()
}
ob := b.StartObject(ownerSize)
ob.SetUint64(ownerLocktimeOff, in.Locktime)
ob.SetUint32(ownerThresholdOff, in.Threshold)
ob.SetList(ownerAddrsOff, addrsOff, len(in.Addrs))
ob.SetList(ownerSigsOff, sigsOff, len(in.Sigs))
ob.SetList(ownerEntriesOff, entriesOff, len(in.Entries))
ob.FinishAsRoot()
return b.Finish()
}