mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
Thirty platformvm files migrated. Every codec.Manager / codec.Registry / linearcodec / wrappers / zapcodec reference inside vms/platformvm now flows through node/vms/pcodecs, completing wave 2D of the codec rip (#101). zero direct luxfi/codec imports remain anywhere in node/vms outside vms/pcodecs/{pcodecs.go,pcodecsmock/manager.go}. Codec construction sites (singletons preserved for external API compatibility — wallet, indexer, network — pcodecs is the construction layer only): platformvm/txs/codec.go — V0+V1 linearcodec + V2 zapcodec via pcodecs.NewLinearCodec / NewZAPCodec / NewDefaultManager / NewMaxInt32Manager helpers platformvm/block/codec.go — v1 + v0 read-only + GenesisCodec via pcodecs helpers platformvm/warp/codec.go — Codec via pcodecs.NewMaxIntManager platformvm/warp/message/codec.go — Codec via pcodecs.NewMaxIntManager platformvm/warp/payload/codec.go — Codec via pcodecs.NewManager platformvm/state/metadata_codec.go — MetadataCodec via pcodecs Production code typed through pcodecs: platformvm/txs/{tx,initial_state,operation}.go — codec.Manager → pcodecs.Manager platformvm/txs/fee/complexity.go — wrappers.{LongLen,IntLen,ShortLen, ByteLen} + codec.VersionSize → pcodecs.{LongLen,IntLen,ShortLen, ByteLen,VersionSize} platformvm/state/{state,codec_helpers,metadata_validator}.go — pcodecs.Manager / pcodecs.Registry / pcodecs.{VersionSize,LongLen,IntLen, BoolLen} platformvm/block/{parse,v0/block}.go — pcodecs.Manager + LinearCodec + Errs platformvm/metrics/metrics.go — wrappers.Errs → pcodecs.Errs platformvm/vm.go — codec.Registry / linearcodec.NewDefault → pcodecs.Registry / pcodecs.NewLinearCodec Tests: platformvm/block/codec_multiversion_test.go — codec.ErrUnknownVersion → pcodecs platformvm/state/{codec_helpers,metadata_validator, metadata_delegator,state_v0_codec}_test.go — codec sentinel errors → pcodecs; linearcodec.NewDefault / codec.NewDefaultManager → pcodecs helpers platformvm/txs/{fee/complexity,tx_fuzz}_test.go — pcodecs.VersionSize / NewLinearCodec / Packer platformvm/warp/{message,unsigned_message}_test.go — pcodecs.ErrUnknownVersion platformvm/warp/message/payload_test.go — pcodecs.ErrUnknownVersion platformvm/warp/payload/{addressed_call,hash,payload}_test.go — pcodecs.ErrUnknownVersion Build: go build ./vms/... Tests: go test ./vms/platformvm/... — all green. Pre-existing failures in vms/xvm (TestTxAcceptAfterParseTx, TestIssueImportTx, TestIssueNFT, TestIssueProperty, TestVerifyFxUsage) are unrelated to wave 2D — they fail on the baseline branch without any change to xvm. Independent fix. Wave 2D complete: - Components: 8 files migrated - Proposervm: 9 files migrated - EVM: 5 files migrated - XSVM: 2 files migrated - RPCchainvm: 1 file migrated - XVM: 18 files migrated - Platformvm: 30 files migrated -- Total: 73 files migrated to pcodecs. vms/pcodecs is the single canonical construction site.
872 lines
28 KiB
Go
872 lines
28 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package state
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/google/btree"
|
|
"github.com/luxfi/metric"
|
|
|
|
"github.com/luxfi/node/vms/pcodecs"
|
|
"github.com/luxfi/runtime"
|
|
validators "github.com/luxfi/validators"
|
|
"github.com/luxfi/validators/uptime"
|
|
"github.com/luxfi/constants"
|
|
"github.com/luxfi/container/maybe"
|
|
"github.com/luxfi/database"
|
|
"github.com/luxfi/database/linkeddb"
|
|
"github.com/luxfi/database/prefixdb"
|
|
"github.com/luxfi/database/versiondb"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/log"
|
|
"github.com/luxfi/node/cache"
|
|
"github.com/luxfi/node/cache/lru"
|
|
"github.com/luxfi/node/cache/metercacher"
|
|
"github.com/luxfi/node/upgrade"
|
|
"github.com/luxfi/node/vms/components/gas"
|
|
lux "github.com/luxfi/utxo"
|
|
"github.com/luxfi/node/vms/platformvm/block"
|
|
"github.com/luxfi/node/vms/platformvm/config"
|
|
"github.com/luxfi/node/vms/platformvm/fx"
|
|
"github.com/luxfi/node/vms/platformvm/metrics"
|
|
"github.com/luxfi/node/vms/platformvm/reward"
|
|
"github.com/luxfi/node/vms/platformvm/status"
|
|
"github.com/luxfi/node/vms/platformvm/txs"
|
|
|
|
// utxo.ParseUTXO factory registration — see
|
|
// vms/components/lux/utxo_parser.go init(). Required for
|
|
// utxoState.GetUTXO to decode wire bytes off disk.
|
|
_ "github.com/luxfi/node/vms/components/lux"
|
|
|
|
safemath "github.com/luxfi/math"
|
|
)
|
|
|
|
const (
|
|
defaultTreeDegree = 2
|
|
indexIterationLimit = 4096
|
|
indexIterationSleepMultiplier = 5
|
|
indexIterationSleepCap = 10 * time.Second
|
|
indexLogFrequency = 30 * time.Second
|
|
)
|
|
|
|
var (
|
|
_ State = (*state)(nil)
|
|
|
|
errIsNotNet = errors.New("is not a chain")
|
|
errMissingPrimaryNetworkValidator = errors.New("missing primary network validator")
|
|
|
|
BlockIDPrefix = []byte("blockID")
|
|
BlockPrefix = []byte("block")
|
|
ValidatorsPrefix = []byte("validators")
|
|
CurrentPrefix = []byte("current")
|
|
PendingPrefix = []byte("pending")
|
|
ValidatorPrefix = []byte("validator")
|
|
DelegatorPrefix = []byte("delegator")
|
|
NetValidatorPrefix = []byte("chainValidator")
|
|
NetDelegatorPrefix = []byte("chainDelegator")
|
|
ValidatorWeightDiffsPrefix = []byte("flatValidatorDiffs")
|
|
ValidatorPublicKeyDiffsPrefix = []byte("flatPublicKeyDiffs")
|
|
TxPrefix = []byte("tx")
|
|
RewardUTXOsPrefix = []byte("rewardUTXOs")
|
|
UTXOPrefix = []byte("utxo")
|
|
NetPrefix = []byte("chain")
|
|
NetOwnerPrefix = []byte("chainOwner")
|
|
NetToL1ConversionPrefix = []byte("chainToL1Conversion")
|
|
TransformedNetPrefix = []byte("transformedNet")
|
|
SupplyPrefix = []byte("supply")
|
|
ChainPrefix = []byte("chain")
|
|
ChainNamePrefix = []byte("chainName") // maps lowercase chain name -> chainID
|
|
ExpiryReplayProtectionPrefix = []byte("expiryReplayProtection")
|
|
L1Prefix = []byte("l1")
|
|
WeightsPrefix = []byte("weights")
|
|
ChainIDNodeIDPrefix = []byte("chainIDNodeID")
|
|
ActivePrefix = []byte("active")
|
|
InactivePrefix = []byte("inactive")
|
|
SingletonPrefix = []byte("singleton")
|
|
|
|
TimestampKey = []byte("timestamp")
|
|
FeeStateKey = []byte("fee state")
|
|
L1ValidatorExcessKey = []byte("l1Validator excess")
|
|
AccruedFeesKey = []byte("accrued fees")
|
|
CurrentSupplyKey = []byte("current supply")
|
|
LastAcceptedKey = []byte("last accepted")
|
|
HeightsIndexedKey = []byte("heights indexed")
|
|
InitializedKey = []byte("initialized")
|
|
BlocksReindexedKey = []byte("blocks reindexed.3")
|
|
|
|
emptyL1ValidatorCache = &cache.Empty[ids.ID, maybe.Maybe[L1Validator]]{}
|
|
)
|
|
|
|
// Chain collects all methods to manage the state of the chain for block
|
|
// execution.
|
|
type Chain interface {
|
|
Expiry
|
|
L1Validators
|
|
Stakers
|
|
L1Validators
|
|
lux.UTXOAdder
|
|
lux.UTXOGetter
|
|
lux.UTXODeleter
|
|
|
|
GetTimestamp() time.Time
|
|
SetTimestamp(tm time.Time)
|
|
|
|
GetFeeState() gas.State
|
|
SetFeeState(f gas.State)
|
|
|
|
GetL1ValidatorExcess() gas.Gas
|
|
SetL1ValidatorExcess(e gas.Gas)
|
|
|
|
GetAccruedFees() uint64
|
|
SetAccruedFees(f uint64)
|
|
|
|
GetCurrentSupply(chainID ids.ID) (uint64, error)
|
|
SetCurrentSupply(chainID ids.ID, cs uint64)
|
|
|
|
AddRewardUTXO(txID ids.ID, utxo *lux.UTXO)
|
|
|
|
AddNet(netID ids.ID)
|
|
|
|
GetNetOwner(netID ids.ID) (fx.Owner, error)
|
|
SetNetOwner(netID ids.ID, owner fx.Owner)
|
|
|
|
GetNetToL1Conversion(chainID ids.ID) (NetToL1Conversion, error)
|
|
SetNetToL1Conversion(chainID ids.ID, c NetToL1Conversion)
|
|
|
|
GetNetTransformation(chainID ids.ID) (*txs.Tx, error)
|
|
AddNetTransformation(transformNetTx *txs.Tx)
|
|
|
|
AddChain(createChainTx *txs.Tx)
|
|
|
|
// Chain name uniqueness - for network-wide chain name resolution
|
|
GetChainIDByName(name string) (ids.ID, error)
|
|
IsChainNameTaken(name string) bool
|
|
|
|
GetTx(txID ids.ID) (*txs.Tx, status.Status, error)
|
|
AddTx(tx *txs.Tx, status status.Status)
|
|
|
|
// L1 Validator support - most methods inherited from L1Validators interface
|
|
// Only PutL1Validator is Chain-specific
|
|
PutL1Validator(validator L1Validator) error
|
|
}
|
|
|
|
type State interface {
|
|
Chain
|
|
uptime.State
|
|
lux.UTXOReader
|
|
|
|
GetLastAccepted() ids.ID
|
|
SetLastAccepted(blkID ids.ID)
|
|
|
|
GetStatelessBlock(blockID ids.ID) (block.Block, error)
|
|
|
|
// Invariant: [block] is an accepted block.
|
|
AddStatelessBlock(block block.Block)
|
|
|
|
GetBlockIDAtHeight(height uint64) (ids.ID, error)
|
|
|
|
GetRewardUTXOs(txID ids.ID) ([]*lux.UTXO, error)
|
|
GetChainIDs() ([]ids.ID, error)
|
|
GetChains(netID ids.ID) ([]*txs.Tx, error)
|
|
|
|
// ApplyValidatorWeightDiffs iterates from [startHeight] towards the genesis
|
|
// block until it has applied all of the diffs up to and including
|
|
// [endHeight]. Applying the diffs modifies [validators].
|
|
//
|
|
// Invariant: If attempting to generate the validator set for
|
|
// [endHeight - 1], [validators] must initially contain the validator
|
|
// weights for [startHeight].
|
|
//
|
|
// Note: Because this function iterates towards the genesis, [startHeight]
|
|
// will typically be greater than or equal to [endHeight]. If [startHeight]
|
|
// is less than [endHeight], no diffs will be applied.
|
|
ApplyValidatorWeightDiffs(
|
|
ctx context.Context,
|
|
validators map[ids.NodeID]*validators.GetValidatorOutput,
|
|
startHeight uint64,
|
|
endHeight uint64,
|
|
netID ids.ID,
|
|
) error
|
|
|
|
// ApplyValidatorPublicKeyDiffs iterates from [startHeight] towards the
|
|
// genesis block until it has applied all of the diffs up to and including
|
|
// [endHeight]. Applying the diffs modifies [validators].
|
|
//
|
|
// Invariant: If attempting to generate the validator set for
|
|
// [endHeight - 1], [validators] must initially contain the validator
|
|
// weights for [startHeight].
|
|
//
|
|
// Note: Because this function iterates towards the genesis, [startHeight]
|
|
// will typically be greater than or equal to [endHeight]. If [startHeight]
|
|
// is less than [endHeight], no diffs will be applied.
|
|
ApplyValidatorPublicKeyDiffs(
|
|
ctx context.Context,
|
|
validators map[ids.NodeID]*validators.GetValidatorOutput,
|
|
startHeight uint64,
|
|
endHeight uint64,
|
|
chainID ids.ID,
|
|
) error
|
|
|
|
SetHeight(height uint64)
|
|
|
|
// GetCurrentValidators returns chain and L1 validators for the given
|
|
// chainID along with the current P-chain height.
|
|
// This method works for both chains and L1s. Depending of the requested
|
|
// chain/L1 validator schema, the return values can include only chain
|
|
// validator, only L1 validators or both if there are initial stakers in the
|
|
// L1 conversion.
|
|
GetCurrentValidators(ctx context.Context, chainID ids.ID) ([]*Staker, []L1Validator, uint64, error)
|
|
|
|
// Discard uncommitted changes to the database.
|
|
Abort()
|
|
|
|
// ReindexBlocks converts any block indices using the legacy storage format
|
|
// to the new format. If this database has already updated the indices,
|
|
// this function will return immediately, without iterating over the
|
|
// database.
|
|
//
|
|
// ReindexBlocks converts legacy block storage indices to the current format.
|
|
// Retained for backward compatibility with pre-v1.14.x databases.
|
|
ReindexBlocks(lock sync.Locker, log log.Logger) error
|
|
|
|
// Commit changes to the base database.
|
|
Commit() error
|
|
|
|
// Returns a batch of unwritten changes that, when written, will commit all
|
|
// pending changes to the base database.
|
|
CommitBatch() (database.Batch, error)
|
|
|
|
Checksum() ids.ID
|
|
|
|
Close() error
|
|
}
|
|
|
|
// Prior to https://github.com/luxfi/node/pull/1719, blocks were
|
|
// stored as a map from blkID to stateBlk. Nodes synced prior to this PR may
|
|
// still have blocks partially stored using this legacy format.
|
|
//
|
|
// stateBlk is the legacy block storage format from before PR #1719.
|
|
// Retained for backward compatibility with pre-v1.14.x databases.
|
|
type stateBlk struct {
|
|
Bytes []byte `serialize:"true"`
|
|
Status uint32 `serialize:"true"`
|
|
}
|
|
|
|
// RegisterStateBlockType registers the stateBlk type with the given codec.
|
|
// This is needed for backward compatibility with old block storage format.
|
|
func RegisterStateBlockType(targetCodec pcodecs.Registry) error {
|
|
return targetCodec.RegisterType(&stateBlk{})
|
|
}
|
|
|
|
// Initialize the stateBlk type registration with the block codecs.
|
|
// This must be called before using parseStoredBlock for backward compatibility.
|
|
func init() {
|
|
// We need to register stateBlk with block.GenesisCodec so that
|
|
// parseStoredBlock can deserialize legacy block storage format.
|
|
// Since state imports block (no import cycle), we can register directly.
|
|
if err := block.RegisterGenesisType(&stateBlk{}); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
/*
|
|
* VMDB
|
|
* |-. validators
|
|
* | |-. current
|
|
* | | |-. validator
|
|
* | | | '-. list
|
|
* | | | '-- txID -> uptime + potential reward + potential delegatee reward
|
|
* | | |-. delegator
|
|
* | | | '-. list
|
|
* | | | '-- txID -> potential reward
|
|
* | | |-. chainValidator
|
|
* | | | '-. list
|
|
* | | | '-- txID -> uptime + potential reward + potential delegatee reward
|
|
* | | '-. chainDelegator
|
|
* | | '-. list
|
|
* | | '-- txID -> potential reward
|
|
* | |-. pending
|
|
* | | |-. validator
|
|
* | | | '-. list
|
|
* | | | '-- txID -> nil
|
|
* | | |-. delegator
|
|
* | | | '-. list
|
|
* | | | '-- txID -> nil
|
|
* | | |-. chainValidator
|
|
* | | | '-. list
|
|
* | | | '-- txID -> nil
|
|
* | | '-. chainDelegator
|
|
* | | '-. list
|
|
* | | '-- txID -> nil
|
|
* | |-. l1
|
|
* | | |-. weights
|
|
* | | | '-- chainID -> weight
|
|
* | | |-. chainIDNodeID
|
|
* | | | '-- chainID+nodeID -> validationID
|
|
* | | |-. active
|
|
* | | | '-- validationID -> l1Validator
|
|
* | | '-. inactive
|
|
* | | '-- validationID -> l1Validator
|
|
* | |-. weight diffs
|
|
* | | '-- chain+height+nodeID -> weightChange
|
|
* | '-. pub key diffs
|
|
* | '-- chain+height+nodeID -> uncompressed public key or nil
|
|
* |-. blockIDs
|
|
* | '-- height -> blockID
|
|
* |-. blocks
|
|
* | '-- blockID -> block bytes
|
|
* |-. txs
|
|
* | '-- txID -> tx bytes + tx status
|
|
* |- rewardUTXOs
|
|
* | '-. txID
|
|
* | '-. list
|
|
* | '-- utxoID -> utxo bytes
|
|
* |- utxos
|
|
* | '-- utxoDB
|
|
* |-. chains
|
|
* | '-. list
|
|
* | '-- txID -> nil
|
|
* |-. chainOwners
|
|
* | '-- chainID -> owner
|
|
* |-. chainToL1Conversions
|
|
* | '-- chainID -> conversionID + chainID + addr
|
|
* |-. chains
|
|
* | '-. netID
|
|
* | '-. list
|
|
* | '-- txID -> nil
|
|
* |-. expiryReplayProtection
|
|
* | '-- timestamp + validationID -> nil
|
|
* '-. singletons
|
|
* |-- initializedKey -> nil
|
|
* |-- blocksReindexedKey -> nil
|
|
* |-- timestampKey -> timestamp
|
|
* |-- feeStateKey -> feeState
|
|
* |-- l1ValidatorExcessKey -> l1ValidatorExcess
|
|
* |-- accruedFeesKey -> accruedFees
|
|
* |-- currentSupplyKey -> currentSupply
|
|
* |-- lastAcceptedKey -> lastAccepted
|
|
* '-- heightsIndexKey -> startIndexHeight + endIndexHeight
|
|
*/
|
|
type state struct {
|
|
validatorState
|
|
|
|
validators validators.Manager
|
|
rt *runtime.Runtime
|
|
upgrades upgrade.Config
|
|
metrics metrics.Metrics
|
|
rewards reward.Calculator
|
|
|
|
baseDB *versiondb.Database
|
|
|
|
expiry *btree.BTreeG[ExpiryEntry]
|
|
expiryDiff *expiryDiff
|
|
expiryDB database.Database
|
|
|
|
activeL1Validators *activeL1Validators
|
|
l1ValidatorsDiff *l1ValidatorsDiff
|
|
l1ValidatorsDiffLock sync.RWMutex // Protects concurrent access to l1ValidatorsDiff
|
|
l1ValidatorsDB database.Database
|
|
weightsCache cache.Cacher[ids.ID, uint64] // chainID -> total L1 validator weight
|
|
weightsDB database.Database
|
|
chainIDNodeIDCache cache.Cacher[chainIDNodeID, bool] // chainID+nodeID -> is validator
|
|
chainIDNodeIDDB database.Database
|
|
activeDB database.Database
|
|
inactiveCache cache.Cacher[ids.ID, maybe.Maybe[L1Validator]] // validationID -> L1Validator
|
|
inactiveDB database.Database
|
|
|
|
currentStakers *baseStakers
|
|
pendingStakers *baseStakers
|
|
|
|
currentHeight uint64
|
|
|
|
// L1 validators storage (temporary in-memory implementation)
|
|
l1Validators map[ids.ID]L1Validator
|
|
|
|
addedBlockIDs map[uint64]ids.ID // map of height -> blockID
|
|
blockIDCache cache.Cacher[uint64, ids.ID] // cache of height -> blockID; if the entry is ids.Empty, it is not in the database
|
|
blockIDDB database.Database
|
|
|
|
addedBlocks map[ids.ID]block.Block // map of blockID -> Block
|
|
blockCache cache.Cacher[ids.ID, block.Block] // cache of blockID -> Block; if the entry is nil, it is not in the database
|
|
blockDB database.Database
|
|
|
|
validatorsDB database.Database
|
|
currentValidatorsDB database.Database
|
|
currentValidatorBaseDB database.Database
|
|
currentValidatorList linkeddb.LinkedDB
|
|
currentDelegatorBaseDB database.Database
|
|
currentDelegatorList linkeddb.LinkedDB
|
|
currentNetValidatorBaseDB database.Database
|
|
currentNetValidatorList linkeddb.LinkedDB
|
|
currentNetDelegatorBaseDB database.Database
|
|
currentNetDelegatorList linkeddb.LinkedDB
|
|
pendingValidatorsDB database.Database
|
|
pendingValidatorBaseDB database.Database
|
|
pendingValidatorList linkeddb.LinkedDB
|
|
pendingDelegatorBaseDB database.Database
|
|
pendingDelegatorList linkeddb.LinkedDB
|
|
pendingNetValidatorBaseDB database.Database
|
|
pendingNetValidatorList linkeddb.LinkedDB
|
|
pendingNetDelegatorBaseDB database.Database
|
|
pendingNetDelegatorList linkeddb.LinkedDB
|
|
|
|
validatorWeightDiffsDB database.Database
|
|
validatorPublicKeyDiffsDB database.Database
|
|
|
|
addedTxs map[ids.ID]*txAndStatus // map of txID -> {*txs.Tx, Status}
|
|
txCache cache.Cacher[ids.ID, *txAndStatus] // txID -> {*txs.Tx, Status}; if the entry is nil, it is not in the database
|
|
txDB database.Database
|
|
|
|
addedRewardUTXOs map[ids.ID][]*lux.UTXO // map of txID -> []*UTXO
|
|
rewardUTXOsCache cache.Cacher[ids.ID, []*lux.UTXO] // txID -> []*UTXO
|
|
rewardUTXODB database.Database
|
|
|
|
modifiedUTXOs map[ids.ID]*lux.UTXO // map of modified UTXOID -> *UTXO; if the UTXO is nil, it has been removed
|
|
utxoDB database.Database
|
|
utxoState lux.UTXOState
|
|
|
|
cachedChainIDs []ids.ID // nil if the chains haven't been loaded
|
|
addedChainIDs []ids.ID
|
|
chainBaseDB database.Database
|
|
chainDB linkeddb.LinkedDB
|
|
|
|
chainOwners map[ids.ID]fx.Owner // map of netID -> owner
|
|
chainOwnerCache cache.Cacher[ids.ID, fxOwnerAndSize] // cache of netID -> owner; if the entry is nil, it is not in the database
|
|
chainOwnerDB database.Database
|
|
|
|
chainToL1Conversions map[ids.ID]NetToL1Conversion // map of chainID -> conversion of the chain
|
|
chainToL1ConversionCache cache.Cacher[ids.ID, NetToL1Conversion] // cache of chainID -> conversion
|
|
chainToL1ConversionDB database.Database
|
|
|
|
transformedNets map[ids.ID]*txs.Tx // map of chainID -> transformNetTx
|
|
transformedNetCache cache.Cacher[ids.ID, *txs.Tx] // cache of chainID -> transformNetTx; if the entry is nil, it is not in the database
|
|
transformedNetDB database.Database
|
|
|
|
modifiedSupplies map[ids.ID]uint64 // map of netID -> current supply
|
|
supplyCache cache.Cacher[ids.ID, *uint64] // cache of netID -> current supply; if the entry is nil, it is not in the database
|
|
supplyDB database.Database
|
|
|
|
addedChains map[ids.ID][]*txs.Tx // maps netID -> the newly added chains to the chain
|
|
chainCache cache.Cacher[ids.ID, []*txs.Tx] // cache of netID -> the chains after all local modifications []*txs.Tx
|
|
chainDBCache cache.Cacher[ids.ID, linkeddb.LinkedDB] // cache of netID -> linkedDB
|
|
chainsDB database.Database // base database for net-specific chains
|
|
|
|
// Chain name uniqueness - maps lowercase chain name to chain ID
|
|
addedChainNames map[string]ids.ID // newly added chain names (lowercase) -> chainID
|
|
chainNameCache cache.Cacher[string, ids.ID] // cache of lowercase chain name -> chainID
|
|
chainNameDB database.Database
|
|
|
|
// The persisted fields represent the current database value
|
|
timestamp, persistedTimestamp time.Time
|
|
feeState, persistedFeeState gas.State
|
|
l1ValidatorExcess, persistedL1ValidatorExcess gas.Gas
|
|
accruedFees, persistedAccruedFees uint64
|
|
currentSupply, persistedCurrentSupply uint64
|
|
// [lastAccepted] is the most recently accepted block.
|
|
lastAccepted, persistedLastAccepted ids.ID
|
|
lastAcceptedLock sync.RWMutex // Protects concurrent access to lastAccepted
|
|
indexedHeights *heightRange
|
|
singletonDB database.Database
|
|
}
|
|
|
|
// heightRange is used to track which heights are safe to use the native DB
|
|
// iterator for querying validator diffs.
|
|
//
|
|
// new indexing mechanism.
|
|
type heightRange struct {
|
|
LowerBound uint64 `serialize:"true"`
|
|
UpperBound uint64 `serialize:"true"`
|
|
}
|
|
|
|
type ValidatorWeightDiff struct {
|
|
Decrease bool `serialize:"true"`
|
|
Amount uint64 `serialize:"true"`
|
|
ValidationID ids.ID `serialize:"true"` // Added to preserve TxID during diff application
|
|
}
|
|
|
|
func (v *ValidatorWeightDiff) Add(amount uint64) error {
|
|
return v.addOrSub(false, amount)
|
|
}
|
|
|
|
func (v *ValidatorWeightDiff) Sub(amount uint64) error {
|
|
return v.addOrSub(true, amount)
|
|
}
|
|
|
|
func (v *ValidatorWeightDiff) addOrSub(sub bool, amount uint64) error {
|
|
if v.Decrease == sub {
|
|
var err error
|
|
v.Amount, err = safemath.Add(v.Amount, amount)
|
|
return err
|
|
}
|
|
|
|
if v.Amount > amount {
|
|
v.Amount -= amount
|
|
} else {
|
|
v.Amount = safemath.AbsDiff(v.Amount, amount)
|
|
v.Decrease = sub
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type txBytesAndStatus struct {
|
|
Tx []byte `serialize:"true"`
|
|
Status status.Status `serialize:"true"`
|
|
}
|
|
|
|
type txAndStatus struct {
|
|
tx *txs.Tx
|
|
status status.Status
|
|
}
|
|
|
|
type fxOwnerAndSize struct {
|
|
owner fx.Owner
|
|
size int
|
|
}
|
|
|
|
type NetToL1Conversion struct {
|
|
ConversionID ids.ID `serialize:"true"`
|
|
ChainID ids.ID `serialize:"true"`
|
|
Addr []byte `serialize:"true"`
|
|
}
|
|
|
|
func txSize(_ ids.ID, tx *txs.Tx) int {
|
|
if tx == nil {
|
|
return ids.IDLen + constants.PointerOverhead
|
|
}
|
|
return ids.IDLen + len(tx.Bytes()) + constants.PointerOverhead
|
|
}
|
|
|
|
func txAndStatusSize(_ ids.ID, t *txAndStatus) int {
|
|
if t == nil {
|
|
return ids.IDLen + constants.PointerOverhead
|
|
}
|
|
return ids.IDLen + len(t.tx.Bytes()) + pcodecs.IntLen + 2*constants.PointerOverhead
|
|
}
|
|
|
|
func blockSize(_ ids.ID, blk block.Block) int {
|
|
if blk == nil {
|
|
return ids.IDLen + constants.PointerOverhead
|
|
}
|
|
return ids.IDLen + len(blk.Bytes()) + constants.PointerOverhead
|
|
}
|
|
|
|
func New(
|
|
db database.Database,
|
|
genesisBytes []byte,
|
|
metricsReg metric.Registerer,
|
|
validators validators.Manager,
|
|
upgrades upgrade.Config,
|
|
execCfg *config.Config,
|
|
rt *runtime.Runtime,
|
|
metrics metrics.Metrics,
|
|
rewards reward.Calculator,
|
|
) (State, error) {
|
|
// Convert metric.Registerer to metric.Registry
|
|
// metricsReg implements Registerer, cast it to metric.Registry
|
|
var reg metric.Registry
|
|
if r, ok := metricsReg.(metric.Registry); ok {
|
|
reg = r
|
|
} else {
|
|
// If conversion fails, use nil (metercacher will handle it)
|
|
reg = nil
|
|
}
|
|
|
|
blockIDCache, err := metercacher.New[uint64, ids.ID](
|
|
"block_id_cache",
|
|
reg,
|
|
lru.NewCache[uint64, ids.ID](execCfg.BlockIDCacheSize),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
blockCache, err := metercacher.New[ids.ID, block.Block](
|
|
"block_cache",
|
|
reg,
|
|
lru.NewSizedCache(execCfg.BlockCacheSize, blockSize),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
baseDB := versiondb.New(db)
|
|
|
|
validatorsDB := prefixdb.New(ValidatorsPrefix, baseDB)
|
|
|
|
currentValidatorsDB := prefixdb.New(CurrentPrefix, validatorsDB)
|
|
currentValidatorBaseDB := prefixdb.New(ValidatorPrefix, currentValidatorsDB)
|
|
currentDelegatorBaseDB := prefixdb.New(DelegatorPrefix, currentValidatorsDB)
|
|
currentNetValidatorBaseDB := prefixdb.New(NetValidatorPrefix, currentValidatorsDB)
|
|
currentNetDelegatorBaseDB := prefixdb.New(NetDelegatorPrefix, currentValidatorsDB)
|
|
|
|
pendingValidatorsDB := prefixdb.New(PendingPrefix, validatorsDB)
|
|
pendingValidatorBaseDB := prefixdb.New(ValidatorPrefix, pendingValidatorsDB)
|
|
pendingDelegatorBaseDB := prefixdb.New(DelegatorPrefix, pendingValidatorsDB)
|
|
pendingNetValidatorBaseDB := prefixdb.New(NetValidatorPrefix, pendingValidatorsDB)
|
|
pendingNetDelegatorBaseDB := prefixdb.New(NetDelegatorPrefix, pendingValidatorsDB)
|
|
|
|
l1ValidatorsDB := prefixdb.New(L1Prefix, validatorsDB)
|
|
|
|
validatorWeightDiffsDB := prefixdb.New(ValidatorWeightDiffsPrefix, validatorsDB)
|
|
validatorPublicKeyDiffsDB := prefixdb.New(ValidatorPublicKeyDiffsPrefix, validatorsDB)
|
|
|
|
weightsCache, err := metercacher.New(
|
|
"l1_validator_weights_cache",
|
|
reg,
|
|
lru.NewSizedCache(execCfg.L1WeightsCacheSize, func(ids.ID, uint64) int {
|
|
return ids.IDLen + pcodecs.LongLen
|
|
}),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
inactiveL1ValidatorsCache, err := metercacher.New(
|
|
"l1_validator_inactive_cache",
|
|
reg,
|
|
lru.NewSizedCache(
|
|
execCfg.L1InactiveValidatorsCacheSize,
|
|
func(_ ids.ID, maybeL1Validator maybe.Maybe[L1Validator]) int {
|
|
const (
|
|
l1ValidatorOverhead = ids.IDLen + ids.NodeIDLen + 4*pcodecs.LongLen + 3*constants.PointerOverhead
|
|
maybeL1ValidatorOverhead = pcodecs.BoolLen + l1ValidatorOverhead
|
|
entryOverhead = ids.IDLen + maybeL1ValidatorOverhead
|
|
)
|
|
if maybeL1Validator.IsNothing() {
|
|
return entryOverhead
|
|
}
|
|
|
|
l1Validator := maybeL1Validator.Value()
|
|
return entryOverhead + len(l1Validator.PublicKey) + len(l1Validator.RemainingBalanceOwner) + len(l1Validator.DeactivationOwner)
|
|
},
|
|
),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
chainIDNodeIDCache, err := metercacher.New(
|
|
"l1_validator_chain_id_node_id_cache",
|
|
reg,
|
|
lru.NewSizedCache(execCfg.L1ChainIDNodeIDCacheSize, func(chainIDNodeID, bool) int {
|
|
return ids.IDLen + ids.NodeIDLen + pcodecs.BoolLen
|
|
}),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
txCache, err := metercacher.New(
|
|
"tx_cache",
|
|
reg,
|
|
lru.NewSizedCache(execCfg.TxCacheSize, txAndStatusSize),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rewardUTXODB := prefixdb.New(RewardUTXOsPrefix, baseDB)
|
|
rewardUTXOsCache, err := metercacher.New[ids.ID, []*lux.UTXO](
|
|
"reward_utxos_cache",
|
|
reg,
|
|
lru.NewCache[ids.ID, []*lux.UTXO](execCfg.RewardUTXOsCacheSize),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
utxoDB := prefixdb.New(UTXOPrefix, baseDB)
|
|
utxoState, err := lux.NewMeteredUTXOState(utxoDB, metricsReg, execCfg.ChecksumsEnabled)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
chainBaseDB := prefixdb.New(NetPrefix, baseDB)
|
|
|
|
chainOwnerDB := prefixdb.New(NetOwnerPrefix, baseDB)
|
|
chainOwnerCache, err := metercacher.New[ids.ID, fxOwnerAndSize](
|
|
"chain_owner_cache",
|
|
reg,
|
|
lru.NewSizedCache(execCfg.FxOwnerCacheSize, func(_ ids.ID, f fxOwnerAndSize) int {
|
|
return ids.IDLen + f.size
|
|
}),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
chainToL1ConversionDB := prefixdb.New(NetToL1ConversionPrefix, baseDB)
|
|
chainToL1ConversionCache, err := metercacher.New[ids.ID, NetToL1Conversion](
|
|
"chain_conversion_cache",
|
|
reg,
|
|
lru.NewSizedCache(execCfg.NetToL1ConversionCacheSize, func(_ ids.ID, c NetToL1Conversion) int {
|
|
return 3*ids.IDLen + len(c.Addr)
|
|
}),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
transformedNetCache, err := metercacher.New(
|
|
"transformed_chain_cache",
|
|
reg,
|
|
lru.NewSizedCache(execCfg.TransformedNetTxCacheSize, txSize),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
supplyCache, err := metercacher.New[ids.ID, *uint64](
|
|
"supply_cache",
|
|
reg,
|
|
lru.NewCache[ids.ID, *uint64](execCfg.ChainCacheSize),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
chainCache, err := metercacher.New[ids.ID, []*txs.Tx](
|
|
"chain_cache",
|
|
reg,
|
|
lru.NewCache[ids.ID, []*txs.Tx](execCfg.ChainCacheSize),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
chainDBCache, err := metercacher.New[ids.ID, linkeddb.LinkedDB](
|
|
"chain_db_cache",
|
|
reg,
|
|
lru.NewCache[ids.ID, linkeddb.LinkedDB](execCfg.ChainDBCacheSize),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
chainNameCache, err := metercacher.New[string, ids.ID](
|
|
"chain_name_cache",
|
|
reg,
|
|
lru.NewCache[string, ids.ID](execCfg.ChainCacheSize),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
s := &state{
|
|
validatorState: newValidatorState(),
|
|
|
|
validators: validators,
|
|
rt: rt,
|
|
upgrades: upgrades,
|
|
metrics: metrics,
|
|
rewards: rewards,
|
|
baseDB: baseDB,
|
|
|
|
addedBlockIDs: make(map[uint64]ids.ID),
|
|
blockIDCache: blockIDCache,
|
|
blockIDDB: prefixdb.New(BlockIDPrefix, baseDB),
|
|
|
|
addedBlocks: make(map[ids.ID]block.Block),
|
|
blockCache: blockCache,
|
|
blockDB: prefixdb.New(BlockPrefix, baseDB),
|
|
|
|
expiry: btree.NewG(defaultTreeDegree, ExpiryEntry.Less),
|
|
expiryDiff: newExpiryDiff(),
|
|
expiryDB: prefixdb.New(ExpiryReplayProtectionPrefix, baseDB),
|
|
|
|
activeL1Validators: newActiveL1Validators(),
|
|
l1ValidatorsDiff: newL1ValidatorsDiff(),
|
|
l1ValidatorsDB: l1ValidatorsDB,
|
|
weightsCache: weightsCache,
|
|
weightsDB: prefixdb.New(WeightsPrefix, l1ValidatorsDB),
|
|
chainIDNodeIDCache: chainIDNodeIDCache,
|
|
chainIDNodeIDDB: prefixdb.New(ChainIDNodeIDPrefix, l1ValidatorsDB),
|
|
activeDB: prefixdb.New(ActivePrefix, l1ValidatorsDB),
|
|
inactiveCache: inactiveL1ValidatorsCache,
|
|
inactiveDB: prefixdb.New(InactivePrefix, l1ValidatorsDB),
|
|
|
|
currentStakers: newBaseStakers(),
|
|
pendingStakers: newBaseStakers(),
|
|
|
|
l1Validators: make(map[ids.ID]L1Validator),
|
|
|
|
validatorsDB: validatorsDB,
|
|
currentValidatorsDB: currentValidatorsDB,
|
|
currentValidatorBaseDB: currentValidatorBaseDB,
|
|
currentValidatorList: linkeddb.NewDefault(currentValidatorBaseDB),
|
|
currentDelegatorBaseDB: currentDelegatorBaseDB,
|
|
currentDelegatorList: linkeddb.NewDefault(currentDelegatorBaseDB),
|
|
currentNetValidatorBaseDB: currentNetValidatorBaseDB,
|
|
currentNetValidatorList: linkeddb.NewDefault(currentNetValidatorBaseDB),
|
|
currentNetDelegatorBaseDB: currentNetDelegatorBaseDB,
|
|
currentNetDelegatorList: linkeddb.NewDefault(currentNetDelegatorBaseDB),
|
|
pendingValidatorsDB: pendingValidatorsDB,
|
|
pendingValidatorBaseDB: pendingValidatorBaseDB,
|
|
pendingValidatorList: linkeddb.NewDefault(pendingValidatorBaseDB),
|
|
pendingDelegatorBaseDB: pendingDelegatorBaseDB,
|
|
pendingDelegatorList: linkeddb.NewDefault(pendingDelegatorBaseDB),
|
|
pendingNetValidatorBaseDB: pendingNetValidatorBaseDB,
|
|
pendingNetValidatorList: linkeddb.NewDefault(pendingNetValidatorBaseDB),
|
|
pendingNetDelegatorBaseDB: pendingNetDelegatorBaseDB,
|
|
pendingNetDelegatorList: linkeddb.NewDefault(pendingNetDelegatorBaseDB),
|
|
validatorWeightDiffsDB: validatorWeightDiffsDB,
|
|
validatorPublicKeyDiffsDB: validatorPublicKeyDiffsDB,
|
|
|
|
addedTxs: make(map[ids.ID]*txAndStatus),
|
|
txDB: prefixdb.New(TxPrefix, baseDB),
|
|
txCache: txCache,
|
|
|
|
addedRewardUTXOs: make(map[ids.ID][]*lux.UTXO),
|
|
rewardUTXODB: rewardUTXODB,
|
|
rewardUTXOsCache: rewardUTXOsCache,
|
|
|
|
modifiedUTXOs: make(map[ids.ID]*lux.UTXO),
|
|
utxoDB: utxoDB,
|
|
utxoState: utxoState,
|
|
|
|
chainBaseDB: chainBaseDB,
|
|
chainDB: linkeddb.NewDefault(chainBaseDB),
|
|
|
|
chainOwners: make(map[ids.ID]fx.Owner),
|
|
chainOwnerDB: chainOwnerDB,
|
|
chainOwnerCache: chainOwnerCache,
|
|
|
|
chainToL1Conversions: make(map[ids.ID]NetToL1Conversion),
|
|
chainToL1ConversionDB: chainToL1ConversionDB,
|
|
chainToL1ConversionCache: chainToL1ConversionCache,
|
|
|
|
transformedNets: make(map[ids.ID]*txs.Tx),
|
|
transformedNetCache: transformedNetCache,
|
|
transformedNetDB: prefixdb.New(TransformedNetPrefix, baseDB),
|
|
|
|
modifiedSupplies: make(map[ids.ID]uint64),
|
|
supplyCache: supplyCache,
|
|
supplyDB: prefixdb.New(SupplyPrefix, baseDB),
|
|
|
|
addedChains: make(map[ids.ID][]*txs.Tx),
|
|
chainsDB: prefixdb.New(ChainPrefix, baseDB),
|
|
chainCache: chainCache,
|
|
chainDBCache: chainDBCache,
|
|
|
|
addedChainNames: make(map[string]ids.ID),
|
|
chainNameCache: chainNameCache,
|
|
chainNameDB: prefixdb.New(ChainNamePrefix, baseDB),
|
|
|
|
singletonDB: prefixdb.New(SingletonPrefix, baseDB),
|
|
}
|
|
|
|
if err := s.sync(genesisBytes); err != nil {
|
|
return nil, errors.Join(
|
|
err,
|
|
s.Close(),
|
|
)
|
|
}
|
|
|
|
return s, nil
|
|
}
|