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