github.com/amazechain/amc@v0.1.3/modules/state/state_object.go (about) 1 // Copyright 2023 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package state 18 19 import ( 20 "bytes" 21 "fmt" 22 "github.com/amazechain/amc/common/account" 23 "github.com/amazechain/amc/common/types" 24 "github.com/amazechain/amc/internal/avm/rlp" 25 "github.com/amazechain/amc/utils" 26 "io" 27 "math/big" 28 29 "github.com/holiman/uint256" 30 ) 31 32 // var emptyCodeHash = crypto.Keccak256(nil) 33 var emptyCodeHash = utils.Keccak256(nil) 34 var emptyCodeHashH = types.BytesToHash(emptyCodeHash) 35 36 type Code []byte 37 38 func (c Code) String() string { 39 return string(c) //strings.Join(Disassemble(c), " ") 40 } 41 42 type Storage map[types.Hash]uint256.Int 43 44 func (s Storage) String() (str string) { 45 for key, value := range s { 46 str += fmt.Sprintf("%X : %X\n", key, value) 47 } 48 49 return 50 } 51 52 func (s Storage) Copy() Storage { 53 cpy := make(Storage) 54 for key, value := range s { 55 cpy[key] = value 56 } 57 58 return cpy 59 } 60 61 // stateObject represents an Ethereum account which is being modified. 62 // 63 // The usage pattern is as follows: 64 // First you need to obtain a state object. 65 // Account values can be accessed and modified through the object. 66 type stateObject struct { 67 address types.Address 68 data account.StateAccount 69 original account.StateAccount 70 db *IntraBlockState 71 72 // Write caches. 73 //trie Trie // storage trie, which becomes non-nil on first access 74 code Code // contract bytecode, which gets set when code is loaded 75 76 originStorage Storage // Storage cache of original entries to dedup rewrites 77 // blockOriginStorage keeps the values of storage items at the beginning of the block 78 // Used to make decision on whether to make a write to the 79 // database (value != origin) or not (value == origin) 80 blockOriginStorage Storage 81 dirtyStorage Storage // Storage entries that need to be flushed to disk 82 fakeStorage Storage // Fake storage which constructed by caller for debugging purpose. 83 84 // Cache flags. 85 // When an object is marked suicided it will be delete from the trie 86 // during the "update" phase of the state transition. 87 dirtyCode bool // true if the code was updated 88 selfdestructed bool 89 deleted bool // true if account was deleted during the lifetime of this object 90 created bool // true if this object represents a newly created contract 91 } 92 93 // empty returns whether the account is considered empty. 94 func (so *stateObject) empty() bool { 95 return so.data.Nonce == 0 && so.data.Balance.IsZero() && bytes.Equal(so.data.CodeHash[:], emptyCodeHash) 96 } 97 98 // newObject creates a state object. 99 func newObject(db *IntraBlockState, address types.Address, data, original *account.StateAccount) *stateObject { 100 var so = stateObject{ 101 db: db, 102 address: address, 103 originStorage: make(Storage), 104 blockOriginStorage: make(Storage), 105 dirtyStorage: make(Storage), 106 } 107 so.data.Copy(data) 108 if !so.data.Initialised { 109 so.data.Balance.SetUint64(0) 110 so.data.Initialised = true 111 } 112 if so.data.CodeHash == (types.Hash{}) { 113 so.data.CodeHash = emptyCodeHashH 114 } 115 if so.data.Root == (types.Hash{}) { 116 // todo 117 //so.data.Root = trie.EmptyRoot 118 } 119 so.original.Copy(original) 120 121 return &so 122 } 123 124 // EncodeRLP implements rlp.Encoder. 125 func (so *stateObject) EncodeRLP(w io.Writer) error { 126 return rlp.Encode(w, so.data) 127 } 128 129 // setError remembers the first non-nil error it is called with. 130 func (so *stateObject) setError(err error) { 131 if so.db.savedErr == nil { 132 so.db.savedErr = err 133 } 134 } 135 136 func (so *stateObject) markSelfdestructed() { 137 so.selfdestructed = true 138 } 139 140 func (so *stateObject) touch() { 141 so.db.journal.append(touchChange{ 142 account: &so.address, 143 }) 144 if so.address == ripemd { 145 // Explicitly put it in the dirty-cache, which is otherwise generated from 146 // flattened journals. 147 so.db.journal.dirty(so.address) 148 } 149 } 150 151 // GetState returns a value from account storage. 152 func (so *stateObject) GetState(key *types.Hash, out *uint256.Int) { 153 // If the fake storage is set, only lookup the state here(in the debugging mode) 154 if so.fakeStorage != nil { 155 *out = so.fakeStorage[*key] 156 return 157 } 158 value, dirty := so.dirtyStorage[*key] 159 if dirty { 160 *out = value 161 return 162 } 163 // Otherwise return the entry's original value 164 so.GetCommittedState(key, out) 165 } 166 167 // GetCommittedState retrieves a value from the committed account storage trie. 168 func (so *stateObject) GetCommittedState(key *types.Hash, out *uint256.Int) { 169 // If the fake storage is set, only lookup the state here(in the debugging mode) 170 if so.fakeStorage != nil { 171 *out = so.fakeStorage[*key] 172 return 173 } 174 // If we have the original value cached, return that 175 { 176 value, cached := so.originStorage[*key] 177 if cached { 178 *out = value 179 return 180 } 181 } 182 if so.created { 183 out.Clear() 184 return 185 } 186 187 if so.db != nil && so.db.snap != nil && !so.db.snap.CanWrite() { 188 // Load from DB in case it is missing. 189 enc, err := so.db.snap.ReadAccountStorage(so.address, so.data.GetIncarnation(), key) 190 if err != nil { 191 so.setError(err) 192 out.Clear() 193 return 194 } 195 if enc != nil { 196 out.SetBytes(enc) 197 } else { 198 out.Clear() 199 } 200 //enc1, err1 := so.db.stateReader.ReadAccountStorage(so.address, so.data.GetIncarnation(), key) 201 //if !bytes.Equal(enc1, enc) { 202 // fmt.Println(err1) 203 //} 204 so.originStorage[*key] = *out 205 so.blockOriginStorage[*key] = *out 206 return 207 } 208 // Load from DB in case it is missing. 209 enc, err := so.db.stateReader.ReadAccountStorage(so.address, so.data.GetIncarnation(), key) 210 if err != nil { 211 so.setError(err) 212 out.Clear() 213 return 214 } 215 if enc != nil { 216 if so.db.snap != nil && so.db.snap.CanWrite() { 217 so.db.snap.AddStorage(so.address, key, so.data.GetIncarnation(), enc) 218 } 219 out.SetBytes(enc) 220 } else { 221 out.Clear() 222 } 223 so.originStorage[*key] = *out 224 so.blockOriginStorage[*key] = *out 225 } 226 227 // SetState updates a value in account storage. 228 func (so *stateObject) SetState(key *types.Hash, value uint256.Int) { 229 // If the fake storage is set, put the temporary state update here. 230 if so.fakeStorage != nil { 231 so.db.journal.append(fakeStorageChange{ 232 account: &so.address, 233 key: *key, 234 prevalue: so.fakeStorage[*key], 235 }) 236 so.fakeStorage[*key] = value 237 return 238 } 239 // If the new value is the same as old, don't set 240 var prev uint256.Int 241 so.GetState(key, &prev) 242 if prev == value { 243 return 244 } 245 // New value is different, update and journal the change 246 so.db.journal.append(storageChange{ 247 account: &so.address, 248 key: *key, 249 prevalue: prev, 250 }) 251 so.setState(key, value) 252 } 253 254 // SetStorage replaces the entire state storage with the given one. 255 // 256 // After this function is called, all original state will be ignored and state 257 // lookup only happens in the fake state storage. 258 // 259 // Note this function should only be used for debugging purpose. 260 func (so *stateObject) SetStorage(storage Storage) { 261 // Allocate fake storage if it's nil. 262 if so.fakeStorage == nil { 263 so.fakeStorage = make(Storage) 264 } 265 for key, value := range storage { 266 so.fakeStorage[key] = value 267 } 268 // Don't bother journal since this function should only be used for 269 // debugging and the `fake` storage won't be committed to database. 270 } 271 272 func (so *stateObject) setState(key *types.Hash, value uint256.Int) { 273 so.dirtyStorage[*key] = value 274 } 275 276 // updateTrie writes cached storage modifications into the object's storage trie. 277 func (so *stateObject) updateTrie(stateWriter StateWriter) error { 278 for key, value := range so.dirtyStorage { 279 value := value 280 original := so.blockOriginStorage[key] 281 so.originStorage[key] = value 282 if err := stateWriter.WriteAccountStorage(so.address, so.data.GetIncarnation(), &key, &original, &value); err != nil { 283 return err 284 } 285 } 286 return nil 287 } 288 func (so *stateObject) printTrie() { 289 for key, value := range so.dirtyStorage { 290 fmt.Printf("WriteAccountStorage: %x,%x,%s\n", so.address, key, value.Hex()) 291 } 292 } 293 294 // AddBalance adds amount to so's balance. 295 // It is used to add funds to the destination account of a transfer. 296 func (so *stateObject) AddBalance(amount *uint256.Int) { 297 // EIP161: We must check emptiness for the objects such that the account 298 // clearing (0,0,0 objects) can take effect. 299 if amount.IsZero() { 300 if so.empty() { 301 so.touch() 302 } 303 304 return 305 } 306 307 so.SetBalance(new(uint256.Int).Add(so.Balance(), amount)) 308 } 309 310 // SubBalance removes amount from so's balance. 311 // It is used to remove funds from the origin account of a transfer. 312 func (so *stateObject) SubBalance(amount *uint256.Int) { 313 if amount.IsZero() { 314 return 315 } 316 so.SetBalance(new(uint256.Int).Sub(so.Balance(), amount)) 317 } 318 319 func (so *stateObject) SetBalance(amount *uint256.Int) { 320 so.db.journal.append(balanceChange{ 321 account: &so.address, 322 prev: so.data.Balance, 323 }) 324 so.setBalance(amount) 325 } 326 327 func (so *stateObject) setBalance(amount *uint256.Int) { 328 so.data.Balance.Set(amount) 329 so.data.Initialised = true 330 } 331 332 // Return the gas back to the origin. Used by the Virtual machine or Closures 333 func (so *stateObject) ReturnGas(gas *big.Int) {} 334 335 func (so *stateObject) setIncarnation(incarnation uint16) { 336 so.data.SetIncarnation(incarnation) 337 } 338 339 // 340 // Attribute accessors 341 // 342 343 // Returns the address of the contract/account 344 func (so *stateObject) Address() types.Address { 345 return so.address 346 } 347 348 // Code returns the contract code associated with this object, if any. 349 func (so *stateObject) Code() []byte { 350 if so.code != nil { 351 return so.code 352 } 353 if bytes.Equal(so.CodeHash(), emptyCodeHash) { 354 return nil 355 } 356 code, err := so.db.stateReader.ReadAccountCode(so.Address(), so.data.Incarnation, types.BytesToHash(so.CodeHash())) 357 if err != nil { 358 so.setError(fmt.Errorf("can't load code hash %x: %w", so.CodeHash(), err)) 359 } 360 so.code = code 361 return code 362 } 363 364 func (so *stateObject) SetCode(codeHash types.Hash, code []byte) { 365 prevcode := so.Code() 366 so.db.journal.append(codeChange{ 367 account: &so.address, 368 prevhash: so.data.CodeHash, 369 prevcode: prevcode, 370 }) 371 so.setCode(codeHash, code) 372 } 373 374 func (so *stateObject) setCode(codeHash types.Hash, code []byte) { 375 so.code = code 376 so.data.CodeHash = codeHash 377 so.dirtyCode = true 378 } 379 380 func (so *stateObject) SetNonce(nonce uint64) { 381 so.db.journal.append(nonceChange{ 382 account: &so.address, 383 prev: so.data.Nonce, 384 }) 385 so.setNonce(nonce) 386 } 387 388 func (so *stateObject) setNonce(nonce uint64) { 389 so.data.Nonce = nonce 390 } 391 392 func (so *stateObject) CodeHash() []byte { 393 return so.data.CodeHash[:] 394 } 395 396 func (so *stateObject) Balance() *uint256.Int { 397 return &so.data.Balance 398 } 399 400 func (so *stateObject) Nonce() uint64 { 401 return so.data.Nonce 402 } 403 404 // Never called, but must be present to allow stateObject to be used 405 // as a vm.Account interface that also satisfies the vm.ContractRef 406 // interface. Interfaces are awesome. 407 func (so *stateObject) Value() *big.Int { 408 panic("Value on stateObject should never be called") 409 }