mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
Squashed batch covering all post-Feb-28 consensus work, capped by the LSS-Pulsar cutover (task #53): - Quasar cutover from upstream Corona to LSS-Pulsar adapter: go.mod: drop direct require github.com/luxfi/corona; add github.com/luxfi/pulsar + github.com/luxfi/threshold; local replaces => ../pulsar, ../threshold epoch.go: InitializeEpoch → keyera.Bootstrap; RotateEpoch → lss.DynamicResharePulsar gated by activation cert verification under unchanged GroupKey quasar.go, grouped_threshold.go: import swap corona → pulsar reshare_epoch.go: production wiring; QUASAR-PULSAR-ACTIVATE-v1 domain prefix; ReshareEpoch + RefreshEpoch EpochKeys: gains KeyEraID, Generation, RollbackFrom (LP-105) BundleSigner: re-derives Lambda for participating subset 258 quasar tests pass. - Earlier post-Feb-28 work (gofmt linter fixes across protocol files, METASTABLE_SIGNED_QUERIES.md doc, MLDSAProof rename across 7 test files) included in the squash. Hash profile: consensus passes nil to resolve to Pulsar-SHA3 default (LP-105 / pulsar/hash). Activation message canonical bytes bind chain_id, network_id, key_era_id, generation, group_id, epoch, set hashes, thresholds, group_pk_hash, nebula_root, hash_suite_id, implementation_version, variant, reshare_transcript_hash — all under TupleHash256("PULSAR-TRANSCRIPT-v1", ...). Vocabulary alignment with LP-105 (Lux Finality Stack lexicon): Photon (vote) → Beam (BLS) → ML-DSA (PQ identity) → Pulsar (PQ threshold kernel) → Pulse (cert over Nebula root) → Prism (composition verifier) → Horizon (finality boundary) → Quasar (full consensus). Excluded from this commit: pkg/wire/{candidate,policies_test}.go uncommitted diff (pre-existing local edits; stashed and restored). Untracked protocol/quasar/witness_producer.go (mtime Apr 29; pre-task).
228 lines
5.7 KiB
Go
228 lines
5.7 KiB
Go
package block
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/luxfi/database"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/log"
|
|
"github.com/luxfi/runtime"
|
|
"github.com/luxfi/version"
|
|
"github.com/luxfi/warp"
|
|
)
|
|
|
|
// Init defines the initialization parameters for a VM.
|
|
// This mirrors the Init struct from the vm package to avoid circular imports.
|
|
type Init struct {
|
|
// Runtime provides chain-scoped wiring/identity/services.
|
|
Runtime *runtime.Runtime
|
|
|
|
// DB is this chain's database namespace (may be a view).
|
|
DB database.Database
|
|
|
|
// Sender is the canonical warp sender.
|
|
Sender warp.Sender
|
|
|
|
// Log is the logger for the VM.
|
|
Log log.Logger
|
|
|
|
// Genesis, Upgrade, Config are the initialization bytes.
|
|
Genesis []byte
|
|
Upgrade []byte
|
|
Config []byte
|
|
|
|
// Fx registry or feature flags
|
|
Fx []any
|
|
|
|
// ToEngine delivers VM->engine notifications.
|
|
ToEngine chan<- Message
|
|
}
|
|
|
|
// Block is a block in the chain
|
|
type Block interface {
|
|
ID() ids.ID
|
|
Parent() ids.ID
|
|
ParentID() ids.ID
|
|
Height() uint64
|
|
Timestamp() time.Time
|
|
Status() uint8
|
|
Verify(context.Context) error
|
|
Accept(context.Context) error
|
|
Reject(context.Context) error
|
|
Bytes() []byte
|
|
}
|
|
|
|
// Epoch represents a P-Chain epoch for validator set coordination
|
|
type Epoch struct {
|
|
PChainHeight uint64 `serialize:"true" json:"pChainHeight"`
|
|
Number uint64 `serialize:"true" json:"number"`
|
|
StartTime int64 `serialize:"true" json:"startTime"`
|
|
}
|
|
|
|
// SignedBlock extends Block with proposer and epoch information
|
|
type SignedBlock interface {
|
|
Block
|
|
|
|
// PChainHeight returns the P-Chain height when this block was proposed
|
|
PChainHeight() uint64
|
|
|
|
// PChainEpoch returns the P-Chain epoch information
|
|
PChainEpoch() Epoch
|
|
|
|
// Timestamp returns the block timestamp
|
|
Timestamp() time.Time
|
|
|
|
// Proposer returns the ID of the node that proposed this block.
|
|
// If no node signed this block, ids.EmptyNodeID will be returned.
|
|
Proposer() ids.NodeID
|
|
}
|
|
|
|
// HealthCheckResult contains health check information
|
|
type HealthCheckResult struct {
|
|
Healthy bool `json:"healthy"`
|
|
Details map[string]string `json:"details,omitempty"`
|
|
}
|
|
|
|
// ChainVM defines the interface for a blockchain VM
|
|
type ChainVM interface {
|
|
// Initialize initializes the VM using the Init struct
|
|
Initialize(ctx context.Context, init Init) error
|
|
|
|
// BuildBlock builds a new block
|
|
BuildBlock(context.Context) (Block, error)
|
|
|
|
// ParseBlock parses a block from bytes
|
|
ParseBlock(context.Context, []byte) (Block, error)
|
|
|
|
// GetBlock gets a block by ID
|
|
GetBlock(context.Context, ids.ID) (Block, error)
|
|
|
|
// Shutdown shuts down the VM
|
|
Shutdown(context.Context) error
|
|
|
|
// NewHTTPHandler returns a new HTTP handler for the VM
|
|
NewHTTPHandler(context.Context) (http.Handler, error)
|
|
|
|
// SetState sets the VM state
|
|
SetState(context.Context, uint32) error
|
|
|
|
// Version returns the VM version
|
|
Version(context.Context) (string, error)
|
|
|
|
// Network callbacks - optional
|
|
Connected(context.Context, ids.NodeID, *version.Application) error
|
|
Disconnected(context.Context, ids.NodeID) error
|
|
HealthCheck(context.Context) (HealthCheckResult, error)
|
|
|
|
// GetBlockIDAtHeight gets block ID at a specific height
|
|
GetBlockIDAtHeight(context.Context, uint64) (ids.ID, error)
|
|
|
|
// SetPreference sets the preferred block
|
|
SetPreference(context.Context, ids.ID) error
|
|
|
|
// LastAccepted returns the last accepted block
|
|
LastAccepted(context.Context) (ids.ID, error)
|
|
|
|
// WaitForEvent blocks until an event occurs that should trigger block building
|
|
WaitForEvent(context.Context) (Message, error)
|
|
}
|
|
|
|
// StateSyncMode defines state sync modes
|
|
type StateSyncMode uint8
|
|
|
|
const (
|
|
StateSyncSkipped StateSyncMode = iota
|
|
StateSyncStatic
|
|
StateSyncDynamic
|
|
)
|
|
|
|
// StateSyncableVM defines a VM that supports state sync
|
|
type StateSyncableVM interface {
|
|
ChainVM
|
|
|
|
// StateSyncEnabled returns whether state sync is enabled
|
|
StateSyncEnabled(context.Context) (bool, error)
|
|
|
|
// GetOngoingSyncStateSummary returns the ongoing sync state summary
|
|
GetOngoingSyncStateSummary(context.Context) (StateSummary, error)
|
|
|
|
// GetLastStateSummary returns the last state summary
|
|
GetLastStateSummary(context.Context) (StateSummary, error)
|
|
|
|
// ParseStateSummary parses a state summary
|
|
ParseStateSummary(context.Context, []byte) (StateSummary, error)
|
|
|
|
// GetStateSummary gets a state summary by height
|
|
GetStateSummary(context.Context, uint64) (StateSummary, error)
|
|
}
|
|
|
|
// StateSummary represents a state summary
|
|
type StateSummary interface {
|
|
ID() ids.ID
|
|
Height() uint64
|
|
Bytes() []byte
|
|
Accept(context.Context) (StateSyncMode, error)
|
|
}
|
|
|
|
// BuildBlockWithContextVM extends ChainVM with context support
|
|
type BuildBlockWithContextVM interface {
|
|
ChainVM
|
|
BuildBlockWithContext(context.Context, *Context) (Block, error)
|
|
}
|
|
|
|
// Context provides context for building blocks
|
|
type Context struct {
|
|
PChainHeight uint64
|
|
}
|
|
|
|
// WithVerifyContext provides verify context support
|
|
type WithVerifyContext interface {
|
|
// VerifyWithContext verifies with context
|
|
VerifyWithContext(context.Context, *Context) error
|
|
|
|
// ShouldVerifyWithContext returns whether to verify with context
|
|
ShouldVerifyWithContext(context.Context) (bool, error)
|
|
}
|
|
|
|
// GetAncestors retrieves ancestors of a block up to a maximum count
|
|
func GetAncestors(
|
|
ctx context.Context,
|
|
vm ChainVM,
|
|
blkID ids.ID,
|
|
maxBlocks int,
|
|
maxBlocksSize int,
|
|
maxBlocksRetrievalTime time.Duration,
|
|
) ([][]byte, error) {
|
|
if maxBlocks <= 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
startTime := time.Now()
|
|
ancestors := make([][]byte, 0, maxBlocks)
|
|
totalSize := 0
|
|
|
|
for len(ancestors) < maxBlocks && totalSize < maxBlocksSize {
|
|
if time.Since(startTime) > maxBlocksRetrievalTime {
|
|
break
|
|
}
|
|
|
|
blk, err := vm.GetBlock(ctx, blkID)
|
|
if err != nil {
|
|
break
|
|
}
|
|
|
|
blkBytes := blk.Bytes()
|
|
totalSize += len(blkBytes)
|
|
if totalSize > maxBlocksSize {
|
|
break
|
|
}
|
|
|
|
ancestors = append(ancestors, blkBytes)
|
|
blkID = blk.ParentID()
|
|
}
|
|
|
|
return ancestors, nil
|
|
}
|