// 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