github.com/baptiste-b-pegasys/quorum/v22@v22.4.2/core/state/state_object.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package state 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "io" 24 "math/big" 25 "sync" 26 "time" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/crypto" 30 "github.com/ethereum/go-ethereum/metrics" 31 "github.com/ethereum/go-ethereum/rlp" 32 ) 33 34 var emptyCodeHash = crypto.Keccak256(nil) 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[common.Hash]common.Hash 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 // Finally, call CommitTrie to write the modified storage trie into a database. 67 type stateObject struct { 68 address common.Address 69 addrHash common.Hash // hash of ethereum address of the account 70 data Account 71 db *StateDB 72 73 // DB error. 74 // State objects are used by the consensus core and VM which are 75 // unable to deal with database-level errors. Any error that occurs 76 // during a database read is memoized here and will eventually be returned 77 // by StateDB.Commit. 78 dbErr error 79 80 // Write caches. 81 trie Trie // storage trie, which becomes non-nil on first access 82 code Code // contract bytecode, which gets set when code is loaded 83 84 // Quorum 85 // contains extra data that is linked to the account 86 accountExtraData *AccountExtraData 87 // as there are many fields in accountExtraData which might be concurrently changed 88 // this is to make sure we can keep track of changes individually. 89 accountExtraDataMutex sync.Mutex 90 91 originStorage Storage // Storage cache of original entries to dedup rewrites, reset for every transaction 92 pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block 93 dirtyStorage Storage // Storage entries that have been modified in the current transaction execution 94 fakeStorage Storage // Fake storage which constructed by caller for debugging purpose. 95 96 // Cache flags. 97 // When an object is marked suicided it will be delete from the trie 98 // during the "update" phase of the state transition. 99 dirtyCode bool // true if the code was updated 100 suicided bool 101 deleted bool 102 // Quorum 103 // flag to track changes in AccountExtraData 104 dirtyAccountExtraData bool 105 106 mux sync.Mutex 107 } 108 109 // empty returns whether the account is considered empty. 110 func (s *stateObject) empty() bool { 111 return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash) 112 } 113 114 // Account is the Ethereum consensus representation of accounts. 115 // These objects are stored in the main account trie. 116 type Account struct { 117 Nonce uint64 118 Balance *big.Int 119 Root common.Hash // merkle root of the storage trie 120 CodeHash []byte 121 } 122 123 // newObject creates a state object. 124 func newObject(db *StateDB, address common.Address, data Account) *stateObject { 125 if data.Balance == nil { 126 data.Balance = new(big.Int) 127 } 128 if data.CodeHash == nil { 129 data.CodeHash = emptyCodeHash 130 } 131 if data.Root == (common.Hash{}) { 132 data.Root = emptyRoot 133 } 134 return &stateObject{ 135 db: db, 136 address: address, 137 addrHash: crypto.Keccak256Hash(address[:]), 138 data: data, 139 originStorage: make(Storage), 140 pendingStorage: make(Storage), 141 dirtyStorage: make(Storage), 142 } 143 } 144 145 // EncodeRLP implements rlp.Encoder. 146 func (s *stateObject) EncodeRLP(w io.Writer) error { 147 return rlp.Encode(w, s.data) 148 } 149 150 // setError remembers the first non-nil error it is called with. 151 func (s *stateObject) setError(err error) { 152 if s.dbErr == nil { 153 s.dbErr = err 154 } 155 } 156 157 func (s *stateObject) markSuicided() { 158 s.suicided = true 159 } 160 161 func (s *stateObject) touch() { 162 s.db.journal.append(touchChange{ 163 account: &s.address, 164 }) 165 if s.address == ripemd { 166 // Explicitly put it in the dirty-cache, which is otherwise generated from 167 // flattened journals. 168 s.db.journal.dirty(s.address) 169 } 170 } 171 172 func (s *stateObject) getTrie(db Database) Trie { 173 if s.trie == nil { 174 // Try fetching from prefetcher first 175 // We don't prefetch empty tries 176 if s.data.Root != emptyRoot && s.db.prefetcher != nil { 177 // When the miner is creating the pending state, there is no 178 // prefetcher 179 s.trie = s.db.prefetcher.trie(s.data.Root) 180 } 181 if s.trie == nil { 182 var err error 183 s.trie, err = db.OpenStorageTrie(s.addrHash, s.data.Root) 184 if err != nil { 185 s.trie, _ = db.OpenStorageTrie(s.addrHash, common.Hash{}) 186 s.setError(fmt.Errorf("can't create storage trie: %v", err)) 187 } 188 } 189 } 190 return s.trie 191 } 192 193 func (so *stateObject) storageRoot(db Database) common.Hash { 194 return so.getTrie(db).Hash() 195 } 196 197 // GetState retrieves a value from the account storage trie. 198 func (s *stateObject) GetState(db Database, key common.Hash) common.Hash { 199 // If the fake storage is set, only lookup the state here(in the debugging mode) 200 if s.fakeStorage != nil { 201 return s.fakeStorage[key] 202 } 203 // If we have a dirty value for this state entry, return it 204 value, dirty := s.dirtyStorage[key] 205 if dirty { 206 return value 207 } 208 // Otherwise return the entry's original value 209 return s.GetCommittedState(db, key) 210 } 211 212 // GetCommittedState retrieves a value from the committed account storage trie. 213 func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash { 214 // If the fake storage is set, only lookup the state here(in the debugging mode) 215 if s.fakeStorage != nil { 216 return s.fakeStorage[key] 217 } 218 // If we have a pending write or clean cached, return that 219 if value, pending := s.pendingStorage[key]; pending { 220 return value 221 } 222 if value, cached := s.originStorage[key]; cached { 223 return value 224 } 225 // If no live objects are available, attempt to use snapshots 226 var ( 227 enc []byte 228 err error 229 meter *time.Duration 230 ) 231 readStart := time.Now() 232 if metrics.EnabledExpensive { 233 // If the snap is 'under construction', the first lookup may fail. If that 234 // happens, we don't want to double-count the time elapsed. Thus this 235 // dance with the metering. 236 defer func() { 237 if meter != nil { 238 *meter += time.Since(readStart) 239 } 240 }() 241 } 242 if s.db.snap != nil { 243 if metrics.EnabledExpensive { 244 meter = &s.db.SnapshotStorageReads 245 } 246 // If the object was destructed in *this* block (and potentially resurrected), 247 // the storage has been cleared out, and we should *not* consult the previous 248 // snapshot about any storage values. The only possible alternatives are: 249 // 1) resurrect happened, and new slot values were set -- those should 250 // have been handles via pendingStorage above. 251 // 2) we don't have new values, and can deliver empty response back 252 if _, destructed := s.db.snapDestructs[s.addrHash]; destructed { 253 return common.Hash{} 254 } 255 enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes())) 256 } 257 // If snapshot unavailable or reading from it failed, load from the database 258 if s.db.snap == nil || err != nil { 259 if meter != nil { 260 // If we already spent time checking the snapshot, account for it 261 // and reset the readStart 262 *meter += time.Since(readStart) 263 readStart = time.Now() 264 } 265 if metrics.EnabledExpensive { 266 meter = &s.db.StorageReads 267 } 268 if enc, err = s.getTrie(db).TryGet(key.Bytes()); err != nil { 269 s.setError(err) 270 return common.Hash{} 271 } 272 } 273 var value common.Hash 274 if len(enc) > 0 { 275 _, content, _, err := rlp.Split(enc) 276 if err != nil { 277 s.setError(err) 278 } 279 value.SetBytes(content) 280 } 281 282 s.mux.Lock() 283 defer s.mux.Unlock() 284 285 s.originStorage[key] = value 286 return value 287 } 288 289 // SetState updates a value in account storage. 290 func (s *stateObject) SetState(db Database, key, value common.Hash) { 291 // If the fake storage is set, put the temporary state update here. 292 if s.fakeStorage != nil { 293 s.fakeStorage[key] = value 294 return 295 } 296 // If the new value is the same as old, don't set 297 prev := s.GetState(db, key) 298 if prev == value { 299 return 300 } 301 // New value is different, update and journal the change 302 s.db.journal.append(storageChange{ 303 account: &s.address, 304 key: key, 305 prevalue: prev, 306 }) 307 s.setState(key, value) 308 } 309 310 // SetStorage replaces the entire state storage with the given one. 311 // 312 // After this function is called, all original state will be ignored and state 313 // lookup only happens in the fake state storage. 314 // 315 // Note this function should only be used for debugging purpose. 316 func (s *stateObject) SetStorage(storage map[common.Hash]common.Hash) { 317 // Allocate fake storage if it's nil. 318 if s.fakeStorage == nil { 319 s.fakeStorage = make(Storage) 320 } 321 for key, value := range storage { 322 s.fakeStorage[key] = value 323 } 324 // Don't bother journal since this function should only be used for 325 // debugging and the `fake` storage won't be committed to database. 326 } 327 328 func (s *stateObject) setState(key, value common.Hash) { 329 s.mux.Lock() 330 defer s.mux.Unlock() 331 332 s.dirtyStorage[key] = value 333 } 334 335 // finalise moves all dirty storage slots into the pending area to be hashed or 336 // committed later. It is invoked at the end of every transaction. 337 func (s *stateObject) finalise(prefetch bool) { 338 s.mux.Lock() 339 defer s.mux.Unlock() 340 341 slotsToPrefetch := make([][]byte, 0, len(s.dirtyStorage)) 342 343 for key, value := range s.dirtyStorage { 344 s.pendingStorage[key] = value 345 if value != s.originStorage[key] { 346 slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure 347 } 348 } 349 if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != emptyRoot { 350 s.db.prefetcher.prefetch(s.data.Root, slotsToPrefetch) 351 } 352 if len(s.dirtyStorage) > 0 { 353 s.dirtyStorage = make(Storage) 354 } 355 } 356 357 // updateTrie writes cached storage modifications into the object's storage trie. 358 // It will return nil if the trie has not been loaded and no changes have been made 359 func (s *stateObject) updateTrie(db Database) Trie { 360 // Make sure all dirty slots are finalized into the pending storage area 361 s.finalise(false) // Don't prefetch any more, pull directly if need be 362 if len(s.pendingStorage) == 0 { 363 return s.trie 364 } 365 // Track the amount of time wasted on updating the storage trie 366 if metrics.EnabledExpensive { 367 defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now()) 368 } 369 // The snapshot storage map for the object 370 var storage map[common.Hash][]byte 371 // Insert all the pending updates into the trie 372 tr := s.getTrie(db) 373 hasher := s.db.hasher 374 375 s.mux.Lock() 376 defer s.mux.Unlock() 377 usedStorage := make([][]byte, 0, len(s.pendingStorage)) 378 for key, value := range s.pendingStorage { 379 // Skip noop changes, persist actual changes 380 if value == s.originStorage[key] { 381 continue 382 } 383 s.originStorage[key] = value 384 385 var v []byte 386 if (value == common.Hash{}) { 387 s.setError(tr.TryDelete(key[:])) 388 } else { 389 // Encoding []byte cannot fail, ok to ignore the error. 390 v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) 391 s.setError(tr.TryUpdate(key[:], v)) 392 } 393 // If state snapshotting is active, cache the data til commit 394 if s.db.snap != nil { 395 if storage == nil { 396 // Retrieve the old storage map, if available, create a new one otherwise 397 if storage = s.db.snapStorage[s.addrHash]; storage == nil { 398 storage = make(map[common.Hash][]byte) 399 s.db.snapStorage[s.addrHash] = storage 400 } 401 } 402 storage[crypto.HashData(hasher, key[:])] = v // v will be nil if value is 0x00 403 } 404 usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure 405 } 406 if s.db.prefetcher != nil { 407 s.db.prefetcher.used(s.data.Root, usedStorage) 408 } 409 if len(s.pendingStorage) > 0 { 410 s.pendingStorage = make(Storage) 411 } 412 return tr 413 } 414 415 // UpdateRoot sets the trie root to the current root hash of 416 func (s *stateObject) updateRoot(db Database) { 417 // If nothing changed, don't bother with hashing anything 418 if s.updateTrie(db) == nil { 419 return 420 } 421 // Track the amount of time wasted on hashing the storage trie 422 if metrics.EnabledExpensive { 423 defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now()) 424 } 425 s.data.Root = s.trie.Hash() 426 } 427 428 // CommitTrie the storage trie of the object to db. 429 // This updates the trie root. 430 func (s *stateObject) CommitTrie(db Database) error { 431 // If nothing changed, don't bother with hashing anything 432 if s.updateTrie(db) == nil { 433 return nil 434 } 435 if s.dbErr != nil { 436 return s.dbErr 437 } 438 // Track the amount of time wasted on committing the storage trie 439 if metrics.EnabledExpensive { 440 defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now()) 441 } 442 root, err := s.trie.Commit(nil) 443 if err == nil { 444 s.data.Root = root 445 } 446 return err 447 } 448 449 // AddBalance adds amount to s's balance. 450 // It is used to add funds to the destination account of a transfer. 451 func (s *stateObject) AddBalance(amount *big.Int) { 452 // EIP161: We must check emptiness for the objects such that the account 453 // clearing (0,0,0 objects) can take effect. 454 if amount.Sign() == 0 { 455 if s.empty() { 456 s.touch() 457 } 458 return 459 } 460 s.SetBalance(new(big.Int).Add(s.Balance(), amount)) 461 } 462 463 // SubBalance removes amount from s's balance. 464 // It is used to remove funds from the origin account of a transfer. 465 func (s *stateObject) SubBalance(amount *big.Int) { 466 if amount.Sign() == 0 { 467 return 468 } 469 s.SetBalance(new(big.Int).Sub(s.Balance(), amount)) 470 } 471 472 func (s *stateObject) SetBalance(amount *big.Int) { 473 s.db.journal.append(balanceChange{ 474 account: &s.address, 475 prev: new(big.Int).Set(s.data.Balance), 476 }) 477 s.setBalance(amount) 478 } 479 480 func (s *stateObject) setBalance(amount *big.Int) { 481 s.data.Balance = amount 482 } 483 484 // Return the gas back to the origin. Used by the Virtual machine or Closures 485 func (s *stateObject) ReturnGas(gas *big.Int) {} 486 487 func (s *stateObject) deepCopy(db *StateDB) *stateObject { 488 s.mux.Lock() 489 defer s.mux.Unlock() 490 491 stateObject := newObject(db, s.address, s.data) 492 if s.trie != nil { 493 stateObject.trie = db.db.CopyTrie(s.trie) 494 } 495 stateObject.code = s.code 496 stateObject.dirtyStorage = s.dirtyStorage.Copy() 497 stateObject.originStorage = s.originStorage.Copy() 498 stateObject.pendingStorage = s.pendingStorage.Copy() 499 stateObject.suicided = s.suicided 500 stateObject.dirtyCode = s.dirtyCode 501 stateObject.deleted = s.deleted 502 // Quorum - copy AccountExtraData 503 stateObject.accountExtraData = s.accountExtraData 504 stateObject.dirtyAccountExtraData = s.dirtyAccountExtraData 505 506 return stateObject 507 } 508 509 // 510 // Attribute accessors 511 // 512 513 // Returns the address of the contract/account 514 func (s *stateObject) Address() common.Address { 515 return s.address 516 } 517 518 // Code returns the contract code associated with this object, if any. 519 func (s *stateObject) Code(db Database) []byte { 520 if s.code != nil { 521 return s.code 522 } 523 if bytes.Equal(s.CodeHash(), emptyCodeHash) { 524 return nil 525 } 526 code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash())) 527 if err != nil { 528 s.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) 529 } 530 s.code = code 531 return code 532 } 533 534 // CodeSize returns the size of the contract code associated with this object, 535 // or zero if none. This method is an almost mirror of Code, but uses a cache 536 // inside the database to avoid loading codes seen recently. 537 func (s *stateObject) CodeSize(db Database) int { 538 if s.code != nil { 539 return len(s.code) 540 } 541 if bytes.Equal(s.CodeHash(), emptyCodeHash) { 542 return 0 543 } 544 size, err := db.ContractCodeSize(s.addrHash, common.BytesToHash(s.CodeHash())) 545 if err != nil { 546 s.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err)) 547 } 548 return size 549 } 550 551 func (s *stateObject) SetCode(codeHash common.Hash, code []byte) { 552 prevcode := s.Code(s.db.db) 553 s.db.journal.append(codeChange{ 554 account: &s.address, 555 prevhash: s.CodeHash(), 556 prevcode: prevcode, 557 }) 558 s.setCode(codeHash, code) 559 } 560 561 func (s *stateObject) setCode(codeHash common.Hash, code []byte) { 562 s.code = code 563 s.data.CodeHash = codeHash[:] 564 s.dirtyCode = true 565 } 566 567 func (s *stateObject) SetNonce(nonce uint64) { 568 s.db.journal.append(nonceChange{ 569 account: &s.address, 570 prev: s.data.Nonce, 571 }) 572 s.setNonce(nonce) 573 } 574 575 func (s *stateObject) setNonce(nonce uint64) { 576 s.data.Nonce = nonce 577 } 578 579 // Quorum 580 // SetAccountExtraData modifies the AccountExtraData reference and journals it 581 func (s *stateObject) SetAccountExtraData(extraData *AccountExtraData) { 582 current, _ := s.AccountExtraData() 583 s.db.journal.append(accountExtraDataChange{ 584 account: &s.address, 585 prev: current, 586 }) 587 s.setAccountExtraData(extraData) 588 } 589 590 // A new AccountExtraData will be created if not exists. 591 // This must be called after successfully acquiring accountExtraDataMutex lock 592 func (s *stateObject) journalAccountExtraData() *AccountExtraData { 593 current, _ := s.AccountExtraData() 594 s.db.journal.append(accountExtraDataChange{ 595 account: &s.address, 596 prev: current.copy(), 597 }) 598 if current == nil { 599 current = &AccountExtraData{} 600 } 601 return current 602 } 603 604 // Quorum 605 // SetStatePrivacyMetadata updates the PrivacyMetadata in AccountExtraData and journals it. 606 func (s *stateObject) SetStatePrivacyMetadata(pm *PrivacyMetadata) { 607 s.accountExtraDataMutex.Lock() 608 defer s.accountExtraDataMutex.Unlock() 609 610 newExtraData := s.journalAccountExtraData() 611 newExtraData.PrivacyMetadata = pm 612 s.setAccountExtraData(newExtraData) 613 } 614 615 // Quorum 616 // SetStatePrivacyMetadata updates the PrivacyMetadata in AccountExtraData and journals it. 617 func (s *stateObject) SetManagedParties(managedParties []string) { 618 s.accountExtraDataMutex.Lock() 619 defer s.accountExtraDataMutex.Unlock() 620 621 newExtraData := s.journalAccountExtraData() 622 newExtraData.ManagedParties = managedParties 623 s.setAccountExtraData(newExtraData) 624 } 625 626 // Quorum 627 // setAccountExtraData modifies the AccountExtraData reference in this state object 628 func (s *stateObject) setAccountExtraData(extraData *AccountExtraData) { 629 s.accountExtraData = extraData 630 s.dirtyAccountExtraData = true 631 } 632 633 func (s *stateObject) CodeHash() []byte { 634 return s.data.CodeHash 635 } 636 637 func (s *stateObject) Balance() *big.Int { 638 return s.data.Balance 639 } 640 641 func (s *stateObject) Nonce() uint64 { 642 return s.data.Nonce 643 } 644 645 // Quorum 646 // AccountExtraData returns the extra data in this state object. 647 // It will also update the reference by searching the accountExtraDataTrie. 648 // 649 // This method enforces on returning error and never returns (nil, nil). 650 func (s *stateObject) AccountExtraData() (*AccountExtraData, error) { 651 if s.accountExtraData != nil { 652 return s.accountExtraData, nil 653 } 654 val, err := s.getCommittedAccountExtraData() 655 if err != nil { 656 return nil, err 657 } 658 s.accountExtraData = val 659 return val, nil 660 } 661 662 // Quorum 663 // getCommittedAccountExtraData looks for an entry in accountExtraDataTrie. 664 // 665 // This method enforces on returning error and never returns (nil, nil). 666 func (s *stateObject) getCommittedAccountExtraData() (*AccountExtraData, error) { 667 val, err := s.db.accountExtraDataTrie.TryGet(s.address.Bytes()) 668 if err != nil { 669 return nil, fmt.Errorf("unable to retrieve data from the accountExtraDataTrie. Cause: %v", err) 670 } 671 if len(val) == 0 { 672 return nil, fmt.Errorf("%s: %w", s.address.Hex(), common.ErrNoAccountExtraData) 673 } 674 var extraData AccountExtraData 675 if err := rlp.DecodeBytes(val, &extraData); err != nil { 676 return nil, fmt.Errorf("unable to decode to AccountExtraData. Cause: %v", err) 677 } 678 return &extraData, nil 679 } 680 681 // Quorum - Privacy Enhancements 682 // PrivacyMetadata returns the reference to PrivacyMetadata. 683 // It will returrn an error if no PrivacyMetadata is in the AccountExtraData. 684 func (s *stateObject) PrivacyMetadata() (*PrivacyMetadata, error) { 685 extraData, err := s.AccountExtraData() 686 if err != nil { 687 return nil, err 688 } 689 // extraData can't be nil. Refer to s.AccountExtraData() 690 if extraData.PrivacyMetadata == nil { 691 return nil, fmt.Errorf("no privacy metadata data for contract %s", s.address.Hex()) 692 } 693 return extraData.PrivacyMetadata, nil 694 } 695 696 func (s *stateObject) GetCommittedPrivacyMetadata() (*PrivacyMetadata, error) { 697 extraData, err := s.getCommittedAccountExtraData() 698 if err != nil { 699 return nil, err 700 } 701 if extraData == nil || extraData.PrivacyMetadata == nil { 702 return nil, fmt.Errorf("The provided contract does not have privacy metadata: %x", s.address) 703 } 704 return extraData.PrivacyMetadata, nil 705 } 706 707 // End Quorum - Privacy Enhancements 708 709 // ManagedParties will return empty if no account extra data found 710 func (s *stateObject) ManagedParties() ([]string, error) { 711 extraData, err := s.AccountExtraData() 712 if errors.Is(err, common.ErrNoAccountExtraData) { 713 return []string{}, nil 714 } 715 if err != nil { 716 return nil, err 717 } 718 // extraData can't be nil. Refer to s.AccountExtraData() 719 return extraData.ManagedParties, nil 720 } 721 722 // Never called, but must be present to allow stateObject to be used 723 // as a vm.Account interface that also satisfies the vm.ContractRef 724 // interface. Interfaces are awesome. 725 func (s *stateObject) Value() *big.Int { 726 panic("Value on stateObject should never be called") 727 }