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  }