mirror of
https://github.com/luxfi/api.git
synced 2026-09-24 00:24:53 +00:00
Adds .hanzo/workflows/cicd.yml calling the canonical pipeline and drops the GitHub-hosted workflows it replaces. Lands here because this is where the repo is written — git.hanzo.ai is upstream and github.com is its push mirror, so the same change made on github.com never reaches the runner fleet.
1168 lines
32 KiB
Go
1168 lines
32 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package zap
|
|
|
|
// State represents VM state values
|
|
type State uint8
|
|
|
|
const (
|
|
StateUnknown State = 0
|
|
StateStarting State = 1
|
|
StateSyncing State = 2
|
|
StateBootstrapping State = 3
|
|
StateReady State = 4
|
|
StateDegraded State = 5
|
|
StateStopping State = 6
|
|
StateStopped State = 7
|
|
)
|
|
|
|
// Error represents VM errors
|
|
type Error uint8
|
|
|
|
// The zero value carries "the call succeeded" — a reply whose Err is
|
|
// ErrorUnspecified is read as a good answer and its fields are trusted. Every
|
|
// other value names a failure, so a failure the vocabulary has no word for
|
|
// must reach the caller as ErrorInternal. Mapping it onto the zero instead
|
|
// hands back a zero-valued block under the name of success.
|
|
const (
|
|
ErrorUnspecified Error = iota
|
|
ErrorClosed
|
|
ErrorNotFound
|
|
ErrorStateSyncNotImplemented
|
|
ErrorInternal
|
|
)
|
|
|
|
// InitializeRequest contains initialization parameters.
|
|
//
|
|
// Note: the upstream upgrade-timestamp surface was ripped under the activate-
|
|
// all-implicitly directive — every chain runs the post-Granite rule-set from
|
|
// genesis, so there are no per-upgrade timestamps to ship over the wire.
|
|
type InitializeRequest struct {
|
|
NetworkID uint32
|
|
ChainID []byte
|
|
NodeID []byte
|
|
PublicKey []byte
|
|
XChainID []byte
|
|
CChainID []byte
|
|
UTXOAssetID []byte
|
|
ChainDataDir string
|
|
GenesisBytes []byte
|
|
UpgradeBytes []byte
|
|
ConfigBytes []byte
|
|
DBServerAddr string
|
|
ServerAddr string
|
|
|
|
// AtomicServerAddr is the address of a ZAP server the node bound over THIS
|
|
// chain's atomic shared-memory handle before calling Initialize. A plugin
|
|
// dials it to reach the primary network's cross-chain import/export
|
|
// primitive, which cannot be copied into the plugin's rebuilt Runtime
|
|
// because it is an interface over a live database the node owns. Same shape
|
|
// and lifetime as DBServerAddr.
|
|
//
|
|
// Empty means the node wired no shared memory for this chain. The plugin
|
|
// MUST then leave Runtime.SharedMemory nil so a settlement precompile
|
|
// reverts fail-closed rather than fabricate value.
|
|
AtomicServerAddr string
|
|
|
|
// ValidatorServerAddr is the address of a ZAP server the node bound over its
|
|
// validator state before calling Initialize. A plugin dials it to learn who
|
|
// the validators are at a P-chain height.
|
|
//
|
|
// It rides here for the same reason AtomicServerAddr does: validator state is
|
|
// an interface over live node-owned state, so it cannot be copied into the
|
|
// plugin's rebuilt Runtime. Without it a plugin-hosted VM sees a nil handle
|
|
// and can form no committee — which is why M-Chain, whose whole job is a
|
|
// threshold ceremony among validators, could never run one.
|
|
//
|
|
// Empty means the node wired no validator state for this chain. The plugin
|
|
// MUST then leave Runtime.ValidatorState nil so a committee lookup fails
|
|
// with a clear "no committee" rather than fabricating an empty set — an
|
|
// empty validator set is a quorum of nobody.
|
|
ValidatorServerAddr string
|
|
|
|
// DChainID is the D-Chain (dexvm) blockchain id, resolved node-side from the
|
|
// chain alias "D". It rides here because the plugin's Runtime has no
|
|
// BCLookup — that field is an interface onto the node's chain manager and,
|
|
// like SharedMemory, does not survive the boundary. The DEX settlement seam
|
|
// needs exactly one alias resolved, so the resolved ID is carried instead of
|
|
// proxying a whole lookup service.
|
|
//
|
|
// Empty means the network has no dexvm deployed; the settlement seam then
|
|
// stays closed rather than guess a peer.
|
|
DChainID []byte
|
|
}
|
|
|
|
// Encode serializes InitializeRequest to the buffer
|
|
func (m *InitializeRequest) Encode(buf *Buffer) {
|
|
buf.WriteUint32(m.NetworkID)
|
|
buf.WriteBytes(m.ChainID)
|
|
buf.WriteBytes(m.NodeID)
|
|
buf.WriteBytes(m.PublicKey)
|
|
buf.WriteBytes(m.XChainID)
|
|
buf.WriteBytes(m.CChainID)
|
|
buf.WriteBytes(m.UTXOAssetID)
|
|
buf.WriteString(m.ChainDataDir)
|
|
buf.WriteBytes(m.GenesisBytes)
|
|
buf.WriteBytes(m.UpgradeBytes)
|
|
buf.WriteBytes(m.ConfigBytes)
|
|
buf.WriteString(m.DBServerAddr)
|
|
buf.WriteString(m.ServerAddr)
|
|
// OPTIONAL trailing fields — see the EVOLUTION RULE on InitializeResponse.
|
|
// Appended, never inserted, so an older decoder stops after ServerAddr and
|
|
// ignores these bytes.
|
|
buf.WriteString(m.AtomicServerAddr)
|
|
buf.WriteBytes(m.DChainID)
|
|
buf.WriteString(m.ValidatorServerAddr)
|
|
}
|
|
|
|
// Decode deserializes InitializeRequest from the reader.
|
|
//
|
|
// LENGTH-TOLERANT trailing fields, the same contract InitializeResponse.Decode
|
|
// documents. AtomicServerAddr, DChainID and ValidatorServerAddr were APPENDED for
|
|
// the cross-chain
|
|
// atomic seam without bumping version.RPCChainVMProtocol, so both skew
|
|
// directions stay safe:
|
|
//
|
|
// - NEW node -> OLD plugin: the old decoder stops after ServerAddr and ignores
|
|
// the trailing bytes (ZAP frames are length-prefixed). The plugin keeps its
|
|
// nil SharedMemory and its settlements keep reverting fail-closed — the
|
|
// behavior it already had, never a silent divergence.
|
|
// - OLD node -> NEW plugin: Remaining() is 0 at these reads, so both fields
|
|
// stay zero-valued and the plugin treats the atomic capability as absent.
|
|
//
|
|
// Neither direction changes how any block executes, which is what makes this
|
|
// safe to roll one validator at a time.
|
|
func (m *InitializeRequest) Decode(r *Reader) error {
|
|
var err error
|
|
if m.NetworkID, err = r.ReadUint32(); err != nil {
|
|
return err
|
|
}
|
|
if m.ChainID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.NodeID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.PublicKey, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.XChainID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.CChainID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.UTXOAssetID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.ChainDataDir, err = r.ReadString(); err != nil {
|
|
return err
|
|
}
|
|
if m.GenesisBytes, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.UpgradeBytes, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.ConfigBytes, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.DBServerAddr, err = r.ReadString(); err != nil {
|
|
return err
|
|
}
|
|
if m.ServerAddr, err = r.ReadString(); err != nil {
|
|
return err
|
|
}
|
|
// OPTIONAL trailing fields. A length-prefixed field costs at least its
|
|
// 4-byte count, so Remaining() < 4 ⇒ the peer predates this field; leave it
|
|
// zero-valued instead of returning io.ErrUnexpectedEOF.
|
|
if r.Remaining() >= 4 {
|
|
if m.AtomicServerAddr, err = r.ReadString(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if r.Remaining() >= 4 {
|
|
if m.DChainID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if r.Remaining() >= 4 {
|
|
if m.ValidatorServerAddr, err = r.ReadString(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// InitializeResponse contains initialization results
|
|
type InitializeResponse struct {
|
|
LastAcceptedID []byte
|
|
LastAcceptedParentID []byte
|
|
Height uint64
|
|
Bytes []byte
|
|
Timestamp int64
|
|
// Capabilities is a bitfield of OPTIONAL cross-boundary add-ons the VM
|
|
// implements (see the Cap* constants). The node reads it once at handshake
|
|
// to decide which add-ons to wire; an unset bit → the node treats that
|
|
// capability as absent and stays on the generic path.
|
|
Capabilities uint64
|
|
}
|
|
|
|
// VM capability bits advertised in InitializeResponse.Capabilities. A VM sets a
|
|
// bit to tell the node it implements the corresponding OPTIONAL add-on that is
|
|
// NOT part of the generic ChainVM contract. Discovered at the handshake, never
|
|
// braided into ChainVM — generic VMs leave every bit clear.
|
|
const (
|
|
// CapQuasarExport: the VM tracks a Quasar (⅔-by-stake) EXPORT-FINAL height
|
|
// distinct from its reorgable local accept tip, and answers
|
|
// MsgSetQuasarFinalized / MsgQuasarHeight. Set by the C-Chain EVM; the node
|
|
// wires the consensus export-frontier observer only when this bit is set.
|
|
CapQuasarExport uint64 = 1 << 0
|
|
|
|
// CapStateSync: the VM can adopt a peer's state summary instead of replaying
|
|
// to it, and answers the six MsgStateSync*/MsgStateSummary* messages. Set by
|
|
// any VM implementing the syncable surface.
|
|
//
|
|
// The node needs this at the handshake because the alternative is asking and
|
|
// reading a refusal, and a VM that cannot answer at all is indistinguishable
|
|
// on the wire from one that answered "no". A node repairing a damaged chain
|
|
// must tell those apart: the first means find another way, the second means
|
|
// this VM chose to replay.
|
|
CapStateSync uint64 = 1 << 1
|
|
)
|
|
|
|
// Encode serializes InitializeResponse to the buffer
|
|
func (m *InitializeResponse) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.LastAcceptedID)
|
|
buf.WriteBytes(m.LastAcceptedParentID)
|
|
buf.WriteUint64(m.Height)
|
|
buf.WriteBytes(m.Bytes)
|
|
buf.WriteInt64(m.Timestamp)
|
|
buf.WriteUint64(m.Capabilities)
|
|
}
|
|
|
|
// Decode deserializes InitializeResponse from the reader.
|
|
//
|
|
// LENGTH-TOLERANT trailing field. Capabilities is OPTIONAL on the wire: it was
|
|
// APPENDED in api v1.0.16 (the Quasar-export handshake) WITHOUT bumping
|
|
// version.RPCChainVMProtocol, so a peer built before it — a stale VM plugin —
|
|
// sends a payload that ends right after Timestamp. Guarding the read on
|
|
// Remaining() lets a newer decoder read that short payload as "Capabilities = 0"
|
|
// (Nova-only, no optional add-ons) instead of failing with io.ErrUnexpectedEOF —
|
|
// exactly the v1.36.11 skew that broke every EVM Initialize with
|
|
// "zap decode initialize response: unexpected EOF". The mirror case (an OLDER
|
|
// decoder reading a NEWER payload) already works: a length-prefixed ZAP frame
|
|
// lets the old decoder stop after Timestamp and ignore the trailing bytes.
|
|
//
|
|
// EVOLUTION RULE: any FUTURE field is appended AFTER Capabilities and read the
|
|
// same way — guard each read on Remaining(), and keep Encode writing fields in
|
|
// this exact order. Never insert or reorder a field in the middle: that is a
|
|
// breaking wire change and MUST bump version.RPCChainVMProtocol.
|
|
func (m *InitializeResponse) Decode(r *Reader) error {
|
|
var err error
|
|
if m.LastAcceptedID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.LastAcceptedParentID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.Height, err = r.ReadUint64(); err != nil {
|
|
return err
|
|
}
|
|
if m.Bytes, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.Timestamp, err = r.ReadInt64(); err != nil {
|
|
return err
|
|
}
|
|
// OPTIONAL trailing field: absent from pre-v1.0.16 peers. Remaining() < 8
|
|
// (a uint64 is 8 bytes) ⇒ leave Capabilities at its zero value rather than
|
|
// EOF. A count of exactly 8 (or more, from an even-newer peer with further
|
|
// appended fields) ⇒ read it and ignore anything past it.
|
|
if r.Remaining() >= 8 {
|
|
if m.Capabilities, err = r.ReadUint64(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SetStateRequest contains state change request.
|
|
// State values are defined in github.com/luxfi/vm (vm.State):
|
|
//
|
|
// Unknown=0, Starting=1, Syncing=2, Bootstrapping=3,
|
|
// Ready=4, Degraded=5, Stopping=6, Stopped=7
|
|
type SetStateRequest struct {
|
|
State State
|
|
}
|
|
|
|
// Encode serializes SetStateRequest to the buffer
|
|
func (m *SetStateRequest) Encode(buf *Buffer) {
|
|
buf.WriteUint8(uint8(m.State))
|
|
}
|
|
|
|
// Decode deserializes SetStateRequest from the reader
|
|
func (m *SetStateRequest) Decode(r *Reader) error {
|
|
v, err := r.ReadUint8()
|
|
m.State = State(v)
|
|
return err
|
|
}
|
|
|
|
// SetStateResponse contains state change results
|
|
type SetStateResponse struct {
|
|
LastAcceptedID []byte
|
|
LastAcceptedParentID []byte
|
|
Height uint64
|
|
Bytes []byte
|
|
Timestamp int64
|
|
}
|
|
|
|
// Encode serializes SetStateResponse to the buffer
|
|
func (m *SetStateResponse) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.LastAcceptedID)
|
|
buf.WriteBytes(m.LastAcceptedParentID)
|
|
buf.WriteUint64(m.Height)
|
|
buf.WriteBytes(m.Bytes)
|
|
buf.WriteInt64(m.Timestamp)
|
|
}
|
|
|
|
// Decode deserializes SetStateResponse from the reader
|
|
func (m *SetStateResponse) Decode(r *Reader) error {
|
|
var err error
|
|
if m.LastAcceptedID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.LastAcceptedParentID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.Height, err = r.ReadUint64(); err != nil {
|
|
return err
|
|
}
|
|
if m.Bytes, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
m.Timestamp, err = r.ReadInt64()
|
|
return err
|
|
}
|
|
|
|
// BuildBlockRequest contains block building parameters
|
|
type BuildBlockRequest struct {
|
|
PChainHeight uint64
|
|
HasPChainHeight bool
|
|
}
|
|
|
|
// Encode serializes BuildBlockRequest to the buffer
|
|
func (m *BuildBlockRequest) Encode(buf *Buffer) {
|
|
buf.WriteBool(m.HasPChainHeight)
|
|
if m.HasPChainHeight {
|
|
buf.WriteUint64(m.PChainHeight)
|
|
}
|
|
}
|
|
|
|
// Decode deserializes BuildBlockRequest from the reader
|
|
func (m *BuildBlockRequest) Decode(r *Reader) error {
|
|
var err error
|
|
if m.HasPChainHeight, err = r.ReadBool(); err != nil {
|
|
return err
|
|
}
|
|
if m.HasPChainHeight {
|
|
m.PChainHeight, err = r.ReadUint64()
|
|
}
|
|
return err
|
|
}
|
|
|
|
// BlockResponse contains block data (used by BuildBlock, ParseBlock, GetBlock)
|
|
type BlockResponse struct {
|
|
ID []byte
|
|
ParentID []byte
|
|
Bytes []byte // Zero-copy block data
|
|
Height uint64
|
|
Timestamp int64
|
|
VerifyWithContext bool
|
|
Err Error
|
|
}
|
|
|
|
// Encode serializes BlockResponse to the buffer
|
|
func (m *BlockResponse) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.ID)
|
|
buf.WriteBytes(m.ParentID)
|
|
buf.WriteBytes(m.Bytes)
|
|
buf.WriteUint64(m.Height)
|
|
buf.WriteInt64(m.Timestamp)
|
|
buf.WriteBool(m.VerifyWithContext)
|
|
buf.WriteUint8(uint8(m.Err))
|
|
}
|
|
|
|
// Decode deserializes BlockResponse from the reader
|
|
func (m *BlockResponse) Decode(r *Reader) error {
|
|
var err error
|
|
if m.ID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.ParentID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.Bytes, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.Height, err = r.ReadUint64(); err != nil {
|
|
return err
|
|
}
|
|
if m.Timestamp, err = r.ReadInt64(); err != nil {
|
|
return err
|
|
}
|
|
if m.VerifyWithContext, err = r.ReadBool(); err != nil {
|
|
return err
|
|
}
|
|
v, err := r.ReadUint8()
|
|
m.Err = Error(v)
|
|
return err
|
|
}
|
|
|
|
// ParseBlockRequest contains bytes to parse
|
|
type ParseBlockRequest struct {
|
|
Bytes []byte // Zero-copy input
|
|
}
|
|
|
|
// Encode serializes ParseBlockRequest to the buffer
|
|
func (m *ParseBlockRequest) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.Bytes)
|
|
}
|
|
|
|
// Decode deserializes ParseBlockRequest from the reader
|
|
func (m *ParseBlockRequest) Decode(r *Reader) error {
|
|
var err error
|
|
m.Bytes, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// GetBlockRequest contains block ID to retrieve
|
|
type GetBlockRequest struct {
|
|
ID []byte
|
|
}
|
|
|
|
// Encode serializes GetBlockRequest to the buffer
|
|
func (m *GetBlockRequest) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.ID)
|
|
}
|
|
|
|
// Decode deserializes GetBlockRequest from the reader
|
|
func (m *GetBlockRequest) Decode(r *Reader) error {
|
|
var err error
|
|
m.ID, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// SetPreferenceRequest contains preferred block ID
|
|
type SetPreferenceRequest struct {
|
|
ID []byte
|
|
}
|
|
|
|
// Encode serializes SetPreferenceRequest to the buffer
|
|
func (m *SetPreferenceRequest) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.ID)
|
|
}
|
|
|
|
// Decode deserializes SetPreferenceRequest from the reader
|
|
func (m *SetPreferenceRequest) Decode(r *Reader) error {
|
|
var err error
|
|
m.ID, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// BlockVerifyRequest contains block verification parameters
|
|
type BlockVerifyRequest struct {
|
|
Bytes []byte
|
|
PChainHeight uint64
|
|
HasPChainHeight bool
|
|
}
|
|
|
|
// Encode serializes BlockVerifyRequest to the buffer
|
|
func (m *BlockVerifyRequest) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.Bytes)
|
|
buf.WriteBool(m.HasPChainHeight)
|
|
if m.HasPChainHeight {
|
|
buf.WriteUint64(m.PChainHeight)
|
|
}
|
|
}
|
|
|
|
// Decode deserializes BlockVerifyRequest from the reader
|
|
func (m *BlockVerifyRequest) Decode(r *Reader) error {
|
|
var err error
|
|
if m.Bytes, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.HasPChainHeight, err = r.ReadBool(); err != nil {
|
|
return err
|
|
}
|
|
if m.HasPChainHeight {
|
|
m.PChainHeight, err = r.ReadUint64()
|
|
}
|
|
return err
|
|
}
|
|
|
|
// BlockVerifyResponse contains verification result
|
|
type BlockVerifyResponse struct {
|
|
Timestamp int64
|
|
}
|
|
|
|
// Encode serializes BlockVerifyResponse to the buffer
|
|
func (m *BlockVerifyResponse) Encode(buf *Buffer) {
|
|
buf.WriteInt64(m.Timestamp)
|
|
}
|
|
|
|
// Decode deserializes BlockVerifyResponse from the reader
|
|
func (m *BlockVerifyResponse) Decode(r *Reader) error {
|
|
var err error
|
|
m.Timestamp, err = r.ReadInt64()
|
|
return err
|
|
}
|
|
|
|
// BlockAcceptRequest contains block ID to accept
|
|
type BlockAcceptRequest struct {
|
|
ID []byte
|
|
}
|
|
|
|
// Encode serializes BlockAcceptRequest to the buffer
|
|
func (m *BlockAcceptRequest) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.ID)
|
|
}
|
|
|
|
// Decode deserializes BlockAcceptRequest from the reader
|
|
func (m *BlockAcceptRequest) Decode(r *Reader) error {
|
|
var err error
|
|
m.ID, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// BlockRejectRequest contains block ID to reject
|
|
type BlockRejectRequest struct {
|
|
ID []byte
|
|
}
|
|
|
|
// Encode serializes BlockRejectRequest to the buffer
|
|
func (m *BlockRejectRequest) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.ID)
|
|
}
|
|
|
|
// Decode deserializes BlockRejectRequest from the reader
|
|
func (m *BlockRejectRequest) Decode(r *Reader) error {
|
|
var err error
|
|
m.ID, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// BatchedParseBlockRequest contains multiple blocks to parse
|
|
type BatchedParseBlockRequest struct {
|
|
Requests [][]byte
|
|
}
|
|
|
|
// Encode serializes BatchedParseBlockRequest to the buffer
|
|
func (m *BatchedParseBlockRequest) Encode(buf *Buffer) {
|
|
buf.WriteUint32(uint32(len(m.Requests)))
|
|
for _, req := range m.Requests {
|
|
buf.WriteBytes(req)
|
|
}
|
|
}
|
|
|
|
// Decode deserializes BatchedParseBlockRequest from the reader
|
|
func (m *BatchedParseBlockRequest) Decode(r *Reader) error {
|
|
count, err := r.ReadCount()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m.Requests = make([][]byte, count)
|
|
for i := uint32(0); i < count; i++ {
|
|
if m.Requests[i], err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// BatchedParseBlockResponse contains parsed blocks
|
|
type BatchedParseBlockResponse struct {
|
|
Responses []BlockResponse
|
|
}
|
|
|
|
// Encode serializes BatchedParseBlockResponse to the buffer
|
|
func (m *BatchedParseBlockResponse) Encode(buf *Buffer) {
|
|
buf.WriteUint32(uint32(len(m.Responses)))
|
|
for i := range m.Responses {
|
|
m.Responses[i].Encode(buf)
|
|
}
|
|
}
|
|
|
|
// Decode deserializes BatchedParseBlockResponse from the reader
|
|
func (m *BatchedParseBlockResponse) Decode(r *Reader) error {
|
|
count, err := r.ReadCount()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m.Responses = make([]BlockResponse, count)
|
|
for i := uint32(0); i < count; i++ {
|
|
if err := m.Responses[i].Decode(r); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetAncestorsRequest contains ancestor retrieval parameters
|
|
type GetAncestorsRequest struct {
|
|
BlkID []byte
|
|
MaxBlocksNum int32
|
|
MaxBlocksSize int32
|
|
MaxBlocksRetrivalTime int64
|
|
}
|
|
|
|
// Encode serializes GetAncestorsRequest to the buffer
|
|
func (m *GetAncestorsRequest) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.BlkID)
|
|
buf.WriteInt32(m.MaxBlocksNum)
|
|
buf.WriteInt32(m.MaxBlocksSize)
|
|
buf.WriteInt64(m.MaxBlocksRetrivalTime)
|
|
}
|
|
|
|
// Decode deserializes GetAncestorsRequest from the reader
|
|
func (m *GetAncestorsRequest) Decode(r *Reader) error {
|
|
var err error
|
|
if m.BlkID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.MaxBlocksNum, err = r.ReadInt32(); err != nil {
|
|
return err
|
|
}
|
|
if m.MaxBlocksSize, err = r.ReadInt32(); err != nil {
|
|
return err
|
|
}
|
|
m.MaxBlocksRetrivalTime, err = r.ReadInt64()
|
|
return err
|
|
}
|
|
|
|
// GetAncestorsResponse contains ancestor blocks
|
|
type GetAncestorsResponse struct {
|
|
BlksBytes [][]byte
|
|
}
|
|
|
|
// Encode serializes GetAncestorsResponse to the buffer
|
|
func (m *GetAncestorsResponse) Encode(buf *Buffer) {
|
|
buf.WriteUint32(uint32(len(m.BlksBytes)))
|
|
for _, blk := range m.BlksBytes {
|
|
buf.WriteBytes(blk)
|
|
}
|
|
}
|
|
|
|
// Decode deserializes GetAncestorsResponse from the reader
|
|
func (m *GetAncestorsResponse) Decode(r *Reader) error {
|
|
count, err := r.ReadCount()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m.BlksBytes = make([][]byte, count)
|
|
for i := uint32(0); i < count; i++ {
|
|
if m.BlksBytes[i], err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetBlockIDAtHeightRequest contains height to query
|
|
type GetBlockIDAtHeightRequest struct {
|
|
Height uint64
|
|
}
|
|
|
|
// Encode serializes GetBlockIDAtHeightRequest to the buffer
|
|
func (m *GetBlockIDAtHeightRequest) Encode(buf *Buffer) {
|
|
buf.WriteUint64(m.Height)
|
|
}
|
|
|
|
// Decode deserializes GetBlockIDAtHeightRequest from the reader
|
|
func (m *GetBlockIDAtHeightRequest) Decode(r *Reader) error {
|
|
var err error
|
|
m.Height, err = r.ReadUint64()
|
|
return err
|
|
}
|
|
|
|
// GetBlockIDAtHeightResponse contains block ID at height
|
|
type GetBlockIDAtHeightResponse struct {
|
|
BlkID []byte
|
|
Err Error
|
|
}
|
|
|
|
// Encode serializes GetBlockIDAtHeightResponse to the buffer
|
|
func (m *GetBlockIDAtHeightResponse) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.BlkID)
|
|
buf.WriteUint8(uint8(m.Err))
|
|
}
|
|
|
|
// Decode deserializes GetBlockIDAtHeightResponse from the reader
|
|
func (m *GetBlockIDAtHeightResponse) Decode(r *Reader) error {
|
|
var err error
|
|
if m.BlkID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
v, err := r.ReadUint8()
|
|
m.Err = Error(v)
|
|
return err
|
|
}
|
|
|
|
// RequestMsg contains incoming request data
|
|
type RequestMsg struct {
|
|
NodeID []byte
|
|
RequestID uint32
|
|
Deadline int64
|
|
Request []byte
|
|
}
|
|
|
|
// Encode serializes RequestMsg to the buffer
|
|
func (m *RequestMsg) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.NodeID)
|
|
buf.WriteUint32(m.RequestID)
|
|
buf.WriteInt64(m.Deadline)
|
|
buf.WriteBytes(m.Request)
|
|
}
|
|
|
|
// Decode deserializes RequestMsg from the reader
|
|
func (m *RequestMsg) Decode(r *Reader) error {
|
|
var err error
|
|
if m.NodeID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.RequestID, err = r.ReadUint32(); err != nil {
|
|
return err
|
|
}
|
|
if m.Deadline, err = r.ReadInt64(); err != nil {
|
|
return err
|
|
}
|
|
m.Request, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// RequestFailedMsg contains failed request info
|
|
type RequestFailedMsg struct {
|
|
NodeID []byte
|
|
RequestID uint32
|
|
ErrorCode int32
|
|
ErrorMessage string
|
|
}
|
|
|
|
// Encode serializes RequestFailedMsg to the buffer
|
|
func (m *RequestFailedMsg) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.NodeID)
|
|
buf.WriteUint32(m.RequestID)
|
|
buf.WriteInt32(m.ErrorCode)
|
|
buf.WriteString(m.ErrorMessage)
|
|
}
|
|
|
|
// Decode deserializes RequestFailedMsg from the reader
|
|
func (m *RequestFailedMsg) Decode(r *Reader) error {
|
|
var err error
|
|
if m.NodeID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.RequestID, err = r.ReadUint32(); err != nil {
|
|
return err
|
|
}
|
|
if m.ErrorCode, err = r.ReadInt32(); err != nil {
|
|
return err
|
|
}
|
|
m.ErrorMessage, err = r.ReadString()
|
|
return err
|
|
}
|
|
|
|
// ResponseMsg contains response data
|
|
type ResponseMsg struct {
|
|
NodeID []byte
|
|
RequestID uint32
|
|
Response []byte
|
|
}
|
|
|
|
// Encode serializes ResponseMsg to the buffer
|
|
func (m *ResponseMsg) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.NodeID)
|
|
buf.WriteUint32(m.RequestID)
|
|
buf.WriteBytes(m.Response)
|
|
}
|
|
|
|
// Decode deserializes ResponseMsg from the reader
|
|
func (m *ResponseMsg) Decode(r *Reader) error {
|
|
var err error
|
|
if m.NodeID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.RequestID, err = r.ReadUint32(); err != nil {
|
|
return err
|
|
}
|
|
m.Response, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// GossipMsg contains gossip message
|
|
type GossipMsg struct {
|
|
NodeID []byte
|
|
Msg []byte
|
|
}
|
|
|
|
// Encode serializes GossipMsg to the buffer
|
|
func (m *GossipMsg) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.NodeID)
|
|
buf.WriteBytes(m.Msg)
|
|
}
|
|
|
|
// Decode deserializes GossipMsg from the reader
|
|
func (m *GossipMsg) Decode(r *Reader) error {
|
|
var err error
|
|
if m.NodeID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
m.Msg, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// ConnectedRequest contains connection info
|
|
type ConnectedRequest struct {
|
|
NodeID []byte
|
|
Name string
|
|
Major uint32
|
|
Minor uint32
|
|
Patch uint32
|
|
}
|
|
|
|
// Encode serializes ConnectedRequest to the buffer
|
|
func (m *ConnectedRequest) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.NodeID)
|
|
buf.WriteString(m.Name)
|
|
buf.WriteUint32(m.Major)
|
|
buf.WriteUint32(m.Minor)
|
|
buf.WriteUint32(m.Patch)
|
|
}
|
|
|
|
// Decode deserializes ConnectedRequest from the reader
|
|
func (m *ConnectedRequest) Decode(r *Reader) error {
|
|
var err error
|
|
if m.NodeID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.Name, err = r.ReadString(); err != nil {
|
|
return err
|
|
}
|
|
if m.Major, err = r.ReadUint32(); err != nil {
|
|
return err
|
|
}
|
|
if m.Minor, err = r.ReadUint32(); err != nil {
|
|
return err
|
|
}
|
|
m.Patch, err = r.ReadUint32()
|
|
return err
|
|
}
|
|
|
|
// DisconnectedRequest contains disconnection info
|
|
type DisconnectedRequest struct {
|
|
NodeID []byte
|
|
}
|
|
|
|
// Encode serializes DisconnectedRequest to the buffer
|
|
func (m *DisconnectedRequest) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.NodeID)
|
|
}
|
|
|
|
// Decode deserializes DisconnectedRequest from the reader
|
|
func (m *DisconnectedRequest) Decode(r *Reader) error {
|
|
var err error
|
|
m.NodeID, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// HealthResponse contains health check result
|
|
type HealthResponse struct {
|
|
Details []byte
|
|
}
|
|
|
|
// Encode serializes HealthResponse to the buffer
|
|
func (m *HealthResponse) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.Details)
|
|
}
|
|
|
|
// Decode deserializes HealthResponse from the reader
|
|
func (m *HealthResponse) Decode(r *Reader) error {
|
|
var err error
|
|
m.Details, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// VersionResponse contains version info
|
|
type VersionResponse struct {
|
|
Version string
|
|
}
|
|
|
|
// Encode serializes VersionResponse to the buffer
|
|
func (m *VersionResponse) Encode(buf *Buffer) {
|
|
buf.WriteString(m.Version)
|
|
}
|
|
|
|
// Decode deserializes VersionResponse from the reader
|
|
func (m *VersionResponse) Decode(r *Reader) error {
|
|
var err error
|
|
m.Version, err = r.ReadString()
|
|
return err
|
|
}
|
|
|
|
// WaitForEventResponse contains event type
|
|
type WaitForEventResponse struct {
|
|
Message uint8
|
|
}
|
|
|
|
// Encode serializes WaitForEventResponse to the buffer
|
|
func (m *WaitForEventResponse) Encode(buf *Buffer) {
|
|
buf.WriteUint8(m.Message)
|
|
}
|
|
|
|
// Decode deserializes WaitForEventResponse from the reader
|
|
func (m *WaitForEventResponse) Decode(r *Reader) error {
|
|
var err error
|
|
m.Message, err = r.ReadUint8()
|
|
return err
|
|
}
|
|
|
|
// HTTPHandler contains HTTP handler info
|
|
type HTTPHandler struct {
|
|
Prefix string
|
|
ServerAddr string
|
|
}
|
|
|
|
// Encode serializes HTTPHandler to the buffer
|
|
func (m *HTTPHandler) Encode(buf *Buffer) {
|
|
buf.WriteString(m.Prefix)
|
|
buf.WriteString(m.ServerAddr)
|
|
}
|
|
|
|
// Decode deserializes HTTPHandler from the reader
|
|
func (m *HTTPHandler) Decode(r *Reader) error {
|
|
var err error
|
|
if m.Prefix, err = r.ReadString(); err != nil {
|
|
return err
|
|
}
|
|
m.ServerAddr, err = r.ReadString()
|
|
return err
|
|
}
|
|
|
|
// CreateHandlersResponse contains handler list
|
|
type CreateHandlersResponse struct {
|
|
Handlers []HTTPHandler
|
|
}
|
|
|
|
// Encode serializes CreateHandlersResponse to the buffer
|
|
func (m *CreateHandlersResponse) Encode(buf *Buffer) {
|
|
buf.WriteUint32(uint32(len(m.Handlers)))
|
|
for i := range m.Handlers {
|
|
m.Handlers[i].Encode(buf)
|
|
}
|
|
}
|
|
|
|
// Decode deserializes CreateHandlersResponse from the reader
|
|
func (m *CreateHandlersResponse) Decode(r *Reader) error {
|
|
count, err := r.ReadCount()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m.Handlers = make([]HTTPHandler, count)
|
|
for i := uint32(0); i < count; i++ {
|
|
if err := m.Handlers[i].Decode(r); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NewHTTPHandlerResponse contains HTTP handler address
|
|
type NewHTTPHandlerResponse struct {
|
|
ServerAddr string
|
|
}
|
|
|
|
// Encode serializes NewHTTPHandlerResponse to the buffer
|
|
func (m *NewHTTPHandlerResponse) Encode(buf *Buffer) {
|
|
buf.WriteString(m.ServerAddr)
|
|
}
|
|
|
|
// Decode deserializes NewHTTPHandlerResponse from the reader
|
|
func (m *NewHTTPHandlerResponse) Decode(r *Reader) error {
|
|
var err error
|
|
m.ServerAddr, err = r.ReadString()
|
|
return err
|
|
}
|
|
|
|
// SetQuasarFinalizedRequest carries a new Quasar (⅔-by-stake) EXPORT-FINAL height
|
|
// from the node's consensus export-frontier observer to the VM (MsgSetQuasarFinalized).
|
|
// The VM persists it; the response is empty.
|
|
type SetQuasarFinalizedRequest struct {
|
|
Height uint64
|
|
}
|
|
|
|
// Encode serializes SetQuasarFinalizedRequest to the buffer
|
|
func (m *SetQuasarFinalizedRequest) Encode(buf *Buffer) {
|
|
buf.WriteUint64(m.Height)
|
|
}
|
|
|
|
// Decode deserializes SetQuasarFinalizedRequest from the reader
|
|
func (m *SetQuasarFinalizedRequest) Decode(r *Reader) error {
|
|
var err error
|
|
m.Height, err = r.ReadUint64()
|
|
return err
|
|
}
|
|
|
|
// QuasarHeightResponse carries the VM's current accept-tip-CLAMPED Quasar
|
|
// EXPORT-FINAL height (MsgQuasarHeight) — 0 before the first export forms. The
|
|
// MsgQuasarHeight request has no fields (empty payload).
|
|
type QuasarHeightResponse struct {
|
|
Height uint64
|
|
}
|
|
|
|
// Encode serializes QuasarHeightResponse to the buffer
|
|
func (m *QuasarHeightResponse) Encode(buf *Buffer) {
|
|
buf.WriteUint64(m.Height)
|
|
}
|
|
|
|
// Decode deserializes QuasarHeightResponse from the reader
|
|
func (m *QuasarHeightResponse) Decode(r *Reader) error {
|
|
var err error
|
|
m.Height, err = r.ReadUint64()
|
|
return err
|
|
}
|
|
|
|
// State sync over the boundary.
|
|
//
|
|
// A state-syncable VM is asked five questions and hands back summaries; a
|
|
// summary is then accepted, which starts the sync. The five questions are
|
|
// ordinary request/response. Accept is not: a summary is an object with
|
|
// behaviour on the VM's side, and only its identity can cross. So Accept
|
|
// travels as an id, and the server answers it against the summary it produced
|
|
// under that id — the same shape a block takes, for the same reason.
|
|
|
|
// StateSyncEnabledResponse answers whether this VM syncs state at all.
|
|
type StateSyncEnabledResponse struct {
|
|
Enabled bool
|
|
Err Error
|
|
}
|
|
|
|
func (m *StateSyncEnabledResponse) Encode(buf *Buffer) {
|
|
buf.WriteBool(m.Enabled)
|
|
buf.WriteUint8(uint8(m.Err))
|
|
}
|
|
|
|
func (m *StateSyncEnabledResponse) Decode(r *Reader) error {
|
|
var err error
|
|
if m.Enabled, err = r.ReadBool(); err != nil {
|
|
return err
|
|
}
|
|
v, err := r.ReadUint8()
|
|
m.Err = Error(v)
|
|
return err
|
|
}
|
|
|
|
// SummaryResponse carries one state summary: what a caller can read off it
|
|
// without holding the object. Every question that answers with a summary
|
|
// answers with this, because the answers differ only in which summary they
|
|
// name, never in what a summary is.
|
|
//
|
|
// An absent summary is not an error and not a zero-valued one: Err says
|
|
// ErrorNotFound and the caller must not read the fields. A VM that does not
|
|
// sync state at all says ErrorStateSyncNotImplemented, which is a different
|
|
// answer from "I sync, and have nothing".
|
|
type SummaryResponse struct {
|
|
ID []byte
|
|
Height uint64
|
|
Bytes []byte
|
|
Err Error
|
|
}
|
|
|
|
func (m *SummaryResponse) Encode(buf *Buffer) {
|
|
buf.WriteBytes(m.ID)
|
|
buf.WriteUint64(m.Height)
|
|
buf.WriteBytes(m.Bytes)
|
|
buf.WriteUint8(uint8(m.Err))
|
|
}
|
|
|
|
func (m *SummaryResponse) Decode(r *Reader) error {
|
|
var err error
|
|
if m.ID, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
if m.Height, err = r.ReadUint64(); err != nil {
|
|
return err
|
|
}
|
|
if m.Bytes, err = r.ReadBytes(); err != nil {
|
|
return err
|
|
}
|
|
v, err := r.ReadUint8()
|
|
m.Err = Error(v)
|
|
return err
|
|
}
|
|
|
|
// ParseStateSummaryRequest carries a peer's summary bytes for the VM to read.
|
|
type ParseStateSummaryRequest struct {
|
|
Bytes []byte
|
|
}
|
|
|
|
func (m *ParseStateSummaryRequest) Encode(buf *Buffer) { buf.WriteBytes(m.Bytes) }
|
|
|
|
func (m *ParseStateSummaryRequest) Decode(r *Reader) error {
|
|
var err error
|
|
m.Bytes, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// GetStateSummaryRequest names the height whose summary is wanted.
|
|
type GetStateSummaryRequest struct {
|
|
Height uint64
|
|
}
|
|
|
|
func (m *GetStateSummaryRequest) Encode(buf *Buffer) { buf.WriteUint64(m.Height) }
|
|
|
|
func (m *GetStateSummaryRequest) Decode(r *Reader) error {
|
|
var err error
|
|
m.Height, err = r.ReadUint64()
|
|
return err
|
|
}
|
|
|
|
// StateSummaryAcceptRequest names the summary to accept.
|
|
//
|
|
// By id, because accepting is the summary's own behaviour and the summary is on
|
|
// the far side. The server resolves the id against the summaries it has handed
|
|
// out; an id it never produced is refused rather than reconstructed, since a
|
|
// summary rebuilt from bytes a caller supplies is not the one that was ratified.
|
|
type StateSummaryAcceptRequest struct {
|
|
ID []byte
|
|
}
|
|
|
|
func (m *StateSummaryAcceptRequest) Encode(buf *Buffer) { buf.WriteBytes(m.ID) }
|
|
|
|
func (m *StateSummaryAcceptRequest) Decode(r *Reader) error {
|
|
var err error
|
|
m.ID, err = r.ReadBytes()
|
|
return err
|
|
}
|
|
|
|
// StateSummaryAcceptResponse reports which way the VM decided to sync.
|
|
type StateSummaryAcceptResponse struct {
|
|
Mode uint8
|
|
Err Error
|
|
}
|
|
|
|
func (m *StateSummaryAcceptResponse) Encode(buf *Buffer) {
|
|
buf.WriteUint8(m.Mode)
|
|
buf.WriteUint8(uint8(m.Err))
|
|
}
|
|
|
|
func (m *StateSummaryAcceptResponse) Decode(r *Reader) error {
|
|
var err error
|
|
if m.Mode, err = r.ReadUint8(); err != nil {
|
|
return err
|
|
}
|
|
v, err := r.ReadUint8()
|
|
m.Err = Error(v)
|
|
return err
|
|
}
|