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 }