mirror of
https://github.com/luxfi/node.git
synced 2026-10-30 15:24:05 +00:00
The module already called itself github.com/luxfi/node while containing no node in Go: cmd/luxd was twenty-one lines that printed the size of a few types, and the Go column of the matrix measured a VM plugin. A repo that fetches the thing it claims to be has not replaced it, so the Go sources move in — 1515 files, the daemon and everything under it — and the build reaches outside this module for nothing. Rust and C++ sit beside it unchanged and are still measured against it by the differential. That is the point of one repo: the reference implementation and the two ports are the same checkout, so parity is a thing you can run rather than a thing you assert. Verified: builds, and the closure carries no lux-private — checked at build time rather than believed. The daemon starts twelve chains on a local network (P X C Q Z A B G K M F, plus D through its plugin) and reports healthy.
142 lines
4.2 KiB
Go
142 lines
4.2 KiB
Go
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package message
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/crypto/bls"
|
|
"github.com/luxfi/crypto/hash"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/vm/types"
|
|
"github.com/luxfi/zap"
|
|
)
|
|
|
|
type ChainToL1ConversionValidatorData struct {
|
|
NodeID types.JSONByteSlice `json:"nodeID"`
|
|
BLSPublicKey [bls.PublicKeyLen]byte `json:"blsPublicKey"`
|
|
Weight uint64 `json:"weight"`
|
|
}
|
|
|
|
type ChainToL1ConversionData struct {
|
|
ChainID ids.ID `json:"chainID"`
|
|
ManagerChainID ids.ID `json:"managerChainID"`
|
|
ManagerAddress types.JSONByteSlice `json:"managerAddress"`
|
|
Validators []ChainToL1ConversionValidatorData `json:"validators"`
|
|
}
|
|
|
|
// ChainToL1ConversionData wire (standalone hash-preimage buffer, no kind byte):
|
|
// ChainID 32B @0, ManagerChainID 32B @32, ManagerAddress bytes @64, Validators
|
|
// list @72 (stride 64: nodeIDStart u32, nodeIDLen u32, BLSPublicKey 48B,
|
|
// Weight u64), NodeID byte pool @80.
|
|
const (
|
|
cdOffChainID = 0
|
|
cdOffManagerID = 32
|
|
cdOffManagerAddr = 64
|
|
cdOffValidators = 72
|
|
cdOffNodeIDPool = 80
|
|
cdSize = 88
|
|
|
|
cvNodeIDStart = 0
|
|
cvNodeIDLen = 4
|
|
cvBLSKey = 8
|
|
cvWeight = 56
|
|
cvStride = 64
|
|
)
|
|
|
|
// Marshal is the ONE canonical byte encoding of the conversion data — the
|
|
// hash preimage of ChainToL1ConversionID. ChainToL1ConversionID calls this
|
|
// same encoder, so the ID and the bytes can never diverge.
|
|
func (d *ChainToL1ConversionData) Marshal() ([]byte, error) {
|
|
b := zap.NewBuilder(zap.HeaderSize + cdSize + len(d.Validators)*cvStride + len(d.ManagerAddress) + 256)
|
|
|
|
var nodeIDPool []byte
|
|
vdrOff, vdrCount := 0, 0
|
|
if len(d.Validators) > 0 {
|
|
lb := b.StartList(cvStride)
|
|
for _, v := range d.Validators {
|
|
var e [cvStride]byte
|
|
binary.LittleEndian.PutUint32(e[cvNodeIDStart:], uint32(len(nodeIDPool)))
|
|
binary.LittleEndian.PutUint32(e[cvNodeIDLen:], uint32(len(v.NodeID)))
|
|
nodeIDPool = append(nodeIDPool, v.NodeID...)
|
|
copy(e[cvBLSKey:], v.BLSPublicKey[:])
|
|
binary.LittleEndian.PutUint64(e[cvWeight:], v.Weight)
|
|
lb.AddBytes(e[:])
|
|
}
|
|
vdrOff, _ = lb.Finish()
|
|
vdrCount = len(d.Validators) // AddBytes counts bytes, not elements
|
|
}
|
|
|
|
ob := b.StartObject(cdSize)
|
|
ob.SetBytesFixed(cdOffChainID, d.ChainID[:])
|
|
ob.SetBytesFixed(cdOffManagerID, d.ManagerChainID[:])
|
|
ob.SetBytes(cdOffManagerAddr, d.ManagerAddress)
|
|
ob.SetList(cdOffValidators, vdrOff, vdrCount)
|
|
ob.SetBytes(cdOffNodeIDPool, nodeIDPool)
|
|
ob.FinishAsRoot()
|
|
return b.Finish(), nil
|
|
}
|
|
|
|
// ChainToL1ConversionID creates a chain conversion ID from the provided
|
|
// chain conversion data. The preimage is exactly ChainToL1ConversionData.Marshal.
|
|
func ChainToL1ConversionID(data ChainToL1ConversionData) (ids.ID, error) {
|
|
bytes, err := data.Marshal()
|
|
if err != nil {
|
|
return ids.Empty, err
|
|
}
|
|
return hash.ComputeHash256Array(bytes), nil
|
|
}
|
|
|
|
// ChainToL1Conversion reports the summary of the chain conversion that
|
|
// occurred on the P-chain.
|
|
//
|
|
// Wire: mkind u8 @0, ID 32B @1 = 33 bytes.
|
|
type ChainToL1Conversion struct {
|
|
payload
|
|
|
|
// ID of the chain conversion. It is typically generated by calling
|
|
// ChainToL1ConversionID.
|
|
ID ids.ID `json:"id"`
|
|
}
|
|
|
|
const (
|
|
convOffID = 1
|
|
convSize = 33
|
|
)
|
|
|
|
// NewChainToL1Conversion creates a new initialized ChainToL1Conversion.
|
|
func NewChainToL1Conversion(id ids.ID) (*ChainToL1Conversion, error) {
|
|
msg := &ChainToL1Conversion{
|
|
ID: id,
|
|
}
|
|
b := zap.NewBuilder(zap.HeaderSize + convSize)
|
|
ob := b.StartObject(convSize)
|
|
ob.SetUint8(offMKind, uint8(mkindChainToL1Conversion))
|
|
ob.SetBytesFixed(convOffID, id[:])
|
|
ob.FinishAsRoot()
|
|
msg.initialize(b.Finish())
|
|
return msg, nil
|
|
}
|
|
|
|
func parseChainToL1Conversion(root zap.Object) *ChainToL1Conversion {
|
|
return &ChainToL1Conversion{
|
|
ID: readID(root, convOffID),
|
|
}
|
|
}
|
|
|
|
// ParseChainToL1Conversion parses bytes into an initialized
|
|
// ChainToL1Conversion.
|
|
func ParseChainToL1Conversion(b []byte) (*ChainToL1Conversion, error) {
|
|
payloadIntf, err := Parse(b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
payload, ok := payloadIntf.(*ChainToL1Conversion)
|
|
if !ok {
|
|
return nil, fmt.Errorf("%w: %T", ErrWrongType, payloadIntf)
|
|
}
|
|
return payload, nil
|
|
}
|