github.com/datachainlab/burrow@v0.25.0/execution/state/state.go (about) 1 // Copyright 2017 Monax Industries Limited 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package state 16 17 import ( 18 "crypto/sha256" 19 "fmt" 20 "sync" 21 22 "github.com/hyperledger/burrow/acm" 23 "github.com/hyperledger/burrow/acm/acmstate" 24 "github.com/hyperledger/burrow/acm/validator" 25 "github.com/hyperledger/burrow/binary" 26 "github.com/hyperledger/burrow/crypto" 27 "github.com/hyperledger/burrow/execution/exec" 28 "github.com/hyperledger/burrow/execution/names" 29 "github.com/hyperledger/burrow/execution/proposal" 30 "github.com/hyperledger/burrow/genesis" 31 "github.com/hyperledger/burrow/logging" 32 "github.com/hyperledger/burrow/permission" 33 "github.com/hyperledger/burrow/storage" 34 "github.com/hyperledger/burrow/txs" 35 dbm "github.com/tendermint/tendermint/libs/db" 36 ) 37 38 const ( 39 DefaultValidatorsWindowSize = 10 40 defaultCacheCapacity = 1024 41 uint64Length = 8 42 // Prefix under which the versioned merkle state tree resides - tracking previous versions of history 43 forestPrefix = "f" 44 ) 45 46 // Implements account and blockchain state 47 var _ acmstate.IterableReader = &State{} 48 var _ names.IterableReader = &State{} 49 var _ Updatable = &writeState{} 50 51 type KeyFormatStore struct { 52 Account *storage.MustKeyFormat 53 Storage *storage.MustKeyFormat 54 Name *storage.MustKeyFormat 55 Proposal *storage.MustKeyFormat 56 Validator *storage.MustKeyFormat 57 Event *storage.MustKeyFormat 58 TxHash *storage.MustKeyFormat 59 } 60 61 var keys = KeyFormatStore{ 62 // AccountAddress -> Account 63 Account: storage.NewMustKeyFormat("a", crypto.AddressLength), 64 // AccountAddress, Key -> Value 65 Storage: storage.NewMustKeyFormat("s", crypto.AddressLength, binary.Word256Length), 66 // Name -> Entry 67 Name: storage.NewMustKeyFormat("n", storage.VariadicSegmentLength), 68 // ProposalHash -> Proposal 69 Proposal: storage.NewMustKeyFormat("p", sha256.Size), 70 // ValidatorAddress -> Power 71 Validator: storage.NewMustKeyFormat("v", crypto.AddressLength), 72 // Height, EventIndex -> StreamEvent 73 Event: storage.NewMustKeyFormat("e", uint64Length, uint64Length), 74 // TxHash -> TxHeight, TxIndex 75 TxHash: storage.NewMustKeyFormat("th", txs.HashLength), 76 } 77 78 func init() { 79 err := storage.EnsureKeyFormatStore(keys) 80 if err != nil { 81 panic(fmt.Errorf("KeyFormatStore is invalid: %v", err)) 82 } 83 } 84 85 type Updatable interface { 86 acmstate.Writer 87 names.Writer 88 proposal.Writer 89 validator.Writer 90 AddBlock(blockExecution *exec.BlockExecution) error 91 } 92 93 // Wraps state to give access to writer methods 94 type writeState struct { 95 forest *storage.MutableForest 96 accountStats acmstate.AccountStats 97 ring *validator.Ring 98 } 99 100 type ReadState struct { 101 Forest storage.ForestReader 102 validator.History 103 } 104 105 // Writers to state are responsible for calling State.Lock() before calling 106 type State struct { 107 sync.Mutex 108 db dbm.DB 109 ReadState 110 writeState writeState 111 logger *logging.Logger 112 } 113 114 // Create a new State object 115 func NewState(db dbm.DB) *State { 116 forest, err := storage.NewMutableForest(storage.NewPrefixDB(db, forestPrefix), defaultCacheCapacity) 117 if err != nil { 118 // This should only happen if we have negative cache capacity, which for us is a positive compile-time constant 119 panic(fmt.Errorf("could not create new state because error creating MutableForest")) 120 } 121 ring := validator.NewRing(nil, DefaultValidatorsWindowSize) 122 rs := ReadState{Forest: forest, History: ring} 123 ws := writeState{forest: forest, ring: ring} 124 return &State{ 125 db: db, 126 ReadState: rs, 127 writeState: ws, 128 logger: logging.NewNoopLogger(), 129 } 130 } 131 132 // Make genesis state from GenesisDoc and save to DB 133 func MakeGenesisState(db dbm.DB, genesisDoc *genesis.GenesisDoc) (*State, error) { 134 s := NewState(db) 135 136 const errHeader = "MakeGenesisState():" 137 // Make accounts state tree 138 for _, genAcc := range genesisDoc.Accounts { 139 perm := genAcc.Permissions 140 acc := &acm.Account{ 141 Address: genAcc.Address, 142 Balance: genAcc.Amount, 143 Permissions: perm, 144 } 145 err := s.writeState.UpdateAccount(acc) 146 if err != nil { 147 return nil, fmt.Errorf("%s %v", errHeader, err) 148 } 149 } 150 // Make genesis validators 151 err := s.writeState.MakeGenesisValidators(genesisDoc) 152 if err != nil { 153 return nil, fmt.Errorf("%s %v", errHeader, err) 154 } 155 // global permissions are saved as the 0 address 156 // so they are included in the accounts tree 157 globalPerms := permission.DefaultAccountPermissions 158 globalPerms = genesisDoc.GlobalPermissions 159 // XXX: make sure the set bits are all true 160 // Without it the HasPermission() functions will fail 161 globalPerms.Base.SetBit = permission.AllPermFlags 162 163 permsAcc := &acm.Account{ 164 Address: acm.GlobalPermissionsAddress, 165 Balance: 1337, 166 Permissions: globalPerms, 167 } 168 err = s.writeState.UpdateAccount(permsAcc) 169 if err != nil { 170 return nil, fmt.Errorf("%s %v", errHeader, err) 171 } 172 173 return s, nil 174 } 175 176 func (s *State) InitialCommit() error { 177 _, version, err := s.commit() 178 if err != nil { 179 return fmt.Errorf("could not save initial state: %v", err) 180 } 181 if version != VersionOffset { 182 return fmt.Errorf("initial state got version %d after committing genesis state but version offset should be %d", 183 version, VersionOffset) 184 } 185 return nil 186 } 187 188 // Tries to load the execution state from DB, returns nil with no error if no state found 189 func LoadState(db dbm.DB, version int64) (*State, error) { 190 s := NewState(db) 191 err := s.writeState.forest.Load(version) 192 if err != nil { 193 return nil, fmt.Errorf("could not load MutableForest at version %d: %v", version, err) 194 } 195 // Populate stats. If this starts taking too long, store the value rather than the full scan at startup 196 err = s.IterateAccounts(func(acc *acm.Account) error { 197 if len(acc.Code) > 0 { 198 s.writeState.accountStats.AccountsWithCode++ 199 } else { 200 s.writeState.accountStats.AccountsWithoutCode++ 201 } 202 return nil 203 }) 204 if err != nil { 205 return nil, err 206 } 207 // load the validator ring 208 ring, err := LoadValidatorRing(version, DefaultValidatorsWindowSize, s.writeState.forest.GetImmutable) 209 if err != nil { 210 return nil, err 211 } 212 s.writeState.ring = ring 213 s.ReadState.History = ring 214 215 return s, nil 216 } 217 218 func (s *State) Version() int64 { 219 return s.writeState.forest.Version() 220 } 221 222 func (s *State) Hash() []byte { 223 return s.writeState.forest.Hash() 224 } 225 226 func (s *State) LoadHeight(height uint64) (*ReadState, error) { 227 version := VersionAtHeight(height) 228 forest, err := s.writeState.forest.GetImmutable(version) 229 if err != nil { 230 return nil, err 231 } 232 ring, err := LoadValidatorRing(version, DefaultValidatorsWindowSize, s.writeState.forest.GetImmutable) 233 if err != nil { 234 return nil, err 235 } 236 return &ReadState{ 237 Forest: forest, 238 History: ring, 239 }, nil 240 } 241 242 // Perform updates to state whilst holding the write lock, allows a commit to hold the write lock across multiple 243 // operations while preventing interlaced reads and writes 244 func (s *State) Update(updater func(up Updatable) error) ([]byte, int64, error) { 245 s.Lock() 246 defer s.Unlock() 247 err := updater(&s.writeState) 248 if err != nil { 249 return nil, 0, err 250 } 251 return s.commit() 252 } 253 254 func (s *State) commit() ([]byte, int64, error) { 255 // save state at a new version may still be orphaned before we save the version against the hash 256 hash, version, err := s.writeState.forest.Save() 257 if err != nil { 258 return nil, 0, err 259 } 260 totalPowerChange, totalFlow, err := s.writeState.ring.Rotate() 261 if err != nil { 262 return nil, 0, err 263 } 264 if totalFlow.Sign() != 0 { 265 //noinspection ALL 266 s.logger.InfoMsg("validator set changes", "total_power_change", totalPowerChange, "total_flow", totalFlow) 267 } 268 return hash, version, err 269 } 270 271 // Creates a copy of the database to the supplied db 272 func (s *State) Copy(db dbm.DB) (*State, error) { 273 stateCopy := NewState(db) 274 err := s.writeState.forest.IterateRWTree(nil, nil, true, 275 func(prefix []byte, tree *storage.RWTree) error { 276 treeCopy, err := stateCopy.writeState.forest.Writer(prefix) 277 if err != nil { 278 return err 279 } 280 return tree.IterateWriteTree(nil, nil, true, func(key []byte, value []byte) error { 281 treeCopy.Set(key, value) 282 return nil 283 }) 284 }) 285 if err != nil { 286 return nil, err 287 } 288 _, _, err = stateCopy.commit() 289 if err != nil { 290 return nil, err 291 } 292 return stateCopy, nil 293 } 294 295 func (s *State) SetLogger(logger *logging.Logger) { 296 s.logger = logger 297 }