github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/core/state/state_object.go (about) 1 package state 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "math/big" 8 9 "github.com/neatlab/neatio/utilities/common" 10 "github.com/neatlab/neatio/utilities/crypto" 11 "github.com/neatlab/neatio/utilities/rlp" 12 ) 13 14 var emptyCodeHash = crypto.Keccak256(nil) 15 16 type Code []byte 17 18 func (self Code) String() string { 19 return string(self) 20 } 21 22 type Storage map[common.Hash]common.Hash 23 24 func (self Storage) String() (str string) { 25 for key, value := range self { 26 str += fmt.Sprintf("%X : %X\n", key, value) 27 } 28 29 return 30 } 31 32 func (self Storage) Copy() Storage { 33 cpy := make(Storage) 34 for key, value := range self { 35 cpy[key] = value 36 } 37 38 return cpy 39 } 40 41 type stateObject struct { 42 address common.Address 43 addrHash common.Hash 44 data Account 45 db *StateDB 46 47 dbErr error 48 49 trie Trie 50 code Code 51 52 originStorage Storage 53 dirtyStorage Storage 54 55 tx1Trie Trie 56 tx3Trie Trie 57 58 dirtyTX1 map[common.Hash]struct{} 59 dirtyTX3 map[common.Hash]struct{} 60 61 proxiedTrie Trie 62 originProxied Proxied 63 dirtyProxied Proxied 64 65 rewardTrie Trie 66 originReward Reward 67 dirtyReward Reward 68 69 dirtyCode bool 70 suicided bool 71 touched bool 72 deleted bool 73 onDirty func(addr common.Address) 74 } 75 76 func (s *stateObject) empty() bool { 77 return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash) && s.data.DepositBalance.Sign() == 0 && len(s.data.SideChainDepositBalance) == 0 && s.data.ChainBalance.Sign() == 0 && s.data.DelegateBalance.Sign() == 0 && s.data.ProxiedBalance.Sign() == 0 && s.data.DepositProxiedBalance.Sign() == 0 && s.data.PendingRefundBalance.Sign() == 0 78 } 79 80 type Account struct { 81 Nonce uint64 82 Balance *big.Int 83 DepositBalance *big.Int 84 SideChainDepositBalance []*sideChainDepositBalance 85 ChainBalance *big.Int 86 Root common.Hash 87 TX1Root common.Hash 88 TX3Root common.Hash 89 CodeHash []byte 90 91 DelegateBalance *big.Int 92 ProxiedBalance *big.Int 93 DepositProxiedBalance *big.Int 94 PendingRefundBalance *big.Int 95 ProxiedRoot common.Hash 96 97 Candidate bool 98 Commission uint8 99 100 Pubkey string 101 FAddress common.Address 102 103 RewardBalance *big.Int 104 105 RewardRoot common.Hash 106 } 107 108 func newObject(db *StateDB, address common.Address, data Account, onDirty func(addr common.Address)) *stateObject { 109 if data.Balance == nil { 110 data.Balance = new(big.Int) 111 } 112 if data.DepositBalance == nil { 113 data.DepositBalance = new(big.Int) 114 } 115 if data.ChainBalance == nil { 116 data.ChainBalance = new(big.Int) 117 } 118 119 if data.DelegateBalance == nil { 120 data.DelegateBalance = new(big.Int) 121 } 122 if data.ProxiedBalance == nil { 123 data.ProxiedBalance = new(big.Int) 124 } 125 if data.DepositProxiedBalance == nil { 126 data.DepositProxiedBalance = new(big.Int) 127 } 128 if data.PendingRefundBalance == nil { 129 data.PendingRefundBalance = new(big.Int) 130 } 131 132 if data.RewardBalance == nil { 133 data.RewardBalance = new(big.Int) 134 } 135 136 if data.CodeHash == nil { 137 data.CodeHash = emptyCodeHash 138 } 139 return &stateObject{ 140 db: db, 141 address: address, 142 addrHash: crypto.Keccak256Hash(address[:]), 143 data: data, 144 originStorage: make(Storage), 145 dirtyStorage: make(Storage), 146 dirtyTX1: make(map[common.Hash]struct{}), 147 dirtyTX3: make(map[common.Hash]struct{}), 148 originProxied: make(Proxied), 149 dirtyProxied: make(Proxied), 150 originReward: make(Reward), 151 dirtyReward: make(Reward), 152 onDirty: onDirty, 153 } 154 } 155 156 func (c *stateObject) EncodeRLP(w io.Writer) error { 157 return rlp.Encode(w, c.data) 158 } 159 160 func (self *stateObject) setError(err error) { 161 if self.dbErr == nil { 162 self.dbErr = err 163 } 164 } 165 166 func (self *stateObject) markSuicided() { 167 self.suicided = true 168 if self.onDirty != nil { 169 self.onDirty(self.Address()) 170 self.onDirty = nil 171 } 172 } 173 174 func (c *stateObject) touch() { 175 c.db.journal = append(c.db.journal, touchChange{ 176 account: &c.address, 177 prev: c.touched, 178 prevDirty: c.onDirty == nil, 179 }) 180 if c.onDirty != nil { 181 c.onDirty(c.Address()) 182 c.onDirty = nil 183 } 184 c.touched = true 185 } 186 187 func (c *stateObject) getTX1Trie(db Database) Trie { 188 if c.tx1Trie == nil { 189 var err error 190 c.tx1Trie, err = db.OpenTX1Trie(c.addrHash, c.data.TX1Root) 191 if err != nil { 192 c.tx1Trie, _ = db.OpenTX1Trie(c.addrHash, common.Hash{}) 193 c.setError(fmt.Errorf("can't create TX1 trie: %v", err)) 194 } 195 } 196 return c.tx1Trie 197 } 198 199 func (self *stateObject) HasTX1(db Database, txHash common.Hash) bool { 200 201 _, ok := self.dirtyTX1[txHash] 202 if ok { 203 return true 204 } 205 206 enc, err := self.getTX1Trie(db).TryGet(txHash[:]) 207 if err != nil { 208 return false 209 } 210 if len(enc) > 0 { 211 _, content, _, err := rlp.Split(enc) 212 if err != nil { 213 self.setError(err) 214 return false 215 } 216 if !bytes.Equal(content, txHash[:]) { 217 self.setError(fmt.Errorf("content mismatch the tx hash")) 218 return false 219 } 220 221 return true 222 } 223 224 return false 225 } 226 227 func (self *stateObject) AddTX1(db Database, txHash common.Hash) { 228 self.db.journal = append(self.db.journal, addTX1Change{ 229 account: &self.address, 230 txHash: txHash, 231 }) 232 self.addTX1(txHash) 233 } 234 235 func (self *stateObject) addTX1(txHash common.Hash) { 236 self.dirtyTX1[txHash] = struct{}{} 237 } 238 239 func (self *stateObject) removeTX1(txHash common.Hash) { 240 delete(self.dirtyTX1, txHash) 241 } 242 243 func (self *stateObject) updateTX1Trie(db Database) Trie { 244 tr := self.getTX1Trie(db) 245 246 for tx1 := range self.dirtyTX1 { 247 delete(self.dirtyTX1, tx1) 248 249 v, _ := rlp.EncodeToBytes(bytes.TrimLeft(tx1[:], "\x00")) 250 self.setError(tr.TryUpdate(tx1[:], v)) 251 } 252 return tr 253 } 254 255 func (self *stateObject) updateTX1Root(db Database) { 256 self.updateTX1Trie(db) 257 self.data.TX1Root = self.tx1Trie.Hash() 258 } 259 260 func (self *stateObject) CommitTX1Trie(db Database) error { 261 self.updateTX1Trie(db) 262 if self.dbErr != nil { 263 return self.dbErr 264 } 265 root, err := self.tx1Trie.Commit(nil) 266 if err == nil { 267 self.data.TX1Root = root 268 } 269 return err 270 } 271 272 func (c *stateObject) getTX3Trie(db Database) Trie { 273 if c.tx3Trie == nil { 274 var err error 275 c.tx3Trie, err = db.OpenTX3Trie(c.addrHash, c.data.TX3Root) 276 if err != nil { 277 c.tx3Trie, _ = db.OpenTX3Trie(c.addrHash, common.Hash{}) 278 c.setError(fmt.Errorf("can't create TX3 trie: %v", err)) 279 } 280 } 281 return c.tx3Trie 282 } 283 284 func (self *stateObject) HasTX3(db Database, txHash common.Hash) bool { 285 286 _, ok := self.dirtyTX3[txHash] 287 if ok { 288 return true 289 } 290 291 enc, err := self.getTX3Trie(db).TryGet(txHash[:]) 292 if err != nil { 293 return false 294 } 295 if len(enc) > 0 { 296 _, content, _, err := rlp.Split(enc) 297 if err != nil { 298 self.setError(err) 299 return false 300 } 301 if !bytes.Equal(content, txHash[:]) { 302 self.setError(fmt.Errorf("content mismatch the tx hash")) 303 return false 304 } 305 306 return true 307 } 308 309 return false 310 } 311 312 func (self *stateObject) AddTX3(db Database, txHash common.Hash) { 313 self.db.journal = append(self.db.journal, addTX3Change{ 314 account: &self.address, 315 txHash: txHash, 316 }) 317 self.addTX3(txHash) 318 } 319 320 func (self *stateObject) addTX3(txHash common.Hash) { 321 self.dirtyTX3[txHash] = struct{}{} 322 } 323 324 func (self *stateObject) removeTX3(txHash common.Hash) { 325 delete(self.dirtyTX3, txHash) 326 } 327 328 func (self *stateObject) updateTX3Trie(db Database) Trie { 329 tr := self.getTX3Trie(db) 330 331 for tx3 := range self.dirtyTX3 { 332 delete(self.dirtyTX3, tx3) 333 334 v, _ := rlp.EncodeToBytes(bytes.TrimLeft(tx3[:], "\x00")) 335 self.setError(tr.TryUpdate(tx3[:], v)) 336 } 337 return tr 338 } 339 340 func (self *stateObject) updateTX3Root(db Database) { 341 self.updateTX3Trie(db) 342 self.data.TX3Root = self.tx3Trie.Hash() 343 } 344 345 func (self *stateObject) CommitTX3Trie(db Database) error { 346 self.updateTX3Trie(db) 347 if self.dbErr != nil { 348 return self.dbErr 349 } 350 root, err := self.tx3Trie.Commit(nil) 351 if err == nil { 352 self.data.TX3Root = root 353 } 354 return err 355 } 356 357 func (c *stateObject) getTrie(db Database) Trie { 358 if c.trie == nil { 359 var err error 360 c.trie, err = db.OpenStorageTrie(c.addrHash, c.data.Root) 361 if err != nil { 362 c.trie, _ = db.OpenStorageTrie(c.addrHash, common.Hash{}) 363 c.setError(fmt.Errorf("can't create storage trie: %v", err)) 364 } 365 } 366 return c.trie 367 } 368 369 func (self *stateObject) GetState(db Database, key common.Hash) common.Hash { 370 371 value, dirty := self.dirtyStorage[key] 372 if dirty { 373 return value 374 } 375 376 return self.GetCommittedState(db, key) 377 } 378 379 func (self *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash { 380 381 value, cached := self.originStorage[key] 382 if cached { 383 return value 384 } 385 386 enc, err := self.getTrie(db).TryGet(key[:]) 387 if err != nil { 388 self.setError(err) 389 return common.Hash{} 390 } 391 if len(enc) > 0 { 392 _, content, _, err := rlp.Split(enc) 393 if err != nil { 394 self.setError(err) 395 } 396 value.SetBytes(content) 397 } 398 self.originStorage[key] = value 399 return value 400 } 401 402 func (self *stateObject) SetState(db Database, key, value common.Hash) { 403 self.db.journal = append(self.db.journal, storageChange{ 404 account: &self.address, 405 key: key, 406 prevalue: self.GetState(db, key), 407 }) 408 self.setState(key, value) 409 } 410 411 func (self *stateObject) setState(key, value common.Hash) { 412 self.dirtyStorage[key] = value 413 414 if self.onDirty != nil { 415 self.onDirty(self.Address()) 416 self.onDirty = nil 417 } 418 } 419 420 func (self *stateObject) updateTrie(db Database) Trie { 421 tr := self.getTrie(db) 422 for key, value := range self.dirtyStorage { 423 delete(self.dirtyStorage, key) 424 425 if value == self.originStorage[key] { 426 continue 427 } 428 self.originStorage[key] = value 429 430 if (value == common.Hash{}) { 431 self.setError(tr.TryDelete(key[:])) 432 continue 433 } 434 435 v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00")) 436 self.setError(tr.TryUpdate(key[:], v)) 437 } 438 return tr 439 } 440 441 func (self *stateObject) updateRoot(db Database) { 442 self.updateTrie(db) 443 self.data.Root = self.trie.Hash() 444 } 445 446 func (self *stateObject) CommitTrie(db Database) error { 447 self.updateTrie(db) 448 if self.dbErr != nil { 449 return self.dbErr 450 } 451 root, err := self.trie.Commit(nil) 452 if err == nil { 453 self.data.Root = root 454 } 455 return err 456 } 457 458 func (c *stateObject) AddBalance(amount *big.Int) { 459 460 if amount.Sign() == 0 { 461 if c.empty() { 462 c.touch() 463 } 464 465 return 466 } 467 c.SetBalance(new(big.Int).Add(c.Balance(), amount)) 468 } 469 470 func (c *stateObject) SubBalance(amount *big.Int) { 471 if amount.Sign() == 0 { 472 return 473 } 474 c.SetBalance(new(big.Int).Sub(c.Balance(), amount)) 475 } 476 477 func (self *stateObject) SetBalance(amount *big.Int) { 478 self.db.journal = append(self.db.journal, balanceChange{ 479 account: &self.address, 480 prev: new(big.Int).Set(self.data.Balance), 481 }) 482 self.setBalance(amount) 483 } 484 485 func (self *stateObject) setBalance(amount *big.Int) { 486 self.data.Balance = amount 487 if self.onDirty != nil { 488 self.onDirty(self.Address()) 489 self.onDirty = nil 490 } 491 } 492 493 func (c *stateObject) ReturnGas(gas *big.Int) {} 494 495 func (self *stateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *stateObject { 496 stateObject := newObject(db, self.address, self.data, onDirty) 497 if self.trie != nil { 498 stateObject.trie = db.db.CopyTrie(self.trie) 499 } 500 if self.tx1Trie != nil { 501 stateObject.tx1Trie = db.db.CopyTrie(self.tx1Trie) 502 } 503 if self.tx3Trie != nil { 504 stateObject.tx3Trie = db.db.CopyTrie(self.tx3Trie) 505 } 506 if self.proxiedTrie != nil { 507 stateObject.proxiedTrie = db.db.CopyTrie(self.proxiedTrie) 508 } 509 if self.rewardTrie != nil { 510 stateObject.rewardTrie = db.db.CopyTrie(self.rewardTrie) 511 } 512 stateObject.code = self.code 513 stateObject.dirtyStorage = self.dirtyStorage.Copy() 514 stateObject.originStorage = self.originStorage.Copy() 515 stateObject.suicided = self.suicided 516 stateObject.dirtyCode = self.dirtyCode 517 stateObject.deleted = self.deleted 518 stateObject.dirtyTX1 = make(map[common.Hash]struct{}) 519 for tx1 := range self.dirtyTX1 { 520 stateObject.dirtyTX1[tx1] = struct{}{} 521 } 522 stateObject.dirtyTX3 = make(map[common.Hash]struct{}) 523 for tx3 := range self.dirtyTX3 { 524 stateObject.dirtyTX3[tx3] = struct{}{} 525 } 526 stateObject.dirtyProxied = self.dirtyProxied.Copy() 527 stateObject.originProxied = self.originProxied.Copy() 528 stateObject.dirtyReward = self.dirtyReward.Copy() 529 stateObject.originReward = self.originReward.Copy() 530 return stateObject 531 } 532 533 func (c *stateObject) Address() common.Address { 534 return c.address 535 } 536 537 func (self *stateObject) Code(db Database) []byte { 538 if self.code != nil { 539 return self.code 540 } 541 if bytes.Equal(self.CodeHash(), emptyCodeHash) { 542 return nil 543 } 544 code, err := db.ContractCode(self.addrHash, common.BytesToHash(self.CodeHash())) 545 if err != nil { 546 self.setError(fmt.Errorf("can't load code hash %x: %v", self.CodeHash(), err)) 547 } 548 self.code = code 549 return code 550 } 551 552 func (self *stateObject) SetCode(codeHash common.Hash, code []byte) { 553 prevcode := self.Code(self.db.db) 554 self.db.journal = append(self.db.journal, codeChange{ 555 account: &self.address, 556 prevhash: self.CodeHash(), 557 prevcode: prevcode, 558 }) 559 self.setCode(codeHash, code) 560 } 561 562 func (self *stateObject) setCode(codeHash common.Hash, code []byte) { 563 self.code = code 564 self.data.CodeHash = codeHash[:] 565 self.dirtyCode = true 566 if self.onDirty != nil { 567 self.onDirty(self.Address()) 568 self.onDirty = nil 569 } 570 } 571 572 func (self *stateObject) SetNonce(nonce uint64) { 573 self.db.journal = append(self.db.journal, nonceChange{ 574 account: &self.address, 575 prev: self.data.Nonce, 576 }) 577 self.setNonce(nonce) 578 } 579 580 func (self *stateObject) setNonce(nonce uint64) { 581 self.data.Nonce = nonce 582 if self.onDirty != nil { 583 self.onDirty(self.Address()) 584 self.onDirty = nil 585 } 586 } 587 588 func (self *stateObject) CodeHash() []byte { 589 return self.data.CodeHash 590 } 591 592 func (self *stateObject) Balance() *big.Int { 593 return self.data.Balance 594 } 595 596 func (self *stateObject) Nonce() uint64 { 597 return self.data.Nonce 598 } 599 600 func (self *stateObject) Value() *big.Int { 601 panic("Value on stateObject should never be called") 602 } 603 604 func (self *stateObject) SetAddress(address common.Address) { 605 self.db.journal = append(self.db.journal, fAddressChange{ 606 account: &self.address, 607 prev: self.data.FAddress, 608 }) 609 610 self.setAddress(address) 611 } 612 613 func (self *stateObject) setAddress(address common.Address) { 614 self.data.FAddress = address 615 if self.onDirty != nil { 616 self.onDirty(self.Address()) 617 self.onDirty = nil 618 } 619 } 620 621 func (self *stateObject) GetAddress() common.Address { 622 return self.data.FAddress 623 }