mirror of
https://github.com/luxfi/chains.git
synced 2026-09-24 00:26:00 +00:00
The lane registry had two paths to a verifier. Register refuses a lane that does not belong to the registry's owner, and its comment says that is what enforces M/F orthogonality. RegisterLegacyAlias then mapped any id at all onto a registered verifier, checking only that the TARGET existed and never that the legacy id belonged to the owner -- so the alias walked around the invariant Register exists to hold. The test demonstrated it: an arbitrary id 200, owned by neither chain, dispatching to an M-Chain verifier. It bought a grace window for LP-5013 T-Chain lane ids. LP-134 dissolved T-Chain with zero remainder, so those ids cannot arrive. Nothing outside the test ever registered an alias. Gone, with the aliases map and ClearAliases: a lane this chain does not own now has no verifier, which is the ownership rule still holding at dispatch. Deleting mpcvm/runtime's two adapter interfaces emptied the package. FChainAdapter and MChainAdapter were declared, never implemented and never called -- every reference to either was inside its own file.
121 lines
3.8 KiB
Go
121 lines
3.8 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Package cert provides the QuasarCertLane registration and
|
|
// certificate-subject binding logic shared by M-Chain and F-Chain.
|
|
//
|
|
// The lane registry is **not** a global. Each chain constructs its
|
|
// own LaneRegistry at boot, registers only the verifiers it owns
|
|
// (M-Chain registers lanes 5..7, F-Chain registers lanes 8..9), and
|
|
// the substrate refuses cross-registration at runtime — a misrouted
|
|
// verifier fails fast.
|
|
package cert
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/chains/mpcvm/types"
|
|
)
|
|
|
|
// LaneVerifier is the contract a chain implements to validate shares
|
|
// on a given cert lane. Verifiers are stateless with respect to the
|
|
// substrate; any mutable state lives in the chain's own runtime.
|
|
type LaneVerifier interface {
|
|
// Lane returns the lane identifier this verifier handles.
|
|
Lane() types.CertLane
|
|
// Verify validates a share's payload against the certificate
|
|
// subject. The payload was extracted via Share.PayloadFrom on
|
|
// the ceremony's PayloadArena.
|
|
Verify(subject [32]byte, share types.Share, payload []byte) error
|
|
}
|
|
|
|
// Owner identifies which operational chain owns a lane registry. The
|
|
// substrate uses Owner to enforce orthogonality: an M-Chain registry
|
|
// refuses F-Chain lanes and vice versa.
|
|
type Owner uint8
|
|
|
|
const (
|
|
OwnerUnknown Owner = 0
|
|
OwnerMChain Owner = 1
|
|
OwnerFChain Owner = 2
|
|
)
|
|
|
|
// LaneRegistry holds the verifier dispatch table for one chain.
|
|
//
|
|
// One registry per chain process. Constructed at boot, written
|
|
// during boot, read-only thereafter. No locks needed: registrations
|
|
// happen serially before the chain starts accepting blocks.
|
|
type LaneRegistry struct {
|
|
owner Owner
|
|
verifier map[types.CertLane]LaneVerifier
|
|
}
|
|
|
|
// NewRegistry constructs a registry owned by the given chain.
|
|
func NewRegistry(owner Owner) *LaneRegistry {
|
|
return &LaneRegistry{
|
|
owner: owner,
|
|
verifier: make(map[types.CertLane]LaneVerifier),
|
|
}
|
|
}
|
|
|
|
// Register adds a verifier to the registry. Returns an error if the
|
|
// lane does not belong to the registry's owner — this enforces M/F
|
|
// orthogonality at the type level.
|
|
func (r *LaneRegistry) Register(v LaneVerifier) error {
|
|
if v == nil {
|
|
return errors.New("registry: nil verifier")
|
|
}
|
|
lane := v.Lane()
|
|
switch r.owner {
|
|
case OwnerMChain:
|
|
if !lane.IsMChain() {
|
|
return fmt.Errorf("registry: lane %d is not owned by M-Chain", lane)
|
|
}
|
|
case OwnerFChain:
|
|
if !lane.IsFChain() {
|
|
return fmt.Errorf("registry: lane %d is not owned by F-Chain", lane)
|
|
}
|
|
default:
|
|
return errors.New("registry: owner unset")
|
|
}
|
|
if _, exists := r.verifier[lane]; exists {
|
|
return fmt.Errorf("registry: lane %d already registered", lane)
|
|
}
|
|
r.verifier[lane] = v
|
|
return nil
|
|
}
|
|
|
|
// Verifier resolves a lane to its verifier. Returns an error if no verifier
|
|
// is registered — a lane this chain does not own has none, which is how
|
|
// Register's ownership rule keeps holding at dispatch time.
|
|
func (r *LaneRegistry) Verifier(lane types.CertLane) (LaneVerifier, error) {
|
|
v, ok := r.verifier[lane]
|
|
if !ok {
|
|
return nil, fmt.Errorf("registry: no verifier for lane %d", lane)
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
// Verify dispatches a share to its lane verifier. Convenience wrapper
|
|
// for the chain runtime — validates the share envelope, extracts the
|
|
// payload window, and calls the verifier.
|
|
func (r *LaneRegistry) Verify(subject [32]byte, share types.Share, arena []byte, set *types.ParticipantSet) error {
|
|
if err := share.Validate(set); err != nil {
|
|
return err
|
|
}
|
|
v, err := r.Verifier(share.Lane)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
payload, err := share.PayloadFrom(arena)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return v.Verify(subject, share, payload)
|
|
}
|
|
|
|
// Owner reports which chain owns this registry. Used by tests and
|
|
// boot-time sanity checks.
|
|
func (r *LaneRegistry) Owner() Owner { return r.owner }
|