github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/core/state/state_object.go (about) 1 // Copyright 2014 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The Spectrum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package state 18 19 import ( 20 "bytes" 21 "fmt" 22 "github.com/SmartMeshFoundation/Spectrum/params" 23 "github.com/hashicorp/golang-lru" 24 "io" 25 "math/big" 26 27 "github.com/SmartMeshFoundation/Spectrum/common" 28 "github.com/SmartMeshFoundation/Spectrum/crypto" 29 "github.com/SmartMeshFoundation/Spectrum/rlp" 30 "github.com/SmartMeshFoundation/Spectrum/trie" 31 ) 32 33 var ( 34 emptyCodeHash = crypto.Keccak256(nil) 35 contractCodeCacheSize = 5461 // max code size 24k , 128MB / 24k == 5461 36 contractCodeCache *lru.Cache 37 ) 38 39 type Code []byte 40 41 func (self Code) String() string { 42 return string(self) //strings.Join(Disassemble(self), " ") 43 } 44 45 type Storage map[common.Hash]common.Hash 46 47 func (self Storage) String() (str string) { 48 for key, value := range self { 49 str += fmt.Sprintf("%X : %X\n", key, value) 50 } 51 52 return 53 } 54 55 func (self Storage) Copy() Storage { 56 cpy := make(Storage) 57 for key, value := range self { 58 cpy[key] = value 59 } 60 61 return cpy 62 } 63 64 // stateObject represents an Ethereum account which is being modified. 65 // 66 // The usage pattern is as follows: 67 // First you need to obtain a state object. 68 // Account values can be accessed and modified through the object. 69 // Finally, call CommitTrie to write the modified storage trie into a database. 70 type stateObject struct { 71 address common.Address 72 addrHash common.Hash // hash of ethereum address of the account 73 data Account 74 db *StateDB 75 76 // DB error. 77 // State objects are used by the consensus core and VM which are 78 // unable to deal with database-level errors. Any error that occurs 79 // during a database read is memoized here and will eventually be returned 80 // by StateDB.Commit. 81 dbErr error 82 83 // Write caches. 84 trie Trie // storage trie, which becomes non-nil on first access 85 code Code // contract bytecode, which gets set when code is loaded 86 87 cachedStorage Storage // Storage entry cache to avoid duplicate reads 88 dirtyStorage Storage // Storage entries that need to be flushed to disk 89 90 // Cache flags. 91 // When an object is marked suicided it will be delete from the trie 92 // during the "update" phase of the state transition. 93 dirtyCode bool // true if the code was updated 94 suicided bool 95 touched bool 96 deleted bool 97 onDirty func(addr common.Address) // Callback method to mark a state object newly dirty 98 } 99 100 // empty returns whether the account is considered empty. 101 func (s *stateObject) empty() bool { 102 return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash) 103 } 104 105 // Account is the Ethereum consensus representation of accounts. 106 // These objects are stored in the main account trie. 107 type Account struct { 108 Nonce uint64 109 Balance *big.Int 110 Root common.Hash // merkle root of the storage trie 111 CodeHash []byte 112 } 113 114 // newObject creates a state object. 115 func newObject(db *StateDB, address common.Address, data Account, onDirty func(addr common.Address)) *stateObject { 116 if contractCodeCache == nil { 117 contractCodeCache, _ = lru.New(contractCodeCacheSize) 118 } 119 if data.Balance == nil { 120 data.Balance = new(big.Int) 121 } 122 if data.CodeHash == nil { 123 data.CodeHash = emptyCodeHash 124 } 125 return &stateObject{ 126 db: db, 127 address: address, 128 addrHash: crypto.Keccak256Hash(address[:]), 129 data: data, 130 cachedStorage: make(Storage), 131 dirtyStorage: make(Storage), 132 onDirty: onDirty, 133 } 134 } 135 136 // EncodeRLP implements rlp.Encoder. 137 func (c *stateObject) EncodeRLP(w io.Writer) error { 138 return rlp.Encode(w, c.data) 139 } 140 141 // setError remembers the first non-nil error it is called with. 142 func (self *stateObject) setError(err error) { 143 if self.dbErr == nil { 144 self.dbErr = err 145 } 146 } 147 148 func (self *stateObject) markSuicided() { 149 self.suicided = true 150 if self.onDirty != nil { 151 self.onDirty(self.Address()) 152 self.onDirty = nil 153 } 154 } 155 156 func (c *stateObject) touch() { 157 c.db.journal = append(c.db.journal, touchChange{ 158 account: &c.address, 159 }) 160 if c.onDirty != nil { 161 c.onDirty(c.Address()) 162 c.onDirty = nil 163 } 164 c.touched = true 165 } 166 167 func (c *stateObject) getTrie(db Database) Trie { 168 if c.trie == nil { 169 var err error 170 c.trie, err = db.OpenStorageTrie(c.addrHash, c.data.Root) 171 if err != nil { 172 c.trie, _ = db.OpenStorageTrie(c.addrHash, common.Hash{}) 173 c.setError(fmt.Errorf("can't create storage trie: %v", err)) 174 } 175 } 176 return c.trie 177 } 178 179 // GetState returns a value in account storage. 180 func (self *stateObject) GetState(db Database, key common.Hash) common.Hash { 181 value, exists := self.cachedStorage[key] 182 if exists { 183 return value 184 } 185 // Load from DB in case it is missing. 186 enc, err := self.getTrie(db).TryGet(key[:]) 187 if err != nil { 188 self.setError(err) 189 return common.Hash{} 190 } 191 if len(enc) > 0 { 192 _, content, _, err := rlp.Split(enc) 193 if err != nil { 194 self.setError(err) 195 } 196 value.SetBytes(content) 197 } 198 if (value != common.Hash{}) { 199 self.cachedStorage[key] = value 200 } 201 return value 202 } 203 204 // SetState updates a value in account storage. 205 func (self *stateObject) SetState(db Database, key, value common.Hash) { 206 self.db.journal = append(self.db.journal, storageChange{ 207 account: &self.address, 208 key: key, 209 prevalue: self.GetState(db, key), 210 }) 211 self.setState(key, value) 212 } 213 214 func (self *stateObject) setState(key, value common.Hash) { 215 self.cachedStorage[key] = value 216 self.dirtyStorage[key] = value 217 218 if self.onDirty != nil { 219 self.onDirty(self.Address()) 220 self.onDirty = nil 221 } 222 } 223 224 // updateTrie writes cached storage modifications into the object's storage trie. 225 func (self *stateObject) updateTrie(db Database) Trie { 226 tr := self.getTrie(db) 227 for key, value := range self.dirtyStorage { 228 delete(self.dirtyStorage, key) 229 if (value == common.Hash{}) { 230 self.setError(tr.TryDelete(key[:])) 231 continue 232 } 233 // Encoding []byte cannot fail, ok to ignore the error. 234 v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00")) 235 self.setError(tr.TryUpdate(key[:], v)) 236 } 237 return tr 238 } 239 240 // UpdateRoot sets the trie root to the current root hash of 241 func (self *stateObject) updateRoot(db Database) { 242 self.updateTrie(db) 243 self.data.Root = self.trie.Hash() 244 } 245 246 // CommitTrie the storage trie of the object to dwb. 247 // This updates the trie root. 248 func (self *stateObject) CommitTrie(db Database, dbw trie.DatabaseWriter) error { 249 self.updateTrie(db) 250 if self.dbErr != nil { 251 return self.dbErr 252 } 253 root, err := self.trie.CommitTo(dbw) 254 if err == nil { 255 self.data.Root = root 256 } 257 return err 258 } 259 260 // AddBalance removes amount from c's balance. 261 // It is used to add funds to the destination account of a transfer. 262 func (c *stateObject) AddBalance(amount *big.Int) { 263 // EIP158: We must check emptiness for the objects such that the account 264 // clearing (0,0,0 objects) can take effect. 265 if amount.Sign() == 0 { 266 if c.empty() { 267 c.touch() 268 } 269 270 return 271 } 272 c.SetBalance(new(big.Int).Add(c.Balance(), amount)) 273 } 274 275 // SubBalance removes amount from c's balance. 276 // It is used to remove funds from the origin account of a transfer. 277 func (c *stateObject) SubBalance(amount *big.Int) { 278 if amount.Sign() == 0 { 279 return 280 } 281 c.SetBalance(new(big.Int).Sub(c.Balance(), amount)) 282 } 283 284 func (self *stateObject) SetBalance(amount *big.Int) { 285 self.db.journal = append(self.db.journal, balanceChange{ 286 account: &self.address, 287 prev: new(big.Int).Set(self.data.Balance), 288 }) 289 self.setBalance(amount) 290 } 291 292 func (self *stateObject) setBalance(amount *big.Int) { 293 self.data.Balance = amount 294 if self.onDirty != nil { 295 self.onDirty(self.Address()) 296 self.onDirty = nil 297 } 298 } 299 300 // Return the gas back to the origin. Used by the Virtual machine or Closures 301 func (c *stateObject) ReturnGas(gas *big.Int) {} 302 303 func (self *stateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *stateObject { 304 stateObject := newObject(db, self.address, self.data, onDirty) 305 if self.trie != nil { 306 stateObject.trie = db.db.CopyTrie(self.trie) 307 } 308 stateObject.code = self.code 309 stateObject.dirtyStorage = self.dirtyStorage.Copy() 310 stateObject.cachedStorage = self.dirtyStorage.Copy() 311 stateObject.suicided = self.suicided 312 stateObject.dirtyCode = self.dirtyCode 313 stateObject.deleted = self.deleted 314 return stateObject 315 } 316 317 // 318 // Attribute accessors 319 // 320 321 // Returns the address of the contract/account 322 func (c *stateObject) Address() common.Address { 323 return c.address 324 } 325 326 func (self *stateObject) getCode(db Database) ([]byte, error) { 327 var ( 328 code []byte 329 err error 330 ) 331 if contractCodeCache == nil { 332 code, err = db.ContractCode(self.addrHash, common.BytesToHash(self.CodeHash())) 333 return code, err 334 } 335 val, ok := contractCodeCache.Get(self.Address()) 336 if ok { 337 return val.([]byte), nil 338 } 339 code, err = db.ContractCode(self.addrHash, common.BytesToHash(self.CodeHash())) 340 if err != nil { 341 return nil, err 342 } 343 contractCodeCache.Add(self.Address(), code) 344 return code, err 345 } 346 347 // Code returns the contract code associated with this object, if any. 348 func (self *stateObject) Code(db Database) []byte { 349 var ( 350 code []byte 351 err error 352 ) 353 if self.code != nil { 354 return self.code 355 } 356 if bytes.Equal(self.CodeHash(), emptyCodeHash) { 357 return nil 358 } 359 // add by liangc : cache chief contract code 360 if params.IsChiefAddress(self.Address()) { 361 code, err = params.GetChiefContractCode(self.Address()) 362 if err != nil { 363 code, err = db.ContractCode(self.addrHash, common.BytesToHash(self.CodeHash())) 364 if err == nil { 365 params.SetChiefContractCode(self.Address(), code) 366 } 367 } 368 } else { 369 // TODO LRU cache 370 //code, err = db.ContractCode(self.addrHash, common.BytesToHash(self.CodeHash())) 371 code, err = self.getCode(db) 372 } 373 374 if err != nil { 375 self.setError(fmt.Errorf("can't load code hash %x: %v", self.CodeHash(), err)) 376 } 377 self.code = code 378 return code 379 } 380 381 func (self *stateObject) SetCode(codeHash common.Hash, code []byte) { 382 prevcode := self.Code(self.db.db) 383 self.db.journal = append(self.db.journal, codeChange{ 384 account: &self.address, 385 prevhash: self.CodeHash(), 386 prevcode: prevcode, 387 }) 388 self.setCode(codeHash, code) 389 } 390 391 func (self *stateObject) setCode(codeHash common.Hash, code []byte) { 392 self.code = code 393 self.data.CodeHash = codeHash[:] 394 self.dirtyCode = true 395 if self.onDirty != nil { 396 self.onDirty(self.Address()) 397 self.onDirty = nil 398 } 399 } 400 401 func (self *stateObject) SetNonce(nonce uint64) { 402 self.db.journal = append(self.db.journal, nonceChange{ 403 account: &self.address, 404 prev: self.data.Nonce, 405 }) 406 self.setNonce(nonce) 407 } 408 409 func (self *stateObject) setNonce(nonce uint64) { 410 self.data.Nonce = nonce 411 if self.onDirty != nil { 412 self.onDirty(self.Address()) 413 self.onDirty = nil 414 } 415 } 416 417 func (self *stateObject) CodeHash() []byte { 418 return self.data.CodeHash 419 } 420 421 func (self *stateObject) Balance() *big.Int { 422 return self.data.Balance 423 } 424 425 func (self *stateObject) Nonce() uint64 { 426 return self.data.Nonce 427 } 428 429 // Never called, but must be present to allow stateObject to be used 430 // as a vm.Account interface that also satisfies the vm.ContractRef 431 // interface. Interfaces are awesome. 432 func (self *stateObject) Value() *big.Int { 433 panic("Value on stateObject should never be called") 434 }