api: initial v1.0.0

This commit is contained in:
Zach Kelling
2026-01-16 11:52:14 -08:00
commit 49e9dc92e8
14 changed files with 1107 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package admin
import "context"
// Service defines the admin API contract.
type Service interface {
StartCPUProfiler(ctx context.Context) (*EmptyReply, error)
StopCPUProfiler(ctx context.Context) (*EmptyReply, error)
MemoryProfile(ctx context.Context) (*EmptyReply, error)
LockProfile(ctx context.Context) (*EmptyReply, error)
Alias(ctx context.Context, args *AliasArgs) (*EmptyReply, error)
AliasChain(ctx context.Context, args *AliasChainArgs) (*EmptyReply, error)
GetChainAliases(ctx context.Context, args *GetChainAliasesArgs) (*GetChainAliasesReply, error)
Stacktrace(ctx context.Context) (*EmptyReply, error)
SetLoggerLevel(ctx context.Context, args *SetLoggerLevelArgs) (*EmptyReply, error)
GetLoggerLevel(ctx context.Context, args *GetLoggerLevelArgs) (*LoggerLevelReply, error)
GetConfig(ctx context.Context) (any, error)
LoadVMs(ctx context.Context) (*LoadVMsReply, error)
DbGet(ctx context.Context, args *DBGetArgs) (*DBGetReply, error)
ListVMs(ctx context.Context) (*ListVMsReply, error)
SetTrackedChains(ctx context.Context, args *SetTrackedChainsArgs) (*SetTrackedChainsReply, error)
GetTrackedChains(ctx context.Context) (*GetTrackedChainsReply, error)
}
+117
View File
@@ -0,0 +1,117 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package admin
import (
"github.com/luxfi/ids"
"github.com/luxfi/api/types"
)
// AliasArgs are the arguments for calling Alias.
type AliasArgs struct {
Endpoint string `json:"endpoint"`
Alias string `json:"alias"`
}
// AliasChainArgs are the arguments for calling AliasChain.
type AliasChainArgs struct {
Chain string `json:"chain"`
Alias string `json:"alias"`
}
// GetChainAliasesArgs are the arguments for calling GetChainAliases.
type GetChainAliasesArgs struct {
Chain string `json:"chain"`
}
// GetChainAliasesReply are the aliases of the given chain.
type GetChainAliasesReply struct {
Aliases []string `json:"aliases"`
}
// SetLoggerLevelArgs are the arguments for setting a logger's levels.
type SetLoggerLevelArgs struct {
LoggerName string `json:"loggerName"`
LogLevel string `json:"logLevel"`
DisplayLevel string `json:"displayLevel"`
}
// LogAndDisplayLevels pairs log and display levels.
type LogAndDisplayLevels struct {
LogLevel string `json:"logLevel"`
DisplayLevel string `json:"displayLevel"`
}
// LoggerLevelReply are the levels of the loggers.
type LoggerLevelReply struct {
LoggerLevels map[string]LogAndDisplayLevels `json:"loggerLevels"`
}
// GetLoggerLevelArgs are the arguments for getting logger levels.
type GetLoggerLevelArgs struct {
LoggerName string `json:"loggerName"`
}
// LoadVMsReply contains the response for LoadVMs.
type LoadVMsReply struct {
NewVMs map[ids.ID][]string `json:"newVMs"`
FailedVMs map[ids.ID]string `json:"failedVMs"`
ChainsRetried int `json:"chainsRetried"`
}
// DBGetArgs are the arguments for DBGet.
type DBGetArgs struct {
Key string `json:"key"`
}
// DBGetReply is the reply for DBGet.
type DBGetReply struct {
Value string `json:"value"`
}
// VMInfo contains information about a registered VM.
type VMInfo struct {
ID string `json:"id"`
Aliases []string `json:"aliases"`
Path string `json:"path,omitempty"`
}
// ListVMsReply contains the response for ListVMs.
type ListVMsReply struct {
VMs map[string]VMInfo `json:"vms"`
}
// SnapshotArgs are the arguments for Snapshot.
type SnapshotArgs struct {
Path string `json:"path"`
Since uint64 `json:"since"`
}
// SnapshotReply is the response for Snapshot.
type SnapshotReply struct {
Version uint64 `json:"version"`
}
// LoadArgs are the arguments for Load.
type LoadArgs struct {
Path string `json:"path"`
}
// SetTrackedChainsArgs are the arguments for SetTrackedChains.
type SetTrackedChainsArgs struct {
Chains []string `json:"chains"`
}
// SetTrackedChainsReply is the response for SetTrackedChains.
type SetTrackedChainsReply struct {
TrackedChains []string `json:"trackedChains"`
}
// GetTrackedChainsReply is the response for GetTrackedChains.
type GetTrackedChainsReply struct {
TrackedChains []string `json:"trackedChains"`
}
// EmptyReply is an alias to common empty reply.
type EmptyReply = types.EmptyReply
+13
View File
@@ -0,0 +1,13 @@
module github.com/luxfi/api
go 1.25.5
require github.com/luxfi/ids v1.2.9
require (
github.com/luxfi/crypto v1.17.38 // indirect
github.com/luxfi/mock v0.1.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
go.uber.org/mock v0.6.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
)
+20
View File
@@ -0,0 +1,20 @@
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/luxfi/crypto v1.17.38 h1:PZ52opsm3ECvyKsR2pLSsKONCey+FqpN0ZEwu+KMdO4=
github.com/luxfi/crypto v1.17.38/go.mod h1:G2t1GQvPsrwnzwyVEj0LQDuX2AWZVI5kEAPyVeicc5o=
github.com/luxfi/ids v1.2.9 h1:+yjdhXW99drnd2Zlp1u/p8k3G23W3/1btJQ4ogHawUI=
github.com/luxfi/ids v1.2.9/go.mod h1:khJOEdOPxd22yn0jcVrnbX1ADa0GHn5Y74gvCzN5BYc=
github.com/luxfi/mock v0.1.0 h1:IwElfNu+T9sXvzFX6tudPDx1vqPuACRSRdxpD5lxW+o=
github.com/luxfi/mock v0.1.0/go.mod h1:izF+9K0gGzFC9zERn6Po37v46eLdPB+EIsDjL3GLk+U=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+13
View File
@@ -0,0 +1,13 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package health
import "context"
// Service defines the health API contract.
type Service interface {
Readiness(ctx context.Context, args *APIArgs) (*APIReply, error)
Health(ctx context.Context, args *APIArgs) (*APIReply, error)
Liveness(ctx context.Context, args *APIArgs) (*APIReply, error)
}
+27
View File
@@ -0,0 +1,27 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package health
import "time"
// APIReply is the response for Readiness, Health, and Liveness.
type APIReply struct {
Checks map[string]Result `json:"checks"`
Healthy bool `json:"healthy"`
}
// APIArgs is the arguments for Readiness, Health, and Liveness.
type APIArgs struct {
Tags []string `json:"tags"`
}
// Result describes a health check result.
type Result struct {
Details interface{} `json:"message,omitempty"`
Error *string `json:"error,omitempty"`
Timestamp time.Time `json:"timestamp,omitempty"`
Duration time.Duration `json:"duration"`
ContiguousFailures int64 `json:"contiguousFailures,omitempty"`
TimeOfFirstFailure *time.Time `json:"timeOfFirstFailure,omitempty"`
}
+39
View File
@@ -0,0 +1,39 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package info
import "context"
const (
MethodGetNodeVersion = "info.getNodeVersion"
MethodGetNodeID = "info.getNodeID"
MethodGetNodeIP = "info.getNodeIP"
MethodGetNetworkID = "info.getNetworkID"
MethodGetNetworkName = "info.getNetworkName"
MethodGetBlockchainID = "info.getBlockchainID"
MethodPeers = "info.peers"
MethodIsBootstrapped = "info.isBootstrapped"
MethodUpgrades = "info.upgrades"
MethodUptime = "info.uptime"
MethodLps = "info.lps"
MethodGetTxFee = "info.getTxFee"
MethodGetVMs = "info.getVMs"
)
// Service defines the info API contract.
type Service interface {
GetNodeVersion(ctx context.Context) (*GetNodeVersionReply, error)
GetNodeID(ctx context.Context) (*GetNodeIDReply, error)
GetNodeIP(ctx context.Context) (*GetNodeIPReply, error)
GetNetworkID(ctx context.Context) (*GetNetworkIDReply, error)
GetNetworkName(ctx context.Context) (*GetNetworkNameReply, error)
GetBlockchainID(ctx context.Context, args *GetBlockchainIDArgs) (*GetBlockchainIDReply, error)
Peers(ctx context.Context, args *PeersArgs) (*PeersReply, error)
IsBootstrapped(ctx context.Context, args *IsBootstrappedArgs) (*IsBootstrappedResponse, error)
Upgrades(ctx context.Context) (*map[string]any, error)
Uptime(ctx context.Context) (*UptimeResponse, error)
Lps(ctx context.Context) (*LPsReply, error)
GetTxFee(ctx context.Context) (*GetTxFeeResponse, error)
GetVMs(ctx context.Context) (*GetVMsReply, error)
}
+124
View File
@@ -0,0 +1,124 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package info
import (
"net/netip"
"github.com/luxfi/api/types"
"github.com/luxfi/ids"
"github.com/luxfi/math/set"
"github.com/luxfi/p2p/peer"
)
// ProofOfPossession is a JSON-friendly representation of a BLS PoP.
type ProofOfPossession struct {
PublicKey string `json:"publicKey"`
ProofOfPossession string `json:"proofOfPossession"`
}
// GetNodeVersionReply are the results from calling GetNodeVersion.
type GetNodeVersionReply struct {
Version string `json:"version"`
DatabaseVersion string `json:"databaseVersion"`
RPCProtocolVersion types.Uint32 `json:"rpcProtocolVersion"`
GitCommit string `json:"gitCommit"`
VMVersions map[string]string `json:"vmVersions"`
}
// GetNodeIDReply are the results from calling GetNodeID.
type GetNodeIDReply struct {
NodeID ids.NodeID `json:"nodeID"`
NodePOP *ProofOfPossession `json:"nodePOP"`
}
// GetNetworkIDReply are the results from calling GetNetworkID.
type GetNetworkIDReply struct {
NetworkID types.Uint32 `json:"networkID"`
}
// GetNodeIPReply are the results from calling GetNodeIP.
type GetNodeIPReply struct {
IP netip.AddrPort `json:"ip"`
}
// GetNetworkNameReply is the result from calling GetNetworkName.
type GetNetworkNameReply struct {
NetworkName string `json:"networkName"`
}
// GetBlockchainIDArgs are the arguments for calling GetBlockchainID.
type GetBlockchainIDArgs struct {
Alias string `json:"alias"`
}
// GetBlockchainIDReply are the results from calling GetBlockchainID.
type GetBlockchainIDReply struct {
BlockchainID ids.ID `json:"blockchainID"`
}
// PeersArgs are the arguments for calling Peers.
type PeersArgs struct {
NodeIDs []ids.NodeID `json:"nodeIDs"`
}
// Peer is information about a peer in the network.
type Peer struct {
peer.Info
Benched []string `json:"benched"`
}
// PeersReply are the results from calling Peers.
type PeersReply struct {
NumPeers types.Uint64 `json:"numPeers"`
Peers []Peer `json:"peers"`
}
// IsBootstrappedArgs are the arguments for calling IsBootstrapped.
type IsBootstrappedArgs struct {
Chain string `json:"chain"`
}
// IsBootstrappedResponse are the results from calling IsBootstrapped.
type IsBootstrappedResponse struct {
IsBootstrapped bool `json:"isBootstrapped"`
}
// UptimeResponse are the results from calling Uptime.
type UptimeResponse struct {
RewardingStakePercentage types.Float64 `json:"rewardingStakePercentage"`
WeightedAveragePercentage types.Float64 `json:"weightedAveragePercentage"`
}
// LP is information about an LP proposal.
type LP struct {
SupportWeight types.Uint64 `json:"supportWeight"`
Supporters set.Set[ids.NodeID] `json:"supporters"`
ObjectWeight types.Uint64 `json:"objectWeight"`
Objectors set.Set[ids.NodeID] `json:"objectors"`
AbstainWeight types.Uint64 `json:"abstainWeight"`
}
// LPsReply are the results from calling LPs.
type LPsReply struct {
LPs map[uint32]*LP `json:"lps"`
}
// GetTxFeeResponse are the results from calling GetTxFee.
type GetTxFeeResponse struct {
TxFee types.Uint64 `json:"txFee"`
CreateAssetTxFee types.Uint64 `json:"createAssetTxFee"`
CreateNetworkTxFee types.Uint64 `json:"createNetworkTxFee"`
TransformChainTxFee types.Uint64 `json:"transformChainTxFee"`
CreateChainTxFee types.Uint64 `json:"createChainTxFee"`
AddNetworkValidatorFee types.Uint64 `json:"addNetworkValidatorFee"`
AddNetworkDelegatorFee types.Uint64 `json:"addNetworkDelegatorFee"`
}
// GetVMsReply contains the response metadata for GetVMs.
type GetVMsReply struct {
VMs map[ids.ID][]string `json:"vms"`
Fxs map[ids.ID]string `json:"fxs"`
}
+329
View File
@@ -0,0 +1,329 @@
// 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 module is the bottom of the dependency graph - no imports from
// node, evm, netrunner, or cli are allowed.
//
// Use stdlib context.Context for cancellation/deadlines.
// Use *Runtime for chain wiring (IDs, logging, validators, etc.)
package runtime
import (
"context"
"sync"
"time"
"github.com/luxfi/ids"
)
// 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"`
// XAssetID is the primary asset ID (X-chain native, typically LUX)
XAssetID ids.ID `json:"xAssetID"`
// 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
// Concrete type depends on context (node vs plugin)
ValidatorState interface{}
// Keystore provides key management
Keystore interface{}
// Metrics provides metrics tracking
Metrics interface{}
// Log provides logging
Log interface{}
// SharedMemory provides cross-chain atomic operations
SharedMemory interface{}
// BCLookup provides blockchain alias lookup
// Use AsBCLookup() method to get typed interface
BCLookup interface{}
// WarpSigner provides BLS signing for Warp messages
WarpSigner interface{}
// NetworkUpgrades contains upgrade activation times
NetworkUpgrades interface{}
// 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{})
}
// ValidatorState provides validator information
type ValidatorState interface {
GetChainID(ids.ID) (ids.ID, error)
GetNetworkID(ids.ID) (ids.ID, error)
GetValidatorSet(uint64, ids.ID) (map[ids.NodeID]uint64, error)
GetCurrentHeight(context.Context) (uint64, error)
GetMinimumHeight(context.Context) (uint64, error)
}
// GetValidatorOutput contains validator information
type GetValidatorOutput struct {
NodeID ids.NodeID
PublicKey []byte
Weight uint64
}
// Metrics provides metrics tracking
type Metrics interface {
Register(namespace string, registerer interface{}) error
}
// SharedMemory provides cross-chain shared memory
type SharedMemory interface {
Get(peerChainID ids.ID, keys [][]byte) (values [][]byte, err error)
Indexed(
peerChainID ids.ID,
traits [][]byte,
startTrait, startKey []byte,
limit int,
) (values [][]byte, lastTrait, lastKey []byte, err error)
Apply(requests map[ids.ID]*AtomicRequests, batch interface{}) error
}
// AtomicRequests contains atomic operations for a chain
type AtomicRequests struct {
RemoveRequests [][]byte
PutRequests []*AtomicPutRequest
}
// AtomicPutRequest represents a put operation in shared memory
type AtomicPutRequest struct {
Key []byte
Value []byte
Traits [][]byte
}
// WarpSigner provides BLS signing for Warp messages
type WarpSigner interface {
Sign(msg interface{}) ([]byte, error)
PublicKey() []byte
NodeID() ids.NodeID
}
// NetworkUpgrades contains network upgrade activation times
type NetworkUpgrades interface {
IsApricotPhase3Activated(timestamp time.Time) bool
IsApricotPhase5Activated(timestamp time.Time) bool
IsBanffActivated(timestamp time.Time) bool
IsCortinaActivated(timestamp time.Time) bool
IsDurangoActivated(timestamp time.Time) bool
IsEtnaActivated(timestamp time.Time) bool
}
// 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{}
GetNetworkUpgrades() 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) ValidatorState {
if rt := FromContext(ctx); rt != nil {
if vs, ok := rt.ValidatorState.(ValidatorState); ok {
return vs
}
}
return nil
}
// GetWarpSigner gets the warp signer from context
func GetWarpSigner(ctx context.Context) interface{} {
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
XAssetID 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.XAssetID = id.XAssetID
rt.ChainDataDir = id.ChainDataDir
return WithRuntime(ctx, rt)
}
// WithValidatorState adds validator state to the context
func WithValidatorState(ctx context.Context, vs interface{}) 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 if available, or nil.
// Use this to access BCLookup methods with proper type safety.
func (rt *Runtime) AsBCLookup() BCLookup {
if bc, ok := rt.BCLookup.(BCLookup); ok {
return bc
}
return nil
}
// AsLogger returns the Log field as a Logger interface if available.
func (rt *Runtime) AsLogger() Logger {
if l, ok := rt.Log.(Logger); ok {
return l
}
return nil
}
// AsValidatorState returns the ValidatorState interface if available.
func (rt *Runtime) AsValidatorState() ValidatorState {
if vs, ok := rt.ValidatorState.(ValidatorState); ok {
return vs
}
return nil
}
+133
View File
@@ -0,0 +1,133 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package types
import (
"encoding/json"
"github.com/luxfi/formatting"
"github.com/luxfi/ids"
)
// EmptyReply indicates that an api doesn't have a response to return.
type EmptyReply struct{}
// HTTPHeaderRoute is the canonical header used to route API requests.
const HTTPHeaderRoute = "Lux-Api-Route"
// UserPass contains a username and password.
type UserPass struct {
Username string `json:"username"`
Password string `json:"password"`
}
// JSONTxID contains the ID of a transaction.
type JSONTxID struct {
TxID ids.ID `json:"txID"`
}
// JSONAddress contains an address.
type JSONAddress struct {
Address string `json:"address"`
}
// JSONAddresses contains a list of address.
type JSONAddresses struct {
Addresses []string `json:"addresses"`
}
// GetBlockArgs is the parameters supplied to the GetBlock API.
type GetBlockArgs struct {
BlockID ids.ID `json:"blockID"`
Encoding formatting.Encoding `json:"encoding"`
}
// GetBlockByHeightArgs is the parameters supplied to the GetBlockByHeight API.
type GetBlockByHeightArgs struct {
Height Uint64 `json:"height"`
Encoding formatting.Encoding `json:"encoding"`
}
// GetBlockResponse is the response object for the GetBlock API.
type GetBlockResponse struct {
Block json.RawMessage `json:"block"`
// If GetBlockResponse.Encoding is formatting.Hex, GetBlockResponse.Block is
// the string representation of the block under hex encoding.
// If GetBlockResponse.Encoding is formatting.JSON, GetBlockResponse.Block
// is the actual block returned as a JSON.
Encoding formatting.Encoding `json:"encoding"`
}
type GetHeightResponse struct {
Height Uint64 `json:"height"`
}
// FormattedBlock defines a JSON formatted struct containing a block in Hex
// format.
type FormattedBlock struct {
Block string `json:"block"`
Encoding formatting.Encoding `json:"encoding"`
}
type GetTxArgs struct {
TxID ids.ID `json:"txID"`
Encoding formatting.Encoding `json:"encoding"`
}
// GetTxReply defines an object containing a single [Tx] object along with Encoding.
type GetTxReply struct {
// If [GetTxArgs.Encoding] is [Hex], [Tx] is the string representation of
// the tx under hex encoding.
// If [GetTxArgs.Encoding] is [JSON], [Tx] is the actual tx, which will be
// returned as JSON to the caller.
Tx json.RawMessage `json:"tx"`
Encoding formatting.Encoding `json:"encoding"`
}
// FormattedTx defines a JSON formatted struct containing a Tx as a string.
type FormattedTx struct {
Tx string `json:"tx"`
Encoding formatting.Encoding `json:"encoding"`
}
// Index is an address and an associated UTXO.
// Marks a starting or stopping point when fetching UTXOs. Used for pagination.
type Index struct {
Address string `json:"address"` // The address as a string
UTXO string `json:"utxo"` // The UTXO ID as a string
}
// GetUTXOsArgs are arguments for passing into GetUTXOs.
// Gets the UTXOs that reference at least one address in [Addresses].
// Returns at most [limit] addresses.
// If specified, [SourceChain] is the chain where the atomic UTXOs were exported from. If empty,
// or the Chain ID of this VM is specified, then GetUTXOs fetches the native UTXOs.
// If [limit] == 0 or > [maxUTXOsToFetch], fetches up to [maxUTXOsToFetch].
// [StartIndex] defines where to start fetching UTXOs (for pagination.)
// UTXOs fetched are from addresses equal to or greater than [StartIndex.Address]
// For address [StartIndex.Address], only UTXOs with IDs greater than [StartIndex.UTXO] will be returned.
// If [StartIndex] is omitted, gets all UTXOs.
// If GetUTXOs is called multiple times, with our without [StartIndex], it is not guaranteed
// that returned UTXOs are unique. That is, the same UTXO may appear in the response of multiple calls.
type GetUTXOsArgs struct {
Addresses []string `json:"addresses"`
SourceChain string `json:"sourceChain"`
Limit Uint32 `json:"limit"`
StartIndex Index `json:"startIndex"`
Encoding formatting.Encoding `json:"encoding"`
}
// GetUTXOsReply defines the GetUTXOs replies returned from the API.
type GetUTXOsReply struct {
// Number of UTXOs returned.
NumFetched Uint64 `json:"numFetched"`
// The UTXOs.
UTXOs []string `json:"utxos"`
// The last UTXO that was returned, and the address it corresponds to.
// Used for pagination. To get the rest of the UTXOs, call GetUTXOs
// again and set [StartIndex] to this value.
EndIndex Index `json:"endIndex"`
// Encoding specifies the encoding format the UTXOs are returned in.
Encoding formatting.Encoding `json:"encoding"`
}
+71
View File
@@ -0,0 +1,71 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package types
import "strconv"
const Null = "null"
type Uint32 uint32
func (u Uint32) MarshalJSON() ([]byte, error) {
return []byte(`"` + strconv.FormatUint(uint64(u), 10) + `"`), nil
}
func (u *Uint32) UnmarshalJSON(b []byte) error {
str := string(b)
if str == Null {
return nil
}
if len(str) >= 2 {
if lastIndex := len(str) - 1; str[0] == '"' && str[lastIndex] == '"' {
str = str[1:lastIndex]
}
}
val, err := strconv.ParseUint(str, 10, 32)
*u = Uint32(val)
return err
}
type Uint64 uint64
func (u Uint64) MarshalJSON() ([]byte, error) {
return []byte(`"` + strconv.FormatUint(uint64(u), 10) + `"`), nil
}
func (u *Uint64) UnmarshalJSON(b []byte) error {
str := string(b)
if str == Null {
return nil
}
if len(str) >= 2 {
if lastIndex := len(str) - 1; str[0] == '"' && str[lastIndex] == '"' {
str = str[1:lastIndex]
}
}
val, err := strconv.ParseUint(str, 10, 64)
*u = Uint64(val)
return err
}
type Float64 float64
func (f Float64) MarshalJSON() ([]byte, error) {
return []byte(`"` + strconv.FormatFloat(float64(f), 'f', 4, 64) + `"`), nil
}
func (f *Float64) UnmarshalJSON(b []byte) error {
str := string(b)
if str == Null {
return nil
}
if len(str) >= 2 {
if lastIndex := len(str) - 1; str[0] == '"' && str[lastIndex] == '"' {
str = str[1:lastIndex]
}
}
val, err := strconv.ParseFloat(str, 64)
*f = Float64(val)
return err
}
+150
View File
@@ -0,0 +1,150 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package api
import (
"context"
"net/http"
"time"
"github.com/luxfi/consensus/runtime"
"github.com/luxfi/ids"
)
// VM is the minimal interface that all VMs must implement.
// This is the execution boundary between consensus and VM logic.
type VM interface {
// Initialize is called when the VM is first created.
// rt contains chain wiring (IDs, logger, db, etc.)
// ctx is used only for this initialization call's cancellation.
Initialize(
ctx context.Context,
rt *runtime.Runtime,
dbManager interface{}, // database.Manager
genesisBytes []byte,
upgradeBytes []byte,
configBytes []byte,
toEngine chan<- Message,
fxs []*Fx,
appSender AppSender,
) error
// SetState is called to notify the VM of its execution state
SetState(ctx context.Context, state State) error
// Shutdown is called when the VM should stop
Shutdown(ctx context.Context) error
// Version returns the VM's version string
Version(ctx context.Context) (string, error)
// CreateHandlers returns HTTP handlers for this VM's API
CreateHandlers(ctx context.Context) (map[string]http.Handler, error)
}
// ChainVM is an optional interface for block-based VMs
type ChainVM interface {
VM
// BuildBlock builds a new block
BuildBlock(ctx context.Context) (Block, error)
// ParseBlock parses a block from bytes
ParseBlock(ctx context.Context, blockBytes []byte) (Block, error)
// GetBlock returns a block by ID
GetBlock(ctx context.Context, blkID ids.ID) (Block, error)
// SetPreference sets the preferred block
SetPreference(ctx context.Context, blkID ids.ID) error
// LastAccepted returns the last accepted block ID
LastAccepted(ctx context.Context) (ids.ID, error)
}
// Block represents a block in the blockchain
type Block interface {
// ID returns the block's unique identifier
ID() ids.ID
// Parent returns the parent block's ID
Parent() ids.ID
// Height returns the block's height
Height() uint64
// Timestamp returns the block's timestamp
Timestamp() time.Time
// Bytes returns the block's serialized form
Bytes() []byte
// Verify verifies the block is valid
Verify(ctx context.Context) error
// Accept marks the block as accepted
Accept(ctx context.Context) error
// Reject marks the block as rejected
Reject(ctx context.Context) error
// Status returns the block's status
Status() Status
}
// Status represents a block's status
type Status uint32
const (
StatusUnknown Status = iota
StatusProcessing
StatusRejected
StatusAccepted
)
// State represents the VM's execution state
type State uint8
const (
StateBootstrapping State = iota
StateNormalOp
)
// Message is sent from VM to consensus engine
type Message struct {
Type MessageType
}
// MessageType identifies the type of message
type MessageType uint8
const (
MessagePendingTxs MessageType = iota
MessageStateSyncDone
)
// Fx represents a feature extension
type Fx struct {
ID ids.ID
Fx interface{}
}
// AppSender sends application-level messages
type AppSender interface {
SendAppRequest(ctx context.Context, nodeIDs []ids.NodeID, requestID uint32, request []byte) error
SendAppResponse(ctx context.Context, nodeID ids.NodeID, requestID uint32, response []byte) error
SendAppError(ctx context.Context, nodeID ids.NodeID, requestID uint32, errorCode int32, errorMessage string) error
SendAppGossip(ctx context.Context, config SendConfig, msg []byte) error
SendAppGossipSpecific(ctx context.Context, nodeIDs []ids.NodeID, msg []byte) error
SendCrossChainAppRequest(ctx context.Context, chainID ids.ID, requestID uint32, msg []byte) error
SendCrossChainAppResponse(ctx context.Context, chainID ids.ID, requestID uint32, msg []byte) error
SendCrossChainAppError(ctx context.Context, chainID ids.ID, requestID uint32, errorCode int32, errorMessage string) error
}
// SendConfig configures gossip sending behavior
type SendConfig struct {
Validators int
NonValidators int
Peers int
}
+13
View File
@@ -0,0 +1,13 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package warp
import "context"
// Service defines the warp IPC API contract.
type Service interface {
PublishBlockchain(ctx context.Context, args *PublishBlockchainArgs) (*PublishBlockchainReply, error)
UnpublishBlockchain(ctx context.Context, args *UnpublishBlockchainArgs) (*EmptyReply, error)
GetPublishedBlockchains(ctx context.Context) (*GetPublishedBlockchainsReply, error)
}
+28
View File
@@ -0,0 +1,28 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package warp
import (
"github.com/luxfi/api/types"
"github.com/luxfi/ids"
)
type PublishBlockchainArgs struct {
BlockchainID string `json:"blockchainID"`
}
type PublishBlockchainReply struct {
ConsensusURL string `json:"consensusURL"`
DecisionsURL string `json:"decisionsURL"`
}
type UnpublishBlockchainArgs struct {
BlockchainID string `json:"blockchainID"`
}
type GetPublishedBlockchainsReply struct {
Chains []ids.ID `json:"chains"`
}
type EmptyReply = types.EmptyReply