github.com/koko1123/flow-go-1@v0.29.6/storage/badger/dkg_state.go (about)

     1  package badger
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/dgraph-io/badger/v3"
     7  
     8  	"github.com/koko1123/flow-go-1/model/encodable"
     9  	"github.com/koko1123/flow-go-1/model/flow"
    10  	"github.com/koko1123/flow-go-1/module"
    11  	"github.com/koko1123/flow-go-1/module/metrics"
    12  	"github.com/koko1123/flow-go-1/storage/badger/operation"
    13  	"github.com/koko1123/flow-go-1/storage/badger/transaction"
    14  	"github.com/onflow/flow-go/crypto"
    15  )
    16  
    17  // DKGState stores state information about in-progress and completed DKGs, including
    18  // computed keys. Must be instantiated using secrets database.
    19  type DKGState struct {
    20  	db       *badger.DB
    21  	keyCache *Cache
    22  }
    23  
    24  // NewDKGState returns the DKGState implementation backed by Badger DB.
    25  func NewDKGState(collector module.CacheMetrics, db *badger.DB) (*DKGState, error) {
    26  	err := operation.EnsureSecretDB(db)
    27  	if err != nil {
    28  		return nil, fmt.Errorf("cannot instantiate dkg state storage in non-secret db: %w", err)
    29  	}
    30  
    31  	storeKey := func(key interface{}, val interface{}) func(*transaction.Tx) error {
    32  		epochCounter := key.(uint64)
    33  		info := val.(*encodable.RandomBeaconPrivKey)
    34  		return transaction.WithTx(operation.InsertMyBeaconPrivateKey(epochCounter, info))
    35  	}
    36  
    37  	retrieveKey := func(key interface{}) func(*badger.Txn) (interface{}, error) {
    38  		epochCounter := key.(uint64)
    39  		var info encodable.RandomBeaconPrivKey
    40  		return func(tx *badger.Txn) (interface{}, error) {
    41  			err := operation.RetrieveMyBeaconPrivateKey(epochCounter, &info)(tx)
    42  			return &info, err
    43  		}
    44  	}
    45  
    46  	cache := newCache(collector, metrics.ResourceBeaconKey,
    47  		withLimit(10),
    48  		withStore(storeKey),
    49  		withRetrieve(retrieveKey),
    50  	)
    51  
    52  	dkgState := &DKGState{
    53  		db:       db,
    54  		keyCache: cache,
    55  	}
    56  
    57  	return dkgState, nil
    58  }
    59  
    60  func (ds *DKGState) storeKeyTx(epochCounter uint64, key *encodable.RandomBeaconPrivKey) func(tx *transaction.Tx) error {
    61  	return ds.keyCache.PutTx(epochCounter, key)
    62  }
    63  
    64  func (ds *DKGState) retrieveKeyTx(epochCounter uint64) func(tx *badger.Txn) (*encodable.RandomBeaconPrivKey, error) {
    65  	return func(tx *badger.Txn) (*encodable.RandomBeaconPrivKey, error) {
    66  		val, err := ds.keyCache.Get(epochCounter)(tx)
    67  		if err != nil {
    68  			return nil, err
    69  		}
    70  		return val.(*encodable.RandomBeaconPrivKey), nil
    71  	}
    72  }
    73  
    74  // InsertMyBeaconPrivateKey stores the random beacon private key for an epoch.
    75  //
    76  // CAUTION: these keys are stored before they are validated against the
    77  // canonical key vector and may not be valid for use in signing. Use SafeBeaconKeys
    78  // to guarantee only keys safe for signing are returned
    79  func (ds *DKGState) InsertMyBeaconPrivateKey(epochCounter uint64, key crypto.PrivateKey) error {
    80  	if key == nil {
    81  		return fmt.Errorf("will not store nil beacon key")
    82  	}
    83  	encodableKey := &encodable.RandomBeaconPrivKey{PrivateKey: key}
    84  	return operation.RetryOnConflictTx(ds.db, transaction.Update, ds.storeKeyTx(epochCounter, encodableKey))
    85  }
    86  
    87  // RetrieveMyBeaconPrivateKey retrieves the random beacon private key for an epoch.
    88  //
    89  // CAUTION: these keys are stored before they are validated against the
    90  // canonical key vector and may not be valid for use in signing. Use SafeBeaconKeys
    91  // to guarantee only keys safe for signing are returned
    92  func (ds *DKGState) RetrieveMyBeaconPrivateKey(epochCounter uint64) (crypto.PrivateKey, error) {
    93  	tx := ds.db.NewTransaction(false)
    94  	defer tx.Discard()
    95  	encodableKey, err := ds.retrieveKeyTx(epochCounter)(tx)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	return encodableKey.PrivateKey, nil
   100  }
   101  
   102  // SetDKGStarted sets the flag indicating the DKG has started for the given epoch.
   103  func (ds *DKGState) SetDKGStarted(epochCounter uint64) error {
   104  	return ds.db.Update(operation.InsertDKGStartedForEpoch(epochCounter))
   105  }
   106  
   107  // GetDKGStarted checks whether the DKG has been started for the given epoch.
   108  func (ds *DKGState) GetDKGStarted(epochCounter uint64) (bool, error) {
   109  	var started bool
   110  	err := ds.db.View(operation.RetrieveDKGStartedForEpoch(epochCounter, &started))
   111  	return started, err
   112  }
   113  
   114  // SetDKGEndState stores that the DKG has ended, and its end state.
   115  func (ds *DKGState) SetDKGEndState(epochCounter uint64, endState flow.DKGEndState) error {
   116  	return ds.db.Update(operation.InsertDKGEndStateForEpoch(epochCounter, endState))
   117  }
   118  
   119  // GetDKGEndState retrieves the DKG end state for the epoch.
   120  func (ds *DKGState) GetDKGEndState(epochCounter uint64) (flow.DKGEndState, error) {
   121  	var endState flow.DKGEndState
   122  	err := ds.db.Update(operation.RetrieveDKGEndStateForEpoch(epochCounter, &endState))
   123  	return endState, err
   124  }
   125  
   126  // SafeBeaconPrivateKeys is the safe beacon key storage backed by Badger DB.
   127  type SafeBeaconPrivateKeys struct {
   128  	state *DKGState
   129  }
   130  
   131  // NewSafeBeaconPrivateKeys returns a safe beacon key storage backed by Badger DB.
   132  func NewSafeBeaconPrivateKeys(state *DKGState) *SafeBeaconPrivateKeys {
   133  	return &SafeBeaconPrivateKeys{state: state}
   134  }
   135  
   136  // RetrieveMyBeaconPrivateKey retrieves my beacon private key for the given
   137  // epoch, only if my key has been confirmed valid and safe for use.
   138  //
   139  // Returns:
   140  // * (key, true, nil) if the key is present and confirmed valid
   141  // * (nil, false, nil) if the key has been marked invalid (by SetDKGEnded)
   142  // * (nil, false, error) for any other condition, or exception
   143  func (keys *SafeBeaconPrivateKeys) RetrieveMyBeaconPrivateKey(epochCounter uint64) (key crypto.PrivateKey, safe bool, err error) {
   144  	err = keys.state.db.View(func(txn *badger.Txn) error {
   145  
   146  		// retrieve the end state, error on any storage error (including not found)
   147  		var endState flow.DKGEndState
   148  		err = operation.RetrieveDKGEndStateForEpoch(epochCounter, &endState)(txn)
   149  		if err != nil {
   150  			key = nil
   151  			safe = false
   152  			return err
   153  		}
   154  
   155  		// for any end state besides success, the key is not safe
   156  		if endState != flow.DKGEndStateSuccess {
   157  			key = nil
   158  			safe = false
   159  			return nil
   160  		}
   161  
   162  		// retrieve the key, error on any storage error
   163  		var encodableKey *encodable.RandomBeaconPrivKey
   164  		encodableKey, err = keys.state.retrieveKeyTx(epochCounter)(txn)
   165  		if err != nil {
   166  			key = nil
   167  			safe = false
   168  			return err
   169  		}
   170  
   171  		// return the key only for successful end state
   172  		safe = true
   173  		key = encodableKey.PrivateKey
   174  		return nil
   175  	})
   176  	return
   177  }