github.com/Unheilbar/quorum@v1.0.0/extension/state_fetcher.go (about)

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