From 23e541781bb8d4ccdc03aefa78b1cd0e11dd14a3 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Wed, 20 Mar 2024 01:48:04 -0400 Subject: [PATCH] Remove fallback validator height indexing (#2801) --- vms/platformvm/state/state.go | 214 ++++++++--------------------- vms/platformvm/state/state_test.go | 20 +-- 2 files changed, 67 insertions(+), 167 deletions(-) diff --git a/vms/platformvm/state/state.go b/vms/platformvm/state/state.go index 32007b4fc928..77047389c1c1 100644 --- a/vms/platformvm/state/state.go +++ b/vms/platformvm/state/state.go @@ -47,28 +47,26 @@ var ( errValidatorSetAlreadyPopulated = errors.New("validator set already populated") errIsNotSubnet = errors.New("is not a subnet") - BlockIDPrefix = []byte("blockID") - BlockPrefix = []byte("block") - ValidatorsPrefix = []byte("validators") - CurrentPrefix = []byte("current") - PendingPrefix = []byte("pending") - ValidatorPrefix = []byte("validator") - DelegatorPrefix = []byte("delegator") - SubnetValidatorPrefix = []byte("subnetValidator") - SubnetDelegatorPrefix = []byte("subnetDelegator") - NestedValidatorWeightDiffsPrefix = []byte("validatorDiffs") - NestedValidatorPublicKeyDiffsPrefix = []byte("publicKeyDiffs") - FlatValidatorWeightDiffsPrefix = []byte("flatValidatorDiffs") - FlatValidatorPublicKeyDiffsPrefix = []byte("flatPublicKeyDiffs") - TxPrefix = []byte("tx") - RewardUTXOsPrefix = []byte("rewardUTXOs") - UTXOPrefix = []byte("utxo") - SubnetPrefix = []byte("subnet") - SubnetOwnerPrefix = []byte("subnetOwner") - TransformedSubnetPrefix = []byte("transformedSubnet") - SupplyPrefix = []byte("supply") - ChainPrefix = []byte("chain") - SingletonPrefix = []byte("singleton") + BlockIDPrefix = []byte("blockID") + BlockPrefix = []byte("block") + ValidatorsPrefix = []byte("validators") + CurrentPrefix = []byte("current") + PendingPrefix = []byte("pending") + ValidatorPrefix = []byte("validator") + DelegatorPrefix = []byte("delegator") + SubnetValidatorPrefix = []byte("subnetValidator") + SubnetDelegatorPrefix = []byte("subnetDelegator") + ValidatorWeightDiffsPrefix = []byte("flatValidatorDiffs") + ValidatorPublicKeyDiffsPrefix = []byte("flatPublicKeyDiffs") + TxPrefix = []byte("tx") + RewardUTXOsPrefix = []byte("rewardUTXOs") + UTXOPrefix = []byte("utxo") + SubnetPrefix = []byte("subnet") + SubnetOwnerPrefix = []byte("subnetOwner") + TransformedSubnetPrefix = []byte("transformedSubnet") + SupplyPrefix = []byte("supply") + ChainPrefix = []byte("chain") + SingletonPrefix = []byte("singleton") TimestampKey = []byte("timestamp") CurrentSupplyKey = []byte("current supply") @@ -209,17 +207,9 @@ type State interface { * | | '-. subnetDelegator * | | '-. list * | | '-- txID -> nil - * | |-. nested weight diffs TODO: Remove once only the flat db is needed - * | | '-. height+subnet - * | | '-. list - * | | '-- nodeID -> weightChange - * | |-. nested pub key diffs TODO: Remove once only the flat db is needed - * | | '-. height - * | | '-. list - * | | '-- nodeID -> compressed public key - * | |-. flat weight diffs + * | |-. weight diffs * | | '-- subnet+height+nodeID -> weightChange - * | '-. flat pub key diffs + * | '-. pub key diffs * | '-- subnet+height+nodeID -> uncompressed public key or nil * |-. blockIDs * | '-- height -> blockID @@ -293,10 +283,8 @@ type state struct { pendingSubnetDelegatorBaseDB database.Database pendingSubnetDelegatorList linkeddb.LinkedDB - nestedValidatorWeightDiffsDB database.Database - nestedValidatorPublicKeyDiffsDB database.Database - flatValidatorWeightDiffsDB database.Database - flatValidatorPublicKeyDiffsDB database.Database + 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 isn't in the database @@ -338,8 +326,9 @@ type state struct { currentSupply, persistedCurrentSupply uint64 // [lastAccepted] is the most recently accepted block. lastAccepted, persistedLastAccepted ids.ID - indexedHeights *heightRange - singletonDB database.Database + // TODO: Remove indexedHeights once v1.11.3 has been released. + indexedHeights *heightRange + singletonDB database.Database } // heightRange is used to track which heights are safe to use the native DB @@ -373,11 +362,6 @@ func (v *ValidatorWeightDiff) Add(negative bool, amount uint64) error { return nil } -type heightWithSubnet struct { - Height uint64 `serialize:"true"` - SubnetID ids.ID `serialize:"true"` -} - type txBytesAndStatus struct { Tx []byte `serialize:"true"` Status status.Status `serialize:"true"` @@ -490,10 +474,8 @@ func newState( pendingSubnetValidatorBaseDB := prefixdb.New(SubnetValidatorPrefix, pendingValidatorsDB) pendingSubnetDelegatorBaseDB := prefixdb.New(SubnetDelegatorPrefix, pendingValidatorsDB) - nestedValidatorWeightDiffsDB := prefixdb.New(NestedValidatorWeightDiffsPrefix, validatorsDB) - nestedValidatorPublicKeyDiffsDB := prefixdb.New(NestedValidatorPublicKeyDiffsPrefix, validatorsDB) - flatValidatorWeightDiffsDB := prefixdb.New(FlatValidatorWeightDiffsPrefix, validatorsDB) - flatValidatorPublicKeyDiffsDB := prefixdb.New(FlatValidatorPublicKeyDiffsPrefix, validatorsDB) + validatorWeightDiffsDB := prefixdb.New(ValidatorWeightDiffsPrefix, validatorsDB) + validatorPublicKeyDiffsDB := prefixdb.New(ValidatorPublicKeyDiffsPrefix, validatorsDB) txCache, err := metercacher.New( "tx_cache", @@ -591,29 +573,27 @@ func newState( currentStakers: newBaseStakers(), pendingStakers: newBaseStakers(), - validatorsDB: validatorsDB, - currentValidatorsDB: currentValidatorsDB, - currentValidatorBaseDB: currentValidatorBaseDB, - currentValidatorList: linkeddb.NewDefault(currentValidatorBaseDB), - currentDelegatorBaseDB: currentDelegatorBaseDB, - currentDelegatorList: linkeddb.NewDefault(currentDelegatorBaseDB), - currentSubnetValidatorBaseDB: currentSubnetValidatorBaseDB, - currentSubnetValidatorList: linkeddb.NewDefault(currentSubnetValidatorBaseDB), - currentSubnetDelegatorBaseDB: currentSubnetDelegatorBaseDB, - currentSubnetDelegatorList: linkeddb.NewDefault(currentSubnetDelegatorBaseDB), - pendingValidatorsDB: pendingValidatorsDB, - pendingValidatorBaseDB: pendingValidatorBaseDB, - pendingValidatorList: linkeddb.NewDefault(pendingValidatorBaseDB), - pendingDelegatorBaseDB: pendingDelegatorBaseDB, - pendingDelegatorList: linkeddb.NewDefault(pendingDelegatorBaseDB), - pendingSubnetValidatorBaseDB: pendingSubnetValidatorBaseDB, - pendingSubnetValidatorList: linkeddb.NewDefault(pendingSubnetValidatorBaseDB), - pendingSubnetDelegatorBaseDB: pendingSubnetDelegatorBaseDB, - pendingSubnetDelegatorList: linkeddb.NewDefault(pendingSubnetDelegatorBaseDB), - nestedValidatorWeightDiffsDB: nestedValidatorWeightDiffsDB, - nestedValidatorPublicKeyDiffsDB: nestedValidatorPublicKeyDiffsDB, - flatValidatorWeightDiffsDB: flatValidatorWeightDiffsDB, - flatValidatorPublicKeyDiffsDB: flatValidatorPublicKeyDiffsDB, + validatorsDB: validatorsDB, + currentValidatorsDB: currentValidatorsDB, + currentValidatorBaseDB: currentValidatorBaseDB, + currentValidatorList: linkeddb.NewDefault(currentValidatorBaseDB), + currentDelegatorBaseDB: currentDelegatorBaseDB, + currentDelegatorList: linkeddb.NewDefault(currentDelegatorBaseDB), + currentSubnetValidatorBaseDB: currentSubnetValidatorBaseDB, + currentSubnetValidatorList: linkeddb.NewDefault(currentSubnetValidatorBaseDB), + currentSubnetDelegatorBaseDB: currentSubnetDelegatorBaseDB, + currentSubnetDelegatorList: linkeddb.NewDefault(currentSubnetDelegatorBaseDB), + pendingValidatorsDB: pendingValidatorsDB, + pendingValidatorBaseDB: pendingValidatorBaseDB, + pendingValidatorList: linkeddb.NewDefault(pendingValidatorBaseDB), + pendingDelegatorBaseDB: pendingDelegatorBaseDB, + pendingDelegatorList: linkeddb.NewDefault(pendingDelegatorBaseDB), + pendingSubnetValidatorBaseDB: pendingSubnetValidatorBaseDB, + pendingSubnetValidatorList: linkeddb.NewDefault(pendingSubnetValidatorBaseDB), + pendingSubnetDelegatorBaseDB: pendingSubnetDelegatorBaseDB, + pendingSubnetDelegatorList: linkeddb.NewDefault(pendingSubnetDelegatorBaseDB), + validatorWeightDiffsDB: validatorWeightDiffsDB, + validatorPublicKeyDiffsDB: validatorPublicKeyDiffsDB, addedTxs: make(map[ids.ID]*txAndStatus), txDB: prefixdb.New(TxPrefix, baseDB), @@ -1053,16 +1033,14 @@ func (s *state) ApplyValidatorWeightDiffs( endHeight uint64, subnetID ids.ID, ) error { - diffIter := s.flatValidatorWeightDiffsDB.NewIteratorWithStartAndPrefix( + diffIter := s.validatorWeightDiffsDB.NewIteratorWithStartAndPrefix( marshalStartDiffKey(subnetID, startHeight), subnetID[:], ) defer diffIter.Release() prevHeight := startHeight + 1 - // TODO: Remove the index continuity checks once we are guaranteed nodes can - // not rollback to not support the new indexing mechanism. - for diffIter.Next() && s.indexedHeights != nil && s.indexedHeights.LowerBound <= endHeight { + for diffIter.Next() { if err := ctx.Err(); err != nil { return err } @@ -1100,50 +1078,7 @@ func (s *state) ApplyValidatorWeightDiffs( return err } } - if err := diffIter.Error(); err != nil { - return err - } - - // TODO: Remove this once it is assumed that all subnet validators have - // adopted the new indexing. - for height := prevHeight - 1; height >= endHeight; height-- { - if err := ctx.Err(); err != nil { - return err - } - - prefixStruct := heightWithSubnet{ - Height: height, - SubnetID: subnetID, - } - prefixBytes, err := block.GenesisCodec.Marshal(block.CodecVersion, prefixStruct) - if err != nil { - return err - } - - rawDiffDB := prefixdb.New(prefixBytes, s.nestedValidatorWeightDiffsDB) - diffDB := linkeddb.NewDefault(rawDiffDB) - diffIter := diffDB.NewIterator() - defer diffIter.Release() - - for diffIter.Next() { - nodeID, err := ids.ToNodeID(diffIter.Key()) - if err != nil { - return err - } - - weightDiff := ValidatorWeightDiff{} - _, err = block.GenesisCodec.Unmarshal(diffIter.Value(), &weightDiff) - if err != nil { - return err - } - - if err := applyWeightDiff(validators, nodeID, &weightDiff); err != nil { - return err - } - } - } - - return nil + return diffIter.Error() } func applyWeightDiff( @@ -1189,7 +1124,7 @@ func (s *state) ApplyValidatorPublicKeyDiffs( startHeight uint64, endHeight uint64, ) error { - diffIter := s.flatValidatorPublicKeyDiffsDB.NewIteratorWithStartAndPrefix( + diffIter := s.validatorPublicKeyDiffsDB.NewIteratorWithStartAndPrefix( marshalStartDiffKey(constants.PrimaryNetworkID, startHeight), constants.PrimaryNetworkID[:], ) @@ -1891,10 +1826,6 @@ func (s *state) GetBlockIDAtHeight(height uint64) (ids.ID, error) { } func (s *state) writeCurrentStakers(updateValidators bool, height uint64, codecVersion uint16) error { - heightBytes := database.PackUInt64(height) - rawNestedPublicKeyDiffDB := prefixdb.New(heightBytes, s.nestedValidatorPublicKeyDiffsDB) - nestedPKDiffDB := linkeddb.NewDefault(rawNestedPublicKeyDiffDB) - for subnetID, validatorDiffs := range s.currentStakers.validatorDiffs { delete(s.currentStakers.validatorDiffs, subnetID) @@ -1906,17 +1837,6 @@ func (s *state) writeCurrentStakers(updateValidators bool, height uint64, codecV delegatorDB = s.currentDelegatorList } - prefixStruct := heightWithSubnet{ - Height: height, - SubnetID: subnetID, - } - prefixBytes, err := block.GenesisCodec.Marshal(block.CodecVersion, prefixStruct) - if err != nil { - return fmt.Errorf("failed to create prefix bytes: %w", err) - } - rawNestedWeightDiffDB := prefixdb.New(prefixBytes, s.nestedValidatorWeightDiffsDB) - nestedWeightDiffDB := linkeddb.NewDefault(rawNestedWeightDiffDB) - // Record the change in weight and/or public key for each validator. for nodeID, validatorDiff := range validatorDiffs { // Copy [nodeID] so it doesn't get overwritten next iteration. @@ -1936,7 +1856,7 @@ func (s *state) writeCurrentStakers(updateValidators bool, height uint64, codecV // Record that the public key for the validator is being // added. This means the prior value for the public key was // nil. - err := s.flatValidatorPublicKeyDiffsDB.Put( + err := s.validatorPublicKeyDiffsDB.Put( marshalDiffKey(constants.PrimaryNetworkID, height, nodeID), nil, ) @@ -1985,22 +1905,13 @@ func (s *state) writeCurrentStakers(updateValidators bool, height uint64, codecV // Note: We store the uncompressed public key here as it is // significantly more efficient to parse when applying // diffs. - err := s.flatValidatorPublicKeyDiffsDB.Put( + err := s.validatorPublicKeyDiffsDB.Put( marshalDiffKey(constants.PrimaryNetworkID, height, nodeID), bls.PublicKeyToUncompressedBytes(staker.PublicKey), ) if err != nil { return err } - - // TODO: Remove this once we no longer support version - // rollbacks. - // - // Note: We store the compressed public key here. - pkBytes := bls.PublicKeyToCompressedBytes(staker.PublicKey) - if err := nestedPKDiffDB.Put(nodeID.Bytes(), pkBytes); err != nil { - return err - } } if err := validatorDB.Delete(staker.TxID[:]); err != nil { @@ -2025,7 +1936,7 @@ func (s *state) writeCurrentStakers(updateValidators bool, height uint64, codecV continue } - err = s.flatValidatorWeightDiffsDB.Put( + err = s.validatorWeightDiffsDB.Put( marshalDiffKey(subnetID, height, nodeID), marshalWeightDiff(weightDiff), ) @@ -2033,15 +1944,6 @@ func (s *state) writeCurrentStakers(updateValidators bool, height uint64, codecV return err } - // TODO: Remove this once we no longer support version rollbacks. - weightDiffBytes, err := block.GenesisCodec.Marshal(block.CodecVersion, weightDiff) - if err != nil { - return fmt.Errorf("failed to serialize validator weight diff: %w", err) - } - if err := nestedWeightDiffDB.Put(nodeID.Bytes(), weightDiffBytes); err != nil { - return err - } - // TODO: Move the validator set management out of the state package if !updateValidators { continue @@ -2347,7 +2249,6 @@ func (s *state) writeMetadata() error { } s.persistedLastAccepted = s.lastAccepted } - if s.indexedHeights != nil { indexedHeightsBytes, err := block.GenesisCodec.Marshal(block.CodecVersion, s.indexedHeights) if err != nil { @@ -2357,6 +2258,5 @@ func (s *state) writeMetadata() error { return fmt.Errorf("failed to write indexed range: %w", err) } } - return nil } diff --git a/vms/platformvm/state/state_test.go b/vms/platformvm/state/state_test.go index e5eda2256f12..17343de5eb8f 100644 --- a/vms/platformvm/state/state_test.go +++ b/vms/platformvm/state/state_test.go @@ -163,7 +163,7 @@ func TestPersistStakers(t *testing.T) { r.Equal(lastUpdated, staker.StartTime) }, checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { - weightDiffBytes, err := s.flatValidatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) + weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) r.NoError(err) weightDiff, err := unmarshalWeightDiff(weightDiffBytes) r.NoError(err) @@ -172,7 +172,7 @@ func TestPersistStakers(t *testing.T) { Amount: staker.Weight, }, weightDiff) - blsDiffBytes, err := s.flatValidatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) + blsDiffBytes, err := s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) if staker.SubnetID == constants.PrimaryNetworkID { r.NoError(err) r.Nil(blsDiffBytes) @@ -261,7 +261,7 @@ func TestPersistStakers(t *testing.T) { checkValidatorUptimes: func(*require.Assertions, *state, *Staker) {}, checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { // validator's weight must increase of delegator's weight amount - weightDiffBytes, err := s.flatValidatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) + weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) r.NoError(err) weightDiff, err := unmarshalWeightDiff(weightDiffBytes) r.NoError(err) @@ -317,10 +317,10 @@ func TestPersistStakers(t *testing.T) { }, checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { // pending validators weight diff and bls diffs are not stored - _, err := s.flatValidatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) + _, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) r.ErrorIs(err, database.ErrNotFound) - _, err = s.flatValidatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) + _, err = s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) r.ErrorIs(err, database.ErrNotFound) }, }, @@ -438,7 +438,7 @@ func TestPersistStakers(t *testing.T) { r.ErrorIs(err, database.ErrNotFound) }, checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { - weightDiffBytes, err := s.flatValidatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) + weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) r.NoError(err) weightDiff, err := unmarshalWeightDiff(weightDiffBytes) r.NoError(err) @@ -447,7 +447,7 @@ func TestPersistStakers(t *testing.T) { Amount: staker.Weight, }, weightDiff) - blsDiffBytes, err := s.flatValidatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) + blsDiffBytes, err := s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) if staker.SubnetID == constants.PrimaryNetworkID { r.NoError(err) r.Equal(bls.PublicKeyFromValidUncompressedBytes(blsDiffBytes), staker.PublicKey) @@ -536,7 +536,7 @@ func TestPersistStakers(t *testing.T) { checkValidatorUptimes: func(*require.Assertions, *state, *Staker) {}, checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { // validator's weight must decrease of delegator's weight amount - weightDiffBytes, err := s.flatValidatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) + weightDiffBytes, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) r.NoError(err) weightDiff, err := unmarshalWeightDiff(weightDiffBytes) r.NoError(err) @@ -592,10 +592,10 @@ func TestPersistStakers(t *testing.T) { r.ErrorIs(err, database.ErrNotFound) }, checkDiffs: func(r *require.Assertions, s *state, staker *Staker, height uint64) { - _, err := s.flatValidatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) + _, err := s.validatorWeightDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) r.ErrorIs(err, database.ErrNotFound) - _, err = s.flatValidatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) + _, err = s.validatorPublicKeyDiffsDB.Get(marshalDiffKey(staker.SubnetID, height, staker.NodeID)) r.ErrorIs(err, database.ErrNotFound) }, },