mirror of
https://github.com/luxfi/chains.git
synced 2026-09-24 00:26:00 +00:00
mpcvm: one way for a lane to reach its verifier, and no dead contracts
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.
This commit is contained in:
+3
-26
@@ -49,9 +49,6 @@ const (
|
||||
type LaneRegistry struct {
|
||||
owner Owner
|
||||
verifier map[types.CertLane]LaneVerifier
|
||||
// aliases lets the host wire legacy-lane-id → modern-lane during
|
||||
// the LP-134 grace window. Empty after the grace epoch closes.
|
||||
aliases map[types.CertLane]types.CertLane
|
||||
}
|
||||
|
||||
// NewRegistry constructs a registry owned by the given chain.
|
||||
@@ -59,7 +56,6 @@ func NewRegistry(owner Owner) *LaneRegistry {
|
||||
return &LaneRegistry{
|
||||
owner: owner,
|
||||
verifier: make(map[types.CertLane]LaneVerifier),
|
||||
aliases: make(map[types.CertLane]types.CertLane),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,29 +86,10 @@ func (r *LaneRegistry) Register(v LaneVerifier) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterLegacyAlias maps a legacy LP-5013 T-Chain lane to the
|
||||
// modern M/F lane during the grace window. After the window closes,
|
||||
// the host calls ClearAliases() and any legacy share is rejected.
|
||||
func (r *LaneRegistry) RegisterLegacyAlias(legacy, modern types.CertLane) error {
|
||||
if _, ok := r.verifier[modern]; !ok {
|
||||
return fmt.Errorf("registry: cannot alias to unregistered lane %d", modern)
|
||||
}
|
||||
r.aliases[legacy] = modern
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearAliases removes all legacy aliases. Called by the host at the
|
||||
// end of the grace epoch.
|
||||
func (r *LaneRegistry) ClearAliases() {
|
||||
r.aliases = make(map[types.CertLane]types.CertLane)
|
||||
}
|
||||
|
||||
// Verifier resolves a lane (including grace-window aliases) to its
|
||||
// verifier. Returns an error if no verifier is registered.
|
||||
// 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) {
|
||||
if alias, ok := r.aliases[lane]; ok {
|
||||
lane = alias
|
||||
}
|
||||
v, ok := r.verifier[lane]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("registry: no verifier for lane %d", lane)
|
||||
|
||||
@@ -87,26 +87,3 @@ func TestRegister_RejectsDoubleRegistration(t *testing.T) {
|
||||
t.Fatal("expected second registration to fail")
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy alias dispatch: a legacy lane id resolves to the modern verifier.
|
||||
func TestLegacyAlias_DispatchesToModern(t *testing.T) {
|
||||
r := NewRegistry(OwnerMChain)
|
||||
if err := r.Register(stubVerifier{lane: types.LaneMChainCGGMP21}); err != nil {
|
||||
t.Fatalf("register: %v", err)
|
||||
}
|
||||
const legacyTChainSign types.CertLane = 200 // arbitrary legacy id
|
||||
if err := r.RegisterLegacyAlias(legacyTChainSign, types.LaneMChainCGGMP21); err != nil {
|
||||
t.Fatalf("alias: %v", err)
|
||||
}
|
||||
v, err := r.Verifier(legacyTChainSign)
|
||||
if err != nil {
|
||||
t.Fatalf("legacy lookup: %v", err)
|
||||
}
|
||||
if v.Lane() != types.LaneMChainCGGMP21 {
|
||||
t.Fatalf("legacy alias should dispatch to MChainCGGMP21, got %d", v.Lane())
|
||||
}
|
||||
r.ClearAliases()
|
||||
if _, err := r.Verifier(legacyTChainSign); err == nil {
|
||||
t.Fatal("after ClearAliases, legacy id should not resolve")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/luxfi/chains/mpcvm/cert"
|
||||
"github.com/luxfi/chains/mpcvm/types"
|
||||
)
|
||||
|
||||
// FChainAdapter is the contract F-Chain implements. Same state
|
||||
// machine as M-Chain, different hooks: F-Chain consumes upstream MPC
|
||||
// outputs and emits FHE compute attestations.
|
||||
type FChainAdapter interface {
|
||||
// Selector returns the F-Chain participant selector. Stake-weighted
|
||||
// over P-Chain stake delegated to F-Chain. GPU operators
|
||||
// self-select by delegating here rather than to M-Chain.
|
||||
Selector() types.Selector
|
||||
|
||||
// Registry returns the F-Chain LaneRegistry. Must be owned by
|
||||
// OwnerFChain and have verifiers for LaneFChainTFHE,
|
||||
// LaneFChainBootstrap registered.
|
||||
Registry() *cert.LaneRegistry
|
||||
|
||||
// FHERoot returns fchain_fhe_root at the current epoch. Bound
|
||||
// into certificate_subject alongside mchain_ceremony_root.
|
||||
FHERoot(ctx context.Context, epoch uint64) ([32]byte, error)
|
||||
|
||||
// OnBootstrapHandoff is called by the substrate when M-Chain
|
||||
// finalizes a KindTFHEKeygen ceremony and hands off the bootstrap
|
||||
// key. F-Chain re-verifies under the M-Chain ceremony root and
|
||||
// installs the key.
|
||||
OnBootstrapHandoff(ctx context.Context, mchainSubject [32]byte, proof types.Proof) error
|
||||
|
||||
// OnEval is called for a TFHE compute ceremony. The participant
|
||||
// set is the F-Chain GPU operators selected by VRF.
|
||||
OnEval(ctx context.Context, ceremony types.Ceremony, set *types.ParticipantSet) error
|
||||
|
||||
// OnFinalize emits the finalized cert artifact onto Quasar 3.0's
|
||||
// CertLane and advances fchain_fhe_root.
|
||||
OnFinalize(ctx context.Context, ceremony types.Ceremony, proof types.Proof) error
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
// Package runtime defines the adapter contracts the host chains
|
||||
// (M-Chain and F-Chain) implement to plug into the ThresholdVM
|
||||
// substrate.
|
||||
//
|
||||
// The substrate calls into adapters; adapters never call into the
|
||||
// substrate. This is the orthogonality boundary at the type level:
|
||||
// MChainAdapter exposes only MPC hooks, FChainAdapter exposes only
|
||||
// FHE hooks. A chain that implements both interfaces is a
|
||||
// configuration error.
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/luxfi/chains/mpcvm/cert"
|
||||
"github.com/luxfi/chains/mpcvm/types"
|
||||
)
|
||||
|
||||
// MChainAdapter is the contract M-Chain implements. The substrate
|
||||
// drives ceremonies by calling these hooks; M-Chain provides the
|
||||
// validator-set selection, persistence, and cert-emission.
|
||||
type MChainAdapter interface {
|
||||
// Selector returns the M-Chain participant selector. Stake-weighted
|
||||
// VRF over P-Chain stake delegated to M-Chain.
|
||||
Selector() types.Selector
|
||||
|
||||
// Registry returns the M-Chain LaneRegistry. Must be owned by
|
||||
// OwnerMChain and have verifiers for LaneMChainCGGMP21,
|
||||
// LaneMChainFROST, LaneMChainCoronaGen registered.
|
||||
Registry() *cert.LaneRegistry
|
||||
|
||||
// CeremonyRoot returns mchain_ceremony_root at the current epoch.
|
||||
// Bound into certificate_subject by Quasar 3.0.
|
||||
CeremonyRoot(ctx context.Context, epoch uint64) ([32]byte, error)
|
||||
|
||||
// OnDKG is called by the substrate when a new DKG ceremony enters
|
||||
// StateRegistered. M-Chain persists the participant set and
|
||||
// allocates the payload arena.
|
||||
OnDKG(ctx context.Context, ceremony types.Ceremony, set *types.ParticipantSet) error
|
||||
|
||||
// OnSign is called for a signing ceremony. Same shape as OnDKG;
|
||||
// distinguished only by Ceremony.Kind.
|
||||
OnSign(ctx context.Context, ceremony types.Ceremony, set *types.ParticipantSet) error
|
||||
|
||||
// OnReshare is called for an LSS resharing ceremony (LP-077). The
|
||||
// new participant set replaces the old one atomically at
|
||||
// finalize.
|
||||
OnReshare(ctx context.Context, ceremony types.Ceremony, oldSet, newSet *types.ParticipantSet) error
|
||||
|
||||
// OnFinalize emits the finalized cert artifact onto Quasar 3.0's
|
||||
// CertLane and advances mchain_ceremony_root. If the ceremony's
|
||||
// kind is KindTFHEKeygen, the proof is also handed off to F-Chain
|
||||
// via the cross-chain envelope.
|
||||
OnFinalize(ctx context.Context, ceremony types.Ceremony, proof types.Proof) error
|
||||
}
|
||||
Reference in New Issue
Block a user