github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/db/kv/state.go (about)

     1  package kv
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  
     7  	"github.com/pkg/errors"
     8  	types "github.com/prysmaticlabs/eth2-types"
     9  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    10  	"github.com/prysmaticlabs/prysm/beacon-chain/state/genesis"
    11  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    13  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    14  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    15  	"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
    16  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    17  	"github.com/prysmaticlabs/prysm/shared/params"
    18  	"github.com/prysmaticlabs/prysm/shared/traceutil"
    19  	bolt "go.etcd.io/bbolt"
    20  	"go.opencensus.io/trace"
    21  )
    22  
    23  // State returns the saved state using block's signing root,
    24  // this particular block was used to generate the state.
    25  func (s *Store) State(ctx context.Context, blockRoot [32]byte) (iface.BeaconState, error) {
    26  	ctx, span := trace.StartSpan(ctx, "BeaconDB.State")
    27  	defer span.End()
    28  	var st *pb.BeaconState
    29  	enc, err := s.stateBytes(ctx, blockRoot)
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  
    34  	if len(enc) == 0 {
    35  		return nil, nil
    36  	}
    37  
    38  	st, err = createState(ctx, enc)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	return v1.InitializeFromProtoUnsafe(st)
    43  }
    44  
    45  // GenesisState returns the genesis state in beacon chain.
    46  func (s *Store) GenesisState(ctx context.Context) (iface.BeaconState, error) {
    47  	ctx, span := trace.StartSpan(ctx, "BeaconDB.GenesisState")
    48  	defer span.End()
    49  
    50  	cached, err := genesis.State(params.BeaconConfig().ConfigName)
    51  	if err != nil {
    52  		traceutil.AnnotateError(span, err)
    53  		return nil, err
    54  	}
    55  	span.AddAttributes(trace.BoolAttribute("cache_hit", cached != nil))
    56  	if cached != nil {
    57  		return cached, nil
    58  	}
    59  
    60  	var st *pb.BeaconState
    61  	err = s.db.View(func(tx *bolt.Tx) error {
    62  		// Retrieve genesis block's signing root from blocks bucket,
    63  		// to look up what the genesis state is.
    64  		bucket := tx.Bucket(blocksBucket)
    65  		genesisBlockRoot := bucket.Get(genesisBlockRootKey)
    66  
    67  		bucket = tx.Bucket(stateBucket)
    68  		enc := bucket.Get(genesisBlockRoot)
    69  		if enc == nil {
    70  			return nil
    71  		}
    72  
    73  		var err error
    74  		st, err = createState(ctx, enc)
    75  		return err
    76  	})
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	if st == nil {
    81  		return nil, nil
    82  	}
    83  	return v1.InitializeFromProtoUnsafe(st)
    84  }
    85  
    86  // SaveState stores a state to the db using block's signing root which was used to generate the state.
    87  func (s *Store) SaveState(ctx context.Context, st iface.ReadOnlyBeaconState, blockRoot [32]byte) error {
    88  	ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveState")
    89  	defer span.End()
    90  
    91  	return s.SaveStates(ctx, []iface.ReadOnlyBeaconState{st}, [][32]byte{blockRoot})
    92  }
    93  
    94  // SaveStates stores multiple states to the db using the provided corresponding roots.
    95  func (s *Store) SaveStates(ctx context.Context, states []iface.ReadOnlyBeaconState, blockRoots [][32]byte) error {
    96  	ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveStates")
    97  	defer span.End()
    98  	if states == nil {
    99  		return errors.New("nil state")
   100  	}
   101  	multipleEncs := make([][]byte, len(states))
   102  	for i, st := range states {
   103  		pbState, err := v1.ProtobufBeaconState(st.InnerStateUnsafe())
   104  		if err != nil {
   105  			return err
   106  		}
   107  		multipleEncs[i], err = encode(ctx, pbState)
   108  		if err != nil {
   109  			return err
   110  		}
   111  	}
   112  
   113  	return s.db.Update(func(tx *bolt.Tx) error {
   114  		bucket := tx.Bucket(stateBucket)
   115  		for i, rt := range blockRoots {
   116  			indicesByBucket := createStateIndicesFromStateSlot(ctx, states[i].Slot())
   117  			if err := updateValueForIndices(ctx, indicesByBucket, rt[:], tx); err != nil {
   118  				return errors.Wrap(err, "could not update DB indices")
   119  			}
   120  			if err := bucket.Put(rt[:], multipleEncs[i]); err != nil {
   121  				return err
   122  			}
   123  		}
   124  		return nil
   125  	})
   126  }
   127  
   128  // HasState checks if a state by root exists in the db.
   129  func (s *Store) HasState(ctx context.Context, blockRoot [32]byte) bool {
   130  	ctx, span := trace.StartSpan(ctx, "BeaconDB.HasState")
   131  	defer span.End()
   132  	hasState := false
   133  	err := s.db.View(func(tx *bolt.Tx) error {
   134  		bkt := tx.Bucket(stateBucket)
   135  		stBytes := bkt.Get(blockRoot[:])
   136  		if len(stBytes) > 0 {
   137  			hasState = true
   138  		}
   139  		return nil
   140  	})
   141  	if err != nil {
   142  		panic(err)
   143  	}
   144  	return hasState
   145  }
   146  
   147  // DeleteState by block root.
   148  func (s *Store) DeleteState(ctx context.Context, blockRoot [32]byte) error {
   149  	ctx, span := trace.StartSpan(ctx, "BeaconDB.DeleteState")
   150  	defer span.End()
   151  
   152  	return s.db.Update(func(tx *bolt.Tx) error {
   153  		bkt := tx.Bucket(blocksBucket)
   154  		genesisBlockRoot := bkt.Get(genesisBlockRootKey)
   155  
   156  		bkt = tx.Bucket(checkpointBucket)
   157  		enc := bkt.Get(finalizedCheckpointKey)
   158  		checkpoint := &ethpb.Checkpoint{}
   159  		if enc == nil {
   160  			checkpoint = &ethpb.Checkpoint{Root: genesisBlockRoot}
   161  		} else if err := decode(ctx, enc, checkpoint); err != nil {
   162  			return err
   163  		}
   164  
   165  		blockBkt := tx.Bucket(blocksBucket)
   166  		headBlkRoot := blockBkt.Get(headBlockRootKey)
   167  		bkt = tx.Bucket(stateBucket)
   168  		// Safe guard against deleting genesis, finalized, head state.
   169  		if bytes.Equal(blockRoot[:], checkpoint.Root) || bytes.Equal(blockRoot[:], genesisBlockRoot) || bytes.Equal(blockRoot[:], headBlkRoot) {
   170  			return errors.New("cannot delete genesis, finalized, or head state")
   171  		}
   172  
   173  		slot, err := slotByBlockRoot(ctx, tx, blockRoot[:])
   174  		if err != nil {
   175  			return err
   176  		}
   177  		indicesByBucket := createStateIndicesFromStateSlot(ctx, slot)
   178  		if err := deleteValueForIndices(ctx, indicesByBucket, blockRoot[:], tx); err != nil {
   179  			return errors.Wrap(err, "could not delete root for DB indices")
   180  		}
   181  
   182  		return bkt.Delete(blockRoot[:])
   183  	})
   184  }
   185  
   186  // DeleteStates by block roots.
   187  func (s *Store) DeleteStates(ctx context.Context, blockRoots [][32]byte) error {
   188  	ctx, span := trace.StartSpan(ctx, "BeaconDB.DeleteStates")
   189  	defer span.End()
   190  
   191  	for _, r := range blockRoots {
   192  		if err := s.DeleteState(ctx, r); err != nil {
   193  			return err
   194  		}
   195  	}
   196  
   197  	return nil
   198  }
   199  
   200  // creates state from marshaled proto state bytes.
   201  func createState(ctx context.Context, enc []byte) (*pb.BeaconState, error) {
   202  	protoState := &pb.BeaconState{}
   203  	if err := decode(ctx, enc, protoState); err != nil {
   204  		return nil, errors.Wrap(err, "failed to unmarshal encoding")
   205  	}
   206  	return protoState, nil
   207  }
   208  
   209  // HasState checks if a state by root exists in the db.
   210  func (s *Store) stateBytes(ctx context.Context, blockRoot [32]byte) ([]byte, error) {
   211  	ctx, span := trace.StartSpan(ctx, "BeaconDB.stateBytes")
   212  	defer span.End()
   213  	var dst []byte
   214  	err := s.db.View(func(tx *bolt.Tx) error {
   215  		bkt := tx.Bucket(stateBucket)
   216  		stBytes := bkt.Get(blockRoot[:])
   217  		if len(stBytes) == 0 {
   218  			return nil
   219  		}
   220  		// Due to https://github.com/boltdb/bolt/issues/204, we need to
   221  		// allocate a byte slice separately in the transaction or there
   222  		// is the possibility of a panic when accessing that particular
   223  		// area of memory.
   224  		dst = make([]byte, len(stBytes))
   225  		copy(dst, stBytes)
   226  		return nil
   227  	})
   228  	return dst, err
   229  }
   230  
   231  // slotByBlockRoot retrieves the corresponding slot of the input block root.
   232  func slotByBlockRoot(ctx context.Context, tx *bolt.Tx, blockRoot []byte) (types.Slot, error) {
   233  	ctx, span := trace.StartSpan(ctx, "BeaconDB.slotByBlockRoot")
   234  	defer span.End()
   235  
   236  	bkt := tx.Bucket(stateSummaryBucket)
   237  	enc := bkt.Get(blockRoot)
   238  
   239  	if enc == nil {
   240  		// Fall back to check the block.
   241  		bkt := tx.Bucket(blocksBucket)
   242  		enc := bkt.Get(blockRoot)
   243  
   244  		if enc == nil {
   245  			// Fallback and check the state.
   246  			bkt = tx.Bucket(stateBucket)
   247  			enc = bkt.Get(blockRoot)
   248  			if enc == nil {
   249  				return 0, errors.New("state enc can't be nil")
   250  			}
   251  			s, err := createState(ctx, enc)
   252  			if err != nil {
   253  				return 0, err
   254  			}
   255  			if s == nil {
   256  				return 0, errors.New("state can't be nil")
   257  			}
   258  			return s.Slot, nil
   259  		}
   260  		b := &ethpb.SignedBeaconBlock{}
   261  		err := decode(ctx, enc, b)
   262  		if err != nil {
   263  			return 0, err
   264  		}
   265  		if err := helpers.VerifyNilBeaconBlock(wrapper.WrappedPhase0SignedBeaconBlock(b)); err != nil {
   266  			return 0, err
   267  		}
   268  		return b.Block.Slot, nil
   269  	}
   270  	stateSummary := &pb.StateSummary{}
   271  	if err := decode(ctx, enc, stateSummary); err != nil {
   272  		return 0, err
   273  	}
   274  	return stateSummary.Slot, nil
   275  }
   276  
   277  // HighestSlotStatesBelow returns the states with the highest slot below the input slot
   278  // from the db. Ideally there should just be one state per slot, but given validator
   279  // can double propose, a single slot could have multiple block roots and
   280  // results states. This returns a list of states.
   281  func (s *Store) HighestSlotStatesBelow(ctx context.Context, slot types.Slot) ([]iface.ReadOnlyBeaconState, error) {
   282  	ctx, span := trace.StartSpan(ctx, "BeaconDB.HighestSlotStatesBelow")
   283  	defer span.End()
   284  
   285  	var best []byte
   286  	if err := s.db.View(func(tx *bolt.Tx) error {
   287  		bkt := tx.Bucket(stateSlotIndicesBucket)
   288  		c := bkt.Cursor()
   289  		for s, root := c.First(); s != nil; s, root = c.Next() {
   290  			if ctx.Err() != nil {
   291  				return ctx.Err()
   292  			}
   293  			key := bytesutil.BytesToSlotBigEndian(s)
   294  			if root == nil {
   295  				continue
   296  			}
   297  			if key >= slot {
   298  				break
   299  			}
   300  			best = root
   301  		}
   302  		return nil
   303  	}); err != nil {
   304  		return nil, err
   305  	}
   306  
   307  	var st iface.ReadOnlyBeaconState
   308  	var err error
   309  	if best != nil {
   310  		st, err = s.State(ctx, bytesutil.ToBytes32(best))
   311  		if err != nil {
   312  			return nil, err
   313  		}
   314  	}
   315  	if st == nil || st.IsNil() {
   316  		st, err = s.GenesisState(ctx)
   317  		if err != nil {
   318  			return nil, err
   319  		}
   320  	}
   321  
   322  	return []iface.ReadOnlyBeaconState{st}, nil
   323  }
   324  
   325  // createStateIndicesFromStateSlot takes in a state slot and returns
   326  // a map of bolt DB index buckets corresponding to each particular key for indices for
   327  // data, such as (shard indices bucket -> shard 5).
   328  func createStateIndicesFromStateSlot(ctx context.Context, slot types.Slot) map[string][]byte {
   329  	ctx, span := trace.StartSpan(ctx, "BeaconDB.createStateIndicesFromState")
   330  	defer span.End()
   331  	indicesByBucket := make(map[string][]byte)
   332  	// Every index has a unique bucket for fast, binary-search
   333  	// range scans for filtering across keys.
   334  	buckets := [][]byte{
   335  		stateSlotIndicesBucket,
   336  	}
   337  
   338  	indices := [][]byte{
   339  		bytesutil.SlotToBytesBigEndian(slot),
   340  	}
   341  	for i := 0; i < len(buckets); i++ {
   342  		indicesByBucket[string(buckets[i])] = indices[i]
   343  	}
   344  	return indicesByBucket
   345  }
   346  
   347  // CleanUpDirtyStates removes states in DB that falls to under archived point interval rules.
   348  // Only following states would be kept:
   349  // 1.) state_slot % archived_interval == 0. (e.g. archived_interval=2048, states with slot 2048, 4096... etc)
   350  // 2.) archived_interval - archived_interval/3 < state_slot % archived_interval
   351  //   (e.g. archived_interval=2048, states with slots after 1365).
   352  //   This is to tolerate skip slots. Not every state lays on the boundary.
   353  // 3.) state with current finalized root
   354  // 4.) unfinalized States
   355  func (s *Store) CleanUpDirtyStates(ctx context.Context, slotsPerArchivedPoint types.Slot) error {
   356  	ctx, span := trace.StartSpan(ctx, "BeaconDB. CleanUpDirtyStates")
   357  	defer span.End()
   358  
   359  	f, err := s.FinalizedCheckpoint(ctx)
   360  	if err != nil {
   361  		return err
   362  	}
   363  	finalizedSlot, err := helpers.StartSlot(f.Epoch)
   364  	if err != nil {
   365  		return err
   366  	}
   367  	deletedRoots := make([][32]byte, 0)
   368  
   369  	err = s.db.View(func(tx *bolt.Tx) error {
   370  		bkt := tx.Bucket(stateSlotIndicesBucket)
   371  		return bkt.ForEach(func(k, v []byte) error {
   372  			if ctx.Err() != nil {
   373  				return ctx.Err()
   374  			}
   375  
   376  			finalizedChkpt := bytesutil.ToBytes32(f.Root) == bytesutil.ToBytes32(v)
   377  			slot := bytesutil.BytesToSlotBigEndian(k)
   378  			mod := slot % slotsPerArchivedPoint
   379  			nonFinalized := slot > finalizedSlot
   380  
   381  			// The following conditions cover 1, 2, 3 and 4 above.
   382  			if mod != 0 && mod <= slotsPerArchivedPoint-slotsPerArchivedPoint/3 && !finalizedChkpt && !nonFinalized {
   383  				deletedRoots = append(deletedRoots, bytesutil.ToBytes32(v))
   384  			}
   385  			return nil
   386  		})
   387  	})
   388  	if err != nil {
   389  		return err
   390  	}
   391  
   392  	// Length of to be deleted roots is 0. Nothing to do.
   393  	if len(deletedRoots) == 0 {
   394  		return nil
   395  	}
   396  
   397  	log.WithField("count", len(deletedRoots)).Info("Cleaning up dirty states")
   398  	if err := s.DeleteStates(ctx, deletedRoots); err != nil {
   399  		return err
   400  	}
   401  
   402  	return err
   403  }