github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/execution/state/state.go (about) 1 // Copyright Monax Industries Limited 2 // SPDX-License-Identifier: Apache-2.0 3 4 package state 5 6 import ( 7 "crypto/sha256" 8 "fmt" 9 "sync" 10 11 "github.com/hyperledger/burrow/execution/registry" 12 13 "github.com/hyperledger/burrow/acm" 14 "github.com/hyperledger/burrow/acm/acmstate" 15 "github.com/hyperledger/burrow/acm/validator" 16 "github.com/hyperledger/burrow/binary" 17 "github.com/hyperledger/burrow/crypto" 18 "github.com/hyperledger/burrow/execution/exec" 19 "github.com/hyperledger/burrow/execution/names" 20 "github.com/hyperledger/burrow/execution/proposal" 21 "github.com/hyperledger/burrow/genesis" 22 "github.com/hyperledger/burrow/logging" 23 "github.com/hyperledger/burrow/storage" 24 "github.com/hyperledger/burrow/txs" 25 dbm "github.com/tendermint/tm-db" 26 ) 27 28 const ( 29 DefaultValidatorsWindowSize = 10 30 defaultCacheCapacity = 1024 31 uint64Length = 8 32 // Prefix under which the versioned merkle state tree resides - tracking previous versions of history 33 forestPrefix = "f" 34 // Prefix for storage outside for the merkel tree - does not contribute to AppHash as a result 35 // Leaving the forest for the plains like early members of the homo genus 36 plainPrefix = "h" 37 ) 38 39 // Implements account and blockchain state 40 var _ acmstate.IterableReader = &State{} 41 var _ names.IterableReader = &State{} 42 var _ Updatable = &writeState{} 43 44 type KeyFormatStore struct { 45 Account *storage.MustKeyFormat 46 Storage *storage.MustKeyFormat 47 Name *storage.MustKeyFormat 48 Proposal *storage.MustKeyFormat 49 Validator *storage.MustKeyFormat 50 Event *storage.MustKeyFormat 51 Registry *storage.MustKeyFormat 52 TxHash *storage.MustKeyFormat 53 Abi *storage.MustKeyFormat 54 } 55 56 var keys = KeyFormatStore{ 57 // Stored in the forest 58 // AccountAddress -> Account 59 Account: storage.NewMustKeyFormat("a", crypto.AddressLength), 60 // AccountAddress, Key -> Value 61 Storage: storage.NewMustKeyFormat("s", crypto.AddressLength, binary.Word256Bytes), 62 // Name -> Entry 63 Name: storage.NewMustKeyFormat("n", storage.VariadicSegmentLength), 64 // ProposalHash -> Proposal 65 Proposal: storage.NewMustKeyFormat("p", sha256.Size), 66 // ValidatorAddress -> Power 67 Validator: storage.NewMustKeyFormat("v", crypto.AddressLength), 68 // Height -> StreamEvent 69 Event: storage.NewMustKeyFormat("e", uint64Length), 70 // Validator -> NodeIdentity 71 Registry: storage.NewMustKeyFormat("r", crypto.AddressLength), 72 73 // Stored on the plain 74 // TxHash -> TxHeight, TxIndex 75 TxHash: storage.NewMustKeyFormat("th", txs.HashLength), 76 // CodeHash -> Abi 77 Abi: storage.NewMustKeyFormat("abi", sha256.Size), 78 } 79 80 var Prefixes [][]byte 81 82 func init() { 83 var err error 84 Prefixes, err = storage.EnsureKeyFormatStore(keys) 85 if err != nil { 86 panic(fmt.Errorf("KeyFormatStore is invalid: %v", err)) 87 } 88 } 89 90 type Updatable interface { 91 acmstate.Writer 92 names.Writer 93 proposal.Writer 94 registry.Writer 95 validator.Writer 96 acmstate.MetadataWriter 97 AddBlock(blockExecution *exec.BlockExecution) error 98 } 99 100 // Wraps state to give access to writer methods 101 type writeState struct { 102 forest *storage.MutableForest 103 plain *storage.PrefixDB 104 ring *validator.Ring 105 accountStats acmstate.AccountStats 106 nodeStats registry.NodeStats 107 } 108 109 // This is the immutable merklised read state at a given finalised height 110 type ImmutableState struct { 111 Forest storage.ForestReader 112 validator.History 113 } 114 115 type ReadState struct { 116 ImmutableState 117 Plain *storage.PrefixDB 118 } 119 120 // Writers to state are responsible for calling State.Lock() before calling 121 type State struct { 122 sync.Mutex 123 db dbm.DB 124 ReadState 125 writeState writeState 126 logger *logging.Logger 127 } 128 129 // NewState creates a new State object 130 func NewState(db dbm.DB) *State { 131 forest, err := storage.NewMutableForest(storage.NewPrefixDB(db, forestPrefix), defaultCacheCapacity) 132 if err != nil { 133 // This should only happen if we have negative cache capacity, which for us is a positive compile-time constant 134 panic(fmt.Errorf("could not create new state because error creating MutableForest")) 135 } 136 plain := storage.NewPrefixDB(db, plainPrefix) 137 ring := validator.NewRing(nil, DefaultValidatorsWindowSize) 138 return &State{ 139 db: db, 140 ReadState: ReadState{ 141 ImmutableState: ImmutableState{ 142 Forest: forest, 143 History: ring, 144 }, 145 Plain: plain, 146 }, 147 writeState: writeState{ 148 forest: forest, 149 plain: plain, 150 ring: ring, 151 nodeStats: registry.NewNodeStats(), 152 }, 153 logger: logging.NewNoopLogger(), 154 } 155 } 156 157 // Make genesis state from GenesisDoc and save to DB 158 func MakeGenesisState(db dbm.DB, genesisDoc *genesis.GenesisDoc) (*State, error) { 159 s := NewState(db) 160 161 const errHeader = "MakeGenesisState():" 162 // Make accounts state tree 163 for _, genAcc := range genesisDoc.Accounts { 164 perm := genAcc.Permissions 165 acc := &acm.Account{ 166 Address: genAcc.Address, 167 Balance: genAcc.Amount, 168 Permissions: perm, 169 } 170 err := s.writeState.UpdateAccount(acc) 171 if err != nil { 172 return nil, fmt.Errorf("%s %v", errHeader, err) 173 } 174 } 175 // Make genesis validators 176 err := s.writeState.MakeGenesisValidators(genesisDoc) 177 if err != nil { 178 return nil, fmt.Errorf("%s %v", errHeader, err) 179 } 180 // Set up fallback global permissions 181 err = s.writeState.UpdateAccount(genesisDoc.GlobalPermissionsAccount()) 182 if err != nil { 183 return nil, fmt.Errorf("%s %v", errHeader, err) 184 } 185 186 return s, nil 187 } 188 189 func (s *State) InitialCommit() error { 190 _, version, err := s.commit() 191 if err != nil { 192 return fmt.Errorf("could not save initial state: %v", err) 193 } 194 if version != VersionOffset { 195 return fmt.Errorf("initial state got version %d after committing genesis state but version offset should be %d", 196 version, VersionOffset) 197 } 198 return nil 199 } 200 201 // Tries to load the execution state from DB, returns nil with no error if no state found 202 func LoadState(db dbm.DB, version int64) (*State, error) { 203 s := NewState(db) 204 err := s.writeState.forest.Load(version) 205 if err != nil { 206 return nil, fmt.Errorf("could not load MutableForest at version %d: %v", version, err) 207 } 208 209 // Populate stats. If this starts taking too long, store the value rather than the full scan at startup 210 err = s.loadAccountStats() 211 if err != nil { 212 return nil, err 213 } 214 215 err = s.loadNodeStats() 216 if err != nil { 217 return nil, err 218 } 219 220 // load the validator ring 221 ring, err := LoadValidatorRing(version, DefaultValidatorsWindowSize, s.writeState.forest.GetImmutable) 222 if err != nil { 223 return nil, err 224 } 225 s.writeState.ring = ring 226 s.ReadState.History = ring 227 228 return s, nil 229 } 230 231 func (s *State) loadAccountStats() error { 232 return s.IterateAccounts(func(acc *acm.Account) error { 233 if len(acc.EVMCode) > 0 || len(acc.WASMCode) > 0 { 234 s.writeState.accountStats.AccountsWithCode++ 235 } else { 236 s.writeState.accountStats.AccountsWithoutCode++ 237 } 238 return nil 239 }) 240 } 241 242 func (s *State) loadNodeStats() error { 243 return s.IterateNodes(func(id crypto.Address, node *registry.NodeIdentity) error { 244 s.writeState.nodeStats.Addresses[node.GetNetworkAddress()][id] = struct{}{} 245 return nil 246 }) 247 } 248 249 func (s *State) Version() int64 { 250 return s.writeState.forest.Version() 251 } 252 253 func (s *State) Hash() []byte { 254 return s.writeState.forest.Hash() 255 } 256 257 func (s *State) AtLatestVersion() (*ImmutableState, error) { 258 return s.AtVersion(s.Version()) 259 } 260 261 // Return a concurrent-safe immutable read state at the given height 262 func (s *State) AtHeight(height uint64) (*ImmutableState, error) { 263 return s.AtVersion(VersionAtHeight(height)) 264 } 265 266 // Return a concurrent-safe immutable read state at the given version 267 func (s *State) AtVersion(version int64) (*ImmutableState, error) { 268 forest, err := s.writeState.forest.GetImmutable(version) 269 if err != nil { 270 return nil, err 271 } 272 ring, err := LoadValidatorRing(version, DefaultValidatorsWindowSize, s.writeState.forest.GetImmutable) 273 if err != nil { 274 return nil, err 275 } 276 return &ImmutableState{ 277 Forest: forest, 278 History: ring, 279 }, nil 280 } 281 282 // Perform updates to state whilst holding the write lock, allows a commit to hold the write lock across multiple 283 // operations while preventing interlaced reads and writes 284 func (s *State) Update(updater func(up Updatable) error) ([]byte, int64, error) { 285 s.Lock() 286 defer s.Unlock() 287 err := updater(&s.writeState) 288 if err != nil { 289 return nil, 0, err 290 } 291 return s.commit() 292 } 293 294 func (s *State) commit() ([]byte, int64, error) { 295 // save state at a new version may still be orphaned before we save the version against the hash 296 hash, version, err := s.writeState.forest.Save() 297 if err != nil { 298 return nil, 0, err 299 } 300 totalPowerChange, totalFlow, err := s.writeState.ring.Rotate() 301 if err != nil { 302 return nil, 0, err 303 } 304 if totalFlow.Sign() != 0 { 305 //noinspection ALL 306 s.logger.InfoMsg("validator set changes", "total_power_change", totalPowerChange, "total_flow", totalFlow) 307 } 308 return hash, version, err 309 } 310 311 // Creates a copy of the database to the supplied db 312 func (s *State) Copy(db dbm.DB) (*State, error) { 313 stateCopy := NewState(db) 314 err := s.writeState.forest.IterateRWTree(nil, nil, true, 315 func(prefix []byte, tree *storage.RWTree) error { 316 return stateCopy.writeState.forest.Write(prefix, func(treeCopy *storage.RWTree) error { 317 return tree.IterateWriteTree(nil, nil, true, func(key []byte, value []byte) error { 318 treeCopy.Set(key, value) 319 return nil 320 }) 321 }) 322 }) 323 if err != nil { 324 return nil, err 325 } 326 _, _, err = stateCopy.commit() 327 if err != nil { 328 return nil, err 329 } 330 return stateCopy, nil 331 } 332 333 func (s *State) SetLogger(logger *logging.Logger) { 334 s.logger = logger 335 } 336 337 func (s *State) Dump() string { 338 return s.writeState.forest.Dump() 339 }