mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 03:30:37 +00:00
1084 various rpc fixes (#1111)
* Fixes issue #1110 - eth_getStorageAt returning inconsistent values * Adds support for various eth_getUncle calls * Adding a couple of comments * Adding support for eth_getTransactionCount * Cleaning up README's * Cleaning up README for rpcdaemon Co-authored-by: tjayrush <jrush@greathill.com>
This commit is contained in:
parent
3a4eb3db3e
commit
e5f8073d75
@ -125,7 +125,9 @@ Run RPC daemon
|
||||
> ./build/bin/rpcdaemon --private.api.addr=localhost:9090
|
||||
```
|
||||
|
||||
Supported JSON-RPC calls ([eth](./cmd/rpcdaemon/commands/eth_api.go), [debug](./cmd/rpcdaemon/commands/debug_api.go), [net](./cmd/rpcdaemon/commands/net_api.go)):
|
||||
Supported JSON-RPC calls ([eth](./cmd/rpcdaemon/commands/eth_api.go), [debug](./cmd/rpcdaemon/commands/debug_api.go), [net](./cmd/rpcdaemon/commands/net_api.go), [web3](./cmd/rpcdaemon/commands/web3_api.go)):
|
||||
|
||||
For a more detailed status, [see this table](./cmd/rpcdaemon/README.md#rpc-implementation-status).
|
||||
|
||||
```
|
||||
eth_coinbase
|
||||
@ -138,6 +140,11 @@ eth_getBlockTransactionCountByHash
|
||||
eth_getBlockTransactionCountByNumber
|
||||
eth_getBalance
|
||||
eth_getCode
|
||||
eth_GetTransactionCount
|
||||
eth_GetUncleByBlockNumberAndIndex
|
||||
eth_GetUncleByBlockHashAndIndex
|
||||
eth_GetUncleCountByBlockNumber
|
||||
eth_GetUncleCountByBlockHash
|
||||
eth_getLogs
|
||||
eth_getStorageAt
|
||||
eth_getTransactionReceipt
|
||||
|
166
cmd/rpcdaemon/README.md
Normal file
166
cmd/rpcdaemon/README.md
Normal file
@ -0,0 +1,166 @@
|
||||
In turbo-geth RPC calls are extracted out of the main binary into a separate daemon.
|
||||
This daemon can use both local or remote DBs. That means, that this RPC daemon
|
||||
doesn't have to be running on the same machine as the main turbo-geth binary or
|
||||
it can run from a snapshot of a database for read-only calls. [Docs](./cmd/rpcdaemon/Readme.md)
|
||||
|
||||
### Get started
|
||||
**For local DB**
|
||||
|
||||
```
|
||||
> make rpcdaemon
|
||||
> ./build/bin/rpcdaemon --chaindata ~/Library/TurboGeth/tg/chaindata --http.api=eth,debug,net
|
||||
```
|
||||
**For remote DB**
|
||||
|
||||
Run turbo-geth in one terminal window
|
||||
|
||||
```
|
||||
> ./build/bin/tg --private.api.addr=localhost:9090
|
||||
```
|
||||
|
||||
Run RPC daemon
|
||||
```
|
||||
> ./build/bin/rpcdaemon --private.api.addr=localhost:9090
|
||||
```
|
||||
|
||||
### Test
|
||||
|
||||
Try `eth_blockNumber` call. In another console/tab, use `curl` to make RPC call:
|
||||
|
||||
```
|
||||
curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber", "params": [], "id":1}' localhost:8545
|
||||
```
|
||||
|
||||
It should return something like this (depending on how far your turbo-geth node has synced):
|
||||
|
||||
```
|
||||
{"jsonrpc":"2.0","id":1,"result":823909}
|
||||
```
|
||||
|
||||
### For Developers
|
||||
|
||||
**Code generation**: `go.mod` stores right version of generators, use `mage grpc` to install it and generate code.
|
||||
|
||||
`protoc` version not managed but recommended version is 3.x, [install instruction](https://grpc.io/docs/protoc-installation/)
|
||||
|
||||
### RPC Implementation Status
|
||||
|
||||
eth_getBalance
|
||||
eth_getCode
|
||||
eth_getTransactionCount
|
||||
eth_getStorageAt
|
||||
eth_call
|
||||
When requests are made that act on the state of ethereum, the last default block parameter determines the height of the block.
|
||||
|
||||
The following options are possible for the defaultBlock parameter:
|
||||
|
||||
HEX String - an integer block number
|
||||
String "earliest" for the earliest/genesis block
|
||||
String "latest" - for the latest mined block
|
||||
String "pending" - for the pending state/transactions
|
||||
Curl Examples Explained
|
||||
The curl options below might return a response where the node complains about the content type, this is because the --data option sets the content type to application/x-www-form-urlencoded . If your node does complain, manually set the header by placing -H “Content-Type: application/json” at the start of the call.
|
||||
|
||||
The examples also do not include the URL/IP & port combination which must be the last argument given to curl e.x. 127.0.0.1:8545
|
||||
|
||||
| Command | Available | Notes |
|
||||
| --------------------------------------------- | --------- | ------------------------------------------------- |
|
||||
| _**------------ Web3 ------------**_ | |
|
||||
| web3_clientVersion | Y |
|
||||
| web3_sha3 | Y |
|
||||
| | |
|
||||
| _**------------ Net ------------**_ | |
|
||||
| net_listening | - |
|
||||
| net_peerCount\* | Y | Returns a count of 25 as work continues on Sentry |
|
||||
| net_version | Y |
|
||||
| | |
|
||||
| _**------------ System ------------**_ | |
|
||||
| eth_blockNumber | Y |
|
||||
| eth_chainID | - |
|
||||
| eth_protocolVersion | - |
|
||||
| eth_syncing | Y |
|
||||
| eth_estimateGas | Y |
|
||||
| eth_gasPrice | - |
|
||||
| | |
|
||||
| _**------------ Blocks/Uncles ------------**_ | |
|
||||
| eth_getBlockByHash | Y |
|
||||
| eth_getBlockByNumber | Y |
|
||||
| eth_getBlockTransactionCountByHash | Y |
|
||||
| eth_getBlockTransactionCountByNumber | Y |
|
||||
| eth_getUncleByBlockHashAndIndex | Y |
|
||||
| eth_getUncleByBlockNumberAndIndex | Y |
|
||||
| eth_getUncleCountByBlockHash | Y |
|
||||
| eth_getUncleCountByBlockNumber | Y |
|
||||
| | |
|
||||
| _**------------ Transactions ------------**_ | |
|
||||
| eth_getTransactionByHash | Y |
|
||||
| eth_getTransactionByBlockHashAndIndex | Y |
|
||||
| eth_getTransactionByBlockNumberAndIndex | Y |
|
||||
| eth_getTransactionReceipt | Y |
|
||||
| eth_getLogs | Y |
|
||||
| | |
|
||||
| _**------------ State ------------**_ | |
|
||||
| eth_getBalance | Y |
|
||||
| eth_getCode | Y |
|
||||
| eth_getStorageAt | Y |
|
||||
| | |
|
||||
| _**------------ Filters ------------**_ | |
|
||||
| eth_newFilter | - |
|
||||
| eth_newBlockFilter | - |
|
||||
| eth_newPendingTransactionFilter | - |
|
||||
| eth_getFilterChanges | - |
|
||||
| eth_getFilterLogs | - |
|
||||
| eth_uninstallFilter | - |
|
||||
| | |
|
||||
| _**------------ Accounts ------------**_ | |
|
||||
| eth_accounts | |
|
||||
| eth_call | Y |
|
||||
| eth_getTransactionCount | Y |
|
||||
| eth_sendRawTransaction | Y |
|
||||
| eth_sendTransaction | - |
|
||||
| eth_sign | - |
|
||||
| eth_signTransaction | - |
|
||||
| eth_signTypedData | - |
|
||||
| | |
|
||||
| _**------------ ????? ------------**_ | |
|
||||
| eth_getProof | - |
|
||||
| | |
|
||||
| _**------------ Mining ------------**_ | |
|
||||
| eth_mining | - |
|
||||
| eth_coinbase | Y |
|
||||
| eth_hashrate | - |
|
||||
| eth_submitHashrate | - |
|
||||
| eth_getWork | - |
|
||||
| eth_submitWork | - |
|
||||
| | |
|
||||
| _**------------ Debug ------------**_ | |
|
||||
| debug_accountRange | Y |
|
||||
| debug_getModifiedAccountsByNumber | Y |
|
||||
| debug_getModifiedAccountsByHash | Y |
|
||||
| debug_storageRangeAt | Y |
|
||||
| debug_traceTransaction | Y |
|
||||
| | |
|
||||
| _\*\*------------ trace_ ------------\*\*\_ | |
|
||||
| trace_filter | Y |
|
||||
| | |
|
||||
| _\*\*------------ Retired ------------\*\*\_ | |
|
||||
| eth_getCompilers | N |
|
||||
| eth_compileLLL | N |
|
||||
| eth_compileSolidity | N |
|
||||
| eth_compileSerpent | N |
|
||||
| | |
|
||||
| db_putString | N |
|
||||
| db_getString | N |
|
||||
| db_putHex | N |
|
||||
| db_getHex | N |
|
||||
| | |
|
||||
| shh_post | N |
|
||||
| shh_version | N |
|
||||
| shh_newIdentity | N |
|
||||
| shh_hasIdentity | N |
|
||||
| shh_newGroup | N |
|
||||
| shh_addToGroup | N |
|
||||
| shh_newFilter | N |
|
||||
| shh_uninstallFilter | N |
|
||||
| shh_getFilterChanges | N |
|
||||
| shh_getMessages | N |
|
@ -1,41 +0,0 @@
|
||||
In turbo-geth RPC calls are extracted out of the main binary into a separate daemon.
|
||||
This daemon can use both local or remote DBs. That means, that this RPC daemon
|
||||
doesn't have to be running on the same machine as the main turbo-geth binary or
|
||||
it can run from a snapshot of a database for read-only calls. [Docs](./cmd/rpcdaemon/Readme.md)
|
||||
|
||||
### Get started
|
||||
**For local DB**
|
||||
|
||||
```
|
||||
> make rpcdaemon
|
||||
> ./build/bin/rpcdaemon --chaindata ~/Library/TurboGeth/tg/chaindata --http.api=eth,debug,net
|
||||
```
|
||||
**For remote DB**
|
||||
|
||||
Run turbo-geth in one terminal window
|
||||
|
||||
```
|
||||
> ./build/bin/tg --private.api.addr=localhost:9090
|
||||
```
|
||||
|
||||
Run RPC daemon
|
||||
```
|
||||
> ./build/bin/rpcdaemon --private.api.addr=localhost:9090
|
||||
```
|
||||
|
||||
### Test
|
||||
|
||||
Try `eth_blockNumber` call. In another console/tab, use `curl` to make RPC call:
|
||||
````
|
||||
curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber", "params": [], "id":1}' localhost:8545
|
||||
````
|
||||
It should return something like this (depending on how far your turbo-geth node has synced):
|
||||
````
|
||||
{"jsonrpc":"2.0","id":1,"result":823909}
|
||||
````
|
||||
|
||||
### For Developers
|
||||
|
||||
**Code generation**: `go.mod` stores right version of generators, use `mage grpc` to install it and generate code.
|
||||
|
||||
`protoc` version not managed but recommended version is 3.*, [install instruction](https://grpc.io/docs/protoc-installation/)
|
@ -63,6 +63,7 @@ func (api *APIImpl) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx
|
||||
return response, err
|
||||
}
|
||||
|
||||
// GetHeaderByNumber returns a block's header by number
|
||||
func (api *APIImpl) GetHeaderByNumber(_ context.Context, number rpc.BlockNumber) (*types.Header, error) {
|
||||
header := rawdb.ReadHeaderByNumber(api.dbReader, uint64(number.Int64()))
|
||||
if header == nil {
|
||||
@ -72,6 +73,7 @@ func (api *APIImpl) GetHeaderByNumber(_ context.Context, number rpc.BlockNumber)
|
||||
return header, nil
|
||||
}
|
||||
|
||||
// GetHeaderByHash returns a block's header by hash
|
||||
func (api *APIImpl) GetHeaderByHash(_ context.Context, hash common.Hash) (*types.Header, error) {
|
||||
header := rawdb.ReadHeaderByHash(api.dbReader, hash)
|
||||
if header == nil {
|
||||
|
@ -40,6 +40,11 @@ type EthAPI interface {
|
||||
GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, txIndex hexutil.Uint) (*RPCTransaction, error)
|
||||
GetStorageAt(ctx context.Context, address common.Address, index string, blockNrOrHash rpc.BlockNumberOrHash) (string, error)
|
||||
GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error)
|
||||
GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error)
|
||||
GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error)
|
||||
GetUncleByBlockHashAndIndex(ctx context.Context, hash common.Hash, index hexutil.Uint) (map[string]interface{}, error)
|
||||
GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint
|
||||
GetUncleCountByBlockHash(ctx context.Context, hash common.Hash) *hexutil.Uint
|
||||
}
|
||||
|
||||
// APIImpl is implementation of the EthAPI interface based on remote Db access
|
||||
@ -211,30 +216,27 @@ func (api *APIImpl) GetTransactionByBlockNumberAndIndex(ctx context.Context, blo
|
||||
return newRPCTransaction(txs[txIndex], block.Hash(), block.NumberU64(), uint64(txIndex)), nil
|
||||
}
|
||||
|
||||
// GetStorageAt returns a 32-byte long, zero-left-padded value at storage location 'index' of address 'address'. Returns '0x' if no value
|
||||
func (api *APIImpl) GetStorageAt(ctx context.Context, address common.Address, index string, blockNrOrHash rpc.BlockNumberOrHash) (string, error) {
|
||||
var empty []byte
|
||||
|
||||
blockNumber, _, err := rpchelper.GetBlockNumber(blockNrOrHash, api.dbReader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return hexutil.Encode(common.LeftPadBytes(empty[:], 32)), err
|
||||
}
|
||||
|
||||
reader := adapter.NewStateReader(api.db, blockNumber)
|
||||
acc, err := reader.ReadAccountData(address)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if acc == nil {
|
||||
return "", fmt.Errorf("account not found")
|
||||
if acc == nil || err != nil {
|
||||
return hexutil.Encode(common.LeftPadBytes(empty[:], 32)), err
|
||||
}
|
||||
|
||||
location := common.HexToHash(index)
|
||||
|
||||
res, err := reader.ReadAccountStorage(address, acc.Incarnation, &location)
|
||||
if err != nil {
|
||||
return "", err
|
||||
res = empty
|
||||
}
|
||||
|
||||
return hexutil.Encode(res), nil
|
||||
return hexutil.Encode(common.LeftPadBytes(res[:], 32)), err
|
||||
}
|
||||
|
||||
// GetCode returns the code stored at the given address in the state for the given block number.
|
||||
@ -255,3 +257,18 @@ func (api *APIImpl) GetCode(ctx context.Context, address common.Address, blockNr
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetTransactionCount returns the number of transactions the given address has sent for the given block number
|
||||
func (api *APIImpl) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) {
|
||||
blockNumber, _, err := rpchelper.GetBlockNumber(blockNrOrHash, api.dbReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nonce := hexutil.Uint64(0)
|
||||
reader := adapter.NewStateReader(api.db, blockNumber)
|
||||
acc, err := reader.ReadAccountData(address)
|
||||
if acc == nil || err != nil {
|
||||
return &nonce, err
|
||||
}
|
||||
return (*hexutil.Uint64)(&acc.Nonce), err
|
||||
}
|
||||
|
83
cmd/rpcdaemon/commands/get_uncles.go
Normal file
83
cmd/rpcdaemon/commands/get_uncles.go
Normal file
@ -0,0 +1,83 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/ledgerwatch/turbo-geth/common"
|
||||
"github.com/ledgerwatch/turbo-geth/common/hexutil"
|
||||
"github.com/ledgerwatch/turbo-geth/core/rawdb"
|
||||
"github.com/ledgerwatch/turbo-geth/core/types"
|
||||
"github.com/ledgerwatch/turbo-geth/log"
|
||||
"github.com/ledgerwatch/turbo-geth/rpc"
|
||||
"github.com/ledgerwatch/turbo-geth/turbo/adapter/ethapi"
|
||||
)
|
||||
|
||||
// GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true
|
||||
// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
||||
func (api *APIImpl) GetUncleByBlockNumberAndIndex(ctx context.Context, number rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) {
|
||||
blockNum, err := getBlockNumber(number, api.dbReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block := rawdb.ReadBlockByNumber(api.dbReader, blockNum)
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("block not found: %d", blockNum)
|
||||
}
|
||||
hash := block.Hash()
|
||||
additionalFields := make(map[string]interface{})
|
||||
additionalFields["totalDifficulty"] = (*hexutil.Big)(rawdb.ReadTd(api.dbReader, block.Hash(), blockNum))
|
||||
|
||||
uncles := block.Uncles()
|
||||
if index >= hexutil.Uint(len(uncles)) {
|
||||
log.Debug("Requested uncle not found", "number", block.Number(), "hash", hash, "index", index)
|
||||
return nil, nil
|
||||
}
|
||||
uncle := types.NewBlockWithHeader(uncles[index])
|
||||
return ethapi.RPCMarshalBlock(uncle, false, false, additionalFields)
|
||||
}
|
||||
|
||||
// GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. When fullTx is true
|
||||
// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
||||
func (api *APIImpl) GetUncleByBlockHashAndIndex(ctx context.Context, hash common.Hash, index hexutil.Uint) (map[string]interface{}, error) {
|
||||
block := rawdb.ReadBlockByHash(api.dbReader, hash)
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("block not found: %x", hash)
|
||||
}
|
||||
number := block.NumberU64()
|
||||
additionalFields := make(map[string]interface{})
|
||||
additionalFields["totalDifficulty"] = (*hexutil.Big)(rawdb.ReadTd(api.dbReader, hash, number))
|
||||
|
||||
uncles := block.Uncles()
|
||||
if index >= hexutil.Uint(len(uncles)) {
|
||||
log.Debug("Requested uncle not found", "number", block.Number(), "hash", hash, "index", index)
|
||||
return nil, nil
|
||||
}
|
||||
uncle := types.NewBlockWithHeader(uncles[index])
|
||||
|
||||
return ethapi.RPCMarshalBlock(uncle, false, false, additionalFields)
|
||||
}
|
||||
|
||||
// GetUncleCountByBlockNumber returns number of uncles in the block for the given block number
|
||||
func (api *APIImpl) GetUncleCountByBlockNumber(ctx context.Context, number rpc.BlockNumber) *hexutil.Uint {
|
||||
n := hexutil.Uint(0)
|
||||
blockNum, err := getBlockNumber(number, api.dbReader)
|
||||
if err != nil {
|
||||
return &n
|
||||
}
|
||||
block := rawdb.ReadBlockByNumber(api.dbReader, blockNum)
|
||||
if block != nil {
|
||||
n = hexutil.Uint(len(block.Uncles()))
|
||||
}
|
||||
return &n
|
||||
}
|
||||
|
||||
// GetUncleCountByBlockHash returns number of uncles in the block for the given block hash
|
||||
func (api *APIImpl) GetUncleCountByBlockHash(ctx context.Context, hash common.Hash) *hexutil.Uint {
|
||||
n := hexutil.Uint(0)
|
||||
block := rawdb.ReadBlockByHash(api.dbReader, hash)
|
||||
if block != nil {
|
||||
n = hexutil.Uint(len(block.Uncles()))
|
||||
}
|
||||
return &n
|
||||
}
|
Loading…
Reference in New Issue
Block a user