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