github.com/ConsenSys/Quorum@v20.10.0+incompatible/extension/state_fetcher.go (about) 1 package extension 2 3 import ( 4 "encoding/json" 5 "fmt" 6 7 "github.com/ethereum/go-ethereum/common" 8 "github.com/ethereum/go-ethereum/core/state" 9 "github.com/ethereum/go-ethereum/core/types" 10 "github.com/ethereum/go-ethereum/extension/extensionContracts" 11 ) 12 13 // ChainAccessor provides methods to fetch state and blocks from the local blockchain 14 type ChainAccessor interface { 15 // GetBlockByHash retrieves a block from the local chain. 16 GetBlockByHash(common.Hash) *types.Block 17 StateAt(root common.Hash) (*state.StateDB, *state.StateDB, error) 18 State() (*state.StateDB, *state.StateDB, error) 19 CurrentBlock() *types.Block 20 } 21 22 // StateFetcher manages retrieving state from the database and returning it in 23 // a usable form by the extension API. 24 type StateFetcher struct { 25 chainAccessor ChainAccessor 26 } 27 28 // Creates a new StateFetcher from the ethereum service 29 func NewStateFetcher(chainAccessor ChainAccessor) *StateFetcher { 30 return &StateFetcher{ 31 chainAccessor: chainAccessor, 32 } 33 } 34 35 // returns the current block hash 36 func (fetcher *StateFetcher) getCurrentBlockHash() common.Hash { 37 return fetcher.chainAccessor.CurrentBlock().Hash() 38 } 39 40 // GetAddressStateFromBlock is a public method that combines the other 41 // functions of a StateFetcher, retrieving the state of an address at a given 42 // block, represented in JSON. 43 func (fetcher *StateFetcher) GetAddressStateFromBlock(blockHash common.Hash, addressToFetch common.Address) ([]byte, error) { 44 privateState, err := fetcher.privateState(blockHash) 45 if err != nil { 46 return nil, err 47 } 48 stateData, err := fetcher.addressStateAsJson(privateState, addressToFetch) 49 if err != nil { 50 return nil, err 51 } 52 return stateData, nil 53 } 54 55 // privateState returns the private state database for a given block hash. 56 func (fetcher *StateFetcher) privateState(blockHash common.Hash) (*state.StateDB, error) { 57 block := fetcher.chainAccessor.GetBlockByHash(blockHash) 58 _, privateState, err := fetcher.chainAccessor.StateAt(block.Root()) 59 60 return privateState, err 61 } 62 63 // addressStateAsJson returns the state of an address, including the balance, 64 // nonce, code and state data as a JSON map. 65 func (fetcher *StateFetcher) addressStateAsJson(privateState *state.StateDB, addressToShare common.Address) ([]byte, error) { 66 keepAddresses := make(map[string]extensionContracts.AccountWithMetadata) 67 68 if account, found := privateState.DumpAddress(addressToShare); found { 69 keepAddresses[addressToShare.Hex()] = extensionContracts.AccountWithMetadata{ 70 State: account, 71 } 72 } else { 73 return nil, fmt.Errorf("error in contract state fetch") 74 } 75 //types can be marshalled, so errors can't occur 76 out, _ := json.Marshal(&keepAddresses) 77 return out, nil 78 } 79 80 // returns the privacy metadata 81 func (fetcher *StateFetcher) GetPrivacyMetaData(blockHash common.Hash, address common.Address) (*state.PrivacyMetadata, error) { 82 privateState, err := fetcher.privateState(blockHash) 83 if err != nil { 84 return nil, err 85 } 86 87 privacyMetaData, err := privateState.GetStatePrivacyMetadata(address) 88 if err != nil { 89 return nil, err 90 } 91 92 return privacyMetaData, nil 93 } 94 95 // returns the privacy metadata 96 func (fetcher *StateFetcher) GetStorageRoot(blockHash common.Hash, address common.Address) (common.Hash, error) { 97 privateState, err := fetcher.privateState(blockHash) 98 if err != nil { 99 return common.Hash{}, err 100 } 101 102 storageRoot, err := privateState.GetStorageRoot(address) 103 if err != nil { 104 return common.Hash{}, err 105 } 106 107 return storageRoot, nil 108 }