Files

298 lines
8.1 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// Package runtime provides chain wiring and runtime dependencies for VMs.
// This package is part of the consensus module and provides the Runtime struct
// that VMs use for chain configuration, logging, validators, etc.
//
// Use stdlib context.Context for cancellation/deadlines.
// Use *Runtime for chain wiring (IDs, logging, validators, etc.)
package runtime
import (
"context"
"sync"
"time"
validators "github.com/luxfi/consensus/validator"
"github.com/luxfi/database"
"github.com/luxfi/ids"
"github.com/luxfi/metric"
"github.com/luxfi/warp"
)
// Element represents an atomic operation element.
// This mirrors vm/chains/atomic.Element to avoid import cycles.
type Element struct {
Key []byte `serialize:"true"`
Value []byte `serialize:"true"`
Traits [][]byte `serialize:"true"`
}
// Requests represents atomic operation requests.
// This mirrors vm/chains/atomic.Requests to avoid import cycles.
type Requests struct {
RemoveRequests [][]byte `serialize:"true"`
PutRequests []*Element `serialize:"true"`
}
// ValidatorState is an alias to validators.State for convenience
type ValidatorState = validators.State
// Runtime provides chain wiring and runtime dependencies for VMs.
// This is separate from stdlib context.Context which handles cancellation/deadlines.
//
// Use context.Context for:
// - Cancellation signals
// - Request deadlines
// - Request-scoped values (sparingly)
//
// Use *Runtime for:
// - Chain IDs, network IDs
// - Node identity (NodeID, PublicKey)
// - Logging, metrics
// - Database handles
// - Validator state
// - Upgrade configurations
type Runtime struct {
// NetworkID is the numeric network identifier (1=mainnet, 2=testnet)
NetworkID uint32 `json:"networkID"`
// ChainID identifies the specific chain within the network
ChainID ids.ID `json:"chainID"`
// NodeID identifies this node
NodeID ids.NodeID `json:"nodeID"`
// PublicKey is the node's BLS public key bytes
PublicKey []byte `json:"publicKey"`
// XChainID is the X-Chain identifier
XChainID ids.ID `json:"xChainID"`
// CChainID is the C-Chain identifier
CChainID ids.ID `json:"cChainID"`
// UTXOAssetID is the primary asset ID (X-chain native, typically LUX)
UTXOAssetID ids.ID `json:"utxoAssetID"`
// ChainDataDir is the directory for chain-specific data
ChainDataDir string `json:"chainDataDir"`
// StartTime is when the node started
StartTime time.Time `json:"startTime"`
// ValidatorState provides validator information (uses consensus/validators.State)
ValidatorState validators.State
// Keystore provides key management
Keystore Keystore
// Metrics provides metrics tracking
Metrics Metrics
// Log provides logging
Log Logger
// SharedMemory provides cross-chain atomic operations
SharedMemory SharedMemory
// BCLookup provides blockchain alias lookup
BCLookup BCLookup
// WarpSigner provides BLS signing for Warp messages
WarpSigner WarpSigner
// Lock for thread-safe access to runtime fields
Lock sync.RWMutex
}
// BCLookup provides blockchain alias lookup
type BCLookup interface {
Lookup(alias string) (ids.ID, error)
PrimaryAlias(id ids.ID) (string, error)
Aliases(id ids.ID) ([]string, error)
}
// Keystore provides key management
type Keystore interface {
GetDatabase(username, password string) (interface{}, error)
NewAccount(username, password string) error
}
// Logger provides logging functionality
type Logger interface {
Debug(msg string, fields ...interface{})
Info(msg string, fields ...interface{})
Warn(msg string, fields ...interface{})
Error(msg string, fields ...interface{})
Fatal(msg string, fields ...interface{})
}
// Metrics provides metrics tracking.
// Matches api/metrics.MultiGatherer interface.
type Metrics interface {
metric.Gatherer
Register(name string, gatherer metric.Gatherer) error
}
// SharedMemory is the canonical interface for cross-chain atomic operations.
// This interface mirrors vm/chains/atomic.SharedMemory to avoid import cycles.
type SharedMemory interface {
// Get fetches values corresponding to keys that have been sent from peerChainID
Get(peerChainID ids.ID, keys [][]byte) (values [][]byte, err error)
// Indexed returns a paginated result of values with given traits from peerChainID
Indexed(
peerChainID ids.ID,
traits [][]byte,
startTrait,
startKey []byte,
limit int,
) (values [][]byte, lastTrait, lastKey []byte, err error)
// Apply atomically applies requests to chainID keys in the map with batches
Apply(requests map[ids.ID]*Requests, batches ...database.Batch) error
}
// WarpSigner provides BLS signing for Warp messages.
// Matches warp.Signer interface exactly.
type WarpSigner = warp.Signer
// VMContext is an interface that VM contexts must implement
// This allows different context types (node, plugin, etc.) to be used interchangeably
type VMContext interface {
GetNetworkID() uint32
GetChainID() ids.ID
GetNodeID() ids.NodeID
GetPublicKey() []byte
GetXChainID() ids.ID
GetCChainID() ids.ID
GetAssetID() ids.ID
GetChainDataDir() string
GetLog() interface{}
GetSharedMemory() interface{}
GetMetrics() interface{}
GetValidatorState() interface{}
GetBCLookup() interface{}
GetWarpSigner() interface{}
}
// runtimeKeyType is the context key type for storing Runtime
type runtimeKeyType struct{}
var runtimeKey = runtimeKeyType{}
// WithRuntime adds Runtime to a context.Context
func WithRuntime(ctx context.Context, rt *Runtime) context.Context {
return context.WithValue(ctx, runtimeKey, rt)
}
// FromContext extracts Runtime from a context.Context
func FromContext(ctx context.Context) *Runtime {
if rt, ok := ctx.Value(runtimeKey).(*Runtime); ok {
return rt
}
return nil
}
// GetChainID gets the chain ID from context
func GetChainID(ctx context.Context) ids.ID {
if rt := FromContext(ctx); rt != nil {
return rt.ChainID
}
return ids.Empty
}
// GetNetworkID gets the numeric network ID from context
func GetNetworkID(ctx context.Context) uint32 {
if rt := FromContext(ctx); rt != nil {
return rt.NetworkID
}
return 0
}
// GetNodeID gets the node ID from context
func GetNodeID(ctx context.Context) ids.NodeID {
if rt := FromContext(ctx); rt != nil {
return rt.NodeID
}
return ids.EmptyNodeID
}
// IsPrimaryNetwork checks if the network is the primary network
func IsPrimaryNetwork(ctx context.Context) bool {
if rt := FromContext(ctx); rt != nil {
return rt.NetworkID == 1
}
return false
}
// GetValidatorState gets the validator state from context
func GetValidatorState(ctx context.Context) validators.State {
if rt := FromContext(ctx); rt != nil {
return rt.ValidatorState
}
return nil
}
// GetWarpSigner gets the warp signer from context
func GetWarpSigner(ctx context.Context) WarpSigner {
if rt := FromContext(ctx); rt != nil {
return rt.WarpSigner
}
return nil
}
// IDs holds the IDs for runtime context
type IDs struct {
NetworkID uint32
ChainID ids.ID
NodeID ids.NodeID
PublicKey []byte
UTXOAssetID ids.ID
ChainDataDir string `json:"chainDataDir"`
}
// WithIDs adds IDs to the context via Runtime
func WithIDs(ctx context.Context, id IDs) context.Context {
rt := FromContext(ctx)
if rt == nil {
rt = &Runtime{}
}
rt.NetworkID = id.NetworkID
rt.ChainID = id.ChainID
rt.NodeID = id.NodeID
rt.PublicKey = id.PublicKey
rt.UTXOAssetID = id.UTXOAssetID
rt.ChainDataDir = id.ChainDataDir
return WithRuntime(ctx, rt)
}
// WithValidatorState adds validator state to the context
func WithValidatorState(ctx context.Context, vs validators.State) context.Context {
rt := FromContext(ctx)
if rt == nil {
rt = &Runtime{}
}
rt.ValidatorState = vs
return WithRuntime(ctx, rt)
}
// GetTimestamp returns the current timestamp
func GetTimestamp() int64 {
return time.Now().Unix()
}
// AsBCLookup returns the BCLookup interface for blockchain alias lookup.
// This method is used by VMs (particularly coreth) to resolve chain aliases.
func (r *Runtime) AsBCLookup() BCLookup {
if r == nil {
return nil
}
return r.BCLookup
}
// GetValidatorOutput is re-exported from validator package for convenience
type GetValidatorOutput = validators.GetValidatorOutput