|
|
@@ -508,6 +508,72 @@ func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Add
|
|
|
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
|
|
|
}
|
|
|
|
|
|
+// Result structs for GetProof
|
|
|
+type AccountResult struct {
|
|
|
+ Address common.Address `json:"address"`
|
|
|
+ AccountProof []string `json:"accountProof"`
|
|
|
+ Balance *hexutil.Big `json:"balance"`
|
|
|
+ CodeHash common.Hash `json:"codeHash"`
|
|
|
+ Nonce hexutil.Uint64 `json:"nonce"`
|
|
|
+ StorageHash common.Hash `json:"storageHash"`
|
|
|
+ StorageProof []StorageResult `json:"storageProof"`
|
|
|
+}
|
|
|
+type StorageResult struct {
|
|
|
+ Key string `json:"key"`
|
|
|
+ Value *hexutil.Big `json:"value"`
|
|
|
+ Proof []string `json:"proof"`
|
|
|
+}
|
|
|
+
|
|
|
+// GetProof returns the Merkle-proof for a given account and optionally some storage keys.
|
|
|
+func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNr rpc.BlockNumber) (*AccountResult, error) {
|
|
|
+ state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
|
|
|
+ if state == nil || err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ storageTrie := state.StorageTrie(address)
|
|
|
+ storageHash := types.EmptyRootHash
|
|
|
+ codeHash := state.GetCodeHash(address)
|
|
|
+ storageProof := make([]StorageResult, len(storageKeys))
|
|
|
+
|
|
|
+ // if we have a storageTrie, (which means the account exists), we can update the storagehash
|
|
|
+ if storageTrie != nil {
|
|
|
+ storageHash = storageTrie.Hash()
|
|
|
+ } else {
|
|
|
+ // no storageTrie means the account does not exist, so the codeHash is the hash of an empty bytearray.
|
|
|
+ codeHash = crypto.Keccak256Hash(nil)
|
|
|
+ }
|
|
|
+
|
|
|
+ // create the proof for the storageKeys
|
|
|
+ for i, key := range storageKeys {
|
|
|
+ if storageTrie != nil {
|
|
|
+ proof, storageError := state.GetStorageProof(address, common.HexToHash(key))
|
|
|
+ if storageError != nil {
|
|
|
+ return nil, storageError
|
|
|
+ }
|
|
|
+ storageProof[i] = StorageResult{key, (*hexutil.Big)(state.GetState(address, common.HexToHash(key)).Big()), common.ToHexArray(proof)}
|
|
|
+ } else {
|
|
|
+ storageProof[i] = StorageResult{key, &hexutil.Big{}, []string{}}
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // create the accountProof
|
|
|
+ accountProof, proofErr := state.GetProof(address)
|
|
|
+ if proofErr != nil {
|
|
|
+ return nil, proofErr
|
|
|
+ }
|
|
|
+
|
|
|
+ return &AccountResult{
|
|
|
+ Address: address,
|
|
|
+ AccountProof: common.ToHexArray(accountProof),
|
|
|
+ Balance: (*hexutil.Big)(state.GetBalance(address)),
|
|
|
+ CodeHash: codeHash,
|
|
|
+ Nonce: hexutil.Uint64(state.GetNonce(address)),
|
|
|
+ StorageHash: storageHash,
|
|
|
+ StorageProof: storageProof,
|
|
|
+ }, state.Error()
|
|
|
+}
|
|
|
+
|
|
|
// GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all
|
|
|
// transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
|
|
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|