api: ethrpc: implement a few ethereum JSON-RPC API methods (#9208)

This commit is contained in:
Kevin Li 2022-09-09 13:59:00 -04:00 committed by vyzo
parent ef90ba7cef
commit 4652d8559f
12 changed files with 1631 additions and 0 deletions

View File

@ -758,6 +758,37 @@ type FullNode interface {
NodeStatus(ctx context.Context, inclChainStatus bool) (NodeStatus, error) //perm:read
// MethodGroup: Eth
// These methods are used for Ethereum-compatible JSON-RPC calls
//
// EthAccounts will always return [] since we don't expect Lotus to manage private keys
EthAccounts(ctx context.Context) ([]EthAddress, error) //perm:read
// EthBlockNumber returns the height of the latest (heaviest) TipSet
EthBlockNumber(ctx context.Context) (EthInt, error) //perm:read
// EthGetBlockTransactionCountByNumber returns the number of messages in the TipSet
EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum EthInt) (EthInt, error) //perm:read
// EthGetBlockTransactionCountByHash returns the number of messages in the TipSet
EthGetBlockTransactionCountByHash(ctx context.Context, blkHash EthHash) (EthInt, error) //perm:read
EthGetBlockByHash(ctx context.Context, blkHash EthHash, fullTxInfo bool) (EthBlock, error) //perm:read
EthGetBlockByNumber(ctx context.Context, blkNum EthInt, fullTxInfo bool) (EthBlock, error) //perm:read
EthGetTransactionByHash(ctx context.Context, txHash EthHash) (EthTx, error) //perm:read
EthGetTransactionCount(ctx context.Context, sender EthAddress, blkOpt string) (EthInt, error) //perm:read
EthGetTransactionReceipt(ctx context.Context, blkHash EthHash) (EthTxReceipt, error) //perm:read
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash EthHash, txIndex EthInt) (EthTx, error) //perm:read
EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum EthInt, txIndex EthInt) (EthTx, error) //perm:read
EthGetCode(ctx context.Context, address EthAddress) (string, error) //perm:read
EthGetStorageAt(ctx context.Context, address EthAddress, position EthInt, blkParam string) (string, error) //perm:read
EthGetBalance(ctx context.Context, address EthAddress, blkParam string) (EthBigInt, error) //perm:read
EthChainId(ctx context.Context) (EthInt, error) //perm:read
NetVersion(ctx context.Context) (string, error) //perm:read
NetListening(ctx context.Context) (bool, error) //perm:read
EthProtocolVersion(ctx context.Context) (EthInt, error) //perm:read
EthMaxPriorityFeePerGas(ctx context.Context) (EthInt, error) //perm:read
EthGasPrice(ctx context.Context) (EthInt, error) //perm:read
// EthSendRawTransaction(ctx context.Context, tx api.EthTx) (EthHash, error) //perm:write
// CreateBackup creates node backup onder the specified file name. The
// method requires that the lotus daemon is running with the
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that

239
api/eth_types.go Normal file
View File

@ -0,0 +1,239 @@
package api
import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/ipfs/go-cid"
"github.com/multiformats/go-multihash"
xerrors "golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/big"
)
type EthInt int64
func (e EthInt) MarshalJSON() ([]byte, error) {
return json.Marshal(fmt.Sprintf("0x%x", e))
}
func (e *EthInt) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
parsedInt, err := strconv.ParseInt(strings.Replace(s, "0x", "", -1), 16, 64)
if err != nil {
return err
}
eint := EthInt(parsedInt)
e = &eint
return nil
}
type EthBigInt big.Int
func (e EthBigInt) MarshalJSON() ([]byte, error) {
if e.Int == nil {
return json.Marshal("0x0")
}
return json.Marshal(fmt.Sprintf("0x%x", e.Int))
}
type EthBlock struct {
ParentHash EthHash `json:"parentHash"`
Sha3Uncles EthHash `json:"sha3Uncles"`
Miner EthAddress `json:"miner"`
StateRoot EthHash `json:"stateRoot"`
TransactionsRoot EthHash `json:"transactionsRoot"`
ReceiptsRoot EthHash `json:"receiptsRoot"`
// TODO: include LogsBloom
Difficulty EthInt `json:"difficulty"`
Number EthInt `json:"number"`
GasLimit EthInt `json:"gasLimit"`
GasUsed EthInt `json:"gasUsed"`
Timestamp EthInt `json:"timestamp"`
Extradata []byte `json:"extraData"`
MixHash EthHash `json:"mixHash"`
Nonce EthNonce `json:"nonce"`
BaseFeePerGas EthInt `json:"baseFeePerGas"`
Transactions EthTx `json:"transactions"`
}
type EthTx struct {
ChainID *EthInt `json:"chainId"`
Nonce uint64 `json:"nonce"`
Hash EthHash `json:"hash"`
BlockHash EthHash `json:"blockHash"`
BlockNumber EthHash `json:"blockNumber"`
TransactionIndex EthInt `json:"transacionIndex"`
From EthAddress `json:"from"`
To EthAddress `json:"to"`
Value EthBigInt `json:"value"`
Type EthInt `json:"type"`
Input []byte `json:"input"`
Gas EthInt `json:"gas"`
MaxFeePerGas EthBigInt `json:"maxFeePerGas"`
MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"`
V EthBigInt `json:"v"`
R EthBigInt `json:"r"`
S EthBigInt `json:"s"`
}
type EthTxReceipt struct {
TransactionHash EthHash `json:"transactionHash"`
TransactionIndex EthInt `json:"transacionIndex"`
BlockHash EthHash `json:"blockHash"`
BlockNumber EthHash `json:"blockNumber"`
From EthAddress `json:"from"`
To EthAddress `json:"to"`
// Logs
// LogsBloom
StateRoot EthHash `json:"root"`
Status EthInt `json:"status"`
ContractAddress *EthAddress `json:"contractAddress"`
CumulativeGasUsed EthBigInt `json:"cumulativeGasUsed"`
GasUsed EthBigInt `json:"gasUsed"`
EffectiveGasPrice EthBigInt `json:"effectiveGasPrice"`
}
const (
ETH_ADDRESS_LENGTH = 20
ETH_HASH_LENGTH = 32
)
type EthNonce [8]byte
func (n EthNonce) String() string {
return "0x" + hex.EncodeToString(n[:])
}
func (n EthNonce) MarshalJSON() ([]byte, error) {
return json.Marshal((n.String()))
}
type EthAddress [ETH_ADDRESS_LENGTH]byte
func (a EthAddress) String() string {
return "0x" + hex.EncodeToString(a[:])
}
func (a EthAddress) MarshalJSON() ([]byte, error) {
return json.Marshal((a.String()))
}
func (a *EthAddress) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
addr, err := EthAddressFromHex(s)
if err != nil {
return err
}
a = &addr
return nil
}
func (a EthAddress) ToFilecoinAddress() (address.Address, error) {
id := binary.BigEndian.Uint64(a[12:])
return address.NewIDAddress(id)
}
func EthAddressFromFilecoinIDAddress(addr address.Address) (EthAddress, error) {
id, err := address.IDFromAddress(addr)
if err != nil {
return EthAddress{}, err
}
buf := make([]byte, ETH_ADDRESS_LENGTH)
buf[0] = 0xff
binary.BigEndian.PutUint64(buf[12:], id)
var ethaddr EthAddress
copy(ethaddr[:], buf)
return ethaddr, nil
}
func EthAddressFromHex(s string) (EthAddress, error) {
handlePrefix(&s)
b, err := decodeHexString(s, ETH_ADDRESS_LENGTH)
if err != nil {
return EthAddress{}, err
}
var h EthAddress
copy(h[ETH_ADDRESS_LENGTH-len(b):], b)
return h, nil
}
type EthHash [ETH_HASH_LENGTH]byte
func (h EthHash) MarshalJSON() ([]byte, error) {
return json.Marshal(h.String())
}
func (h *EthHash) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
hash, err := EthHashFromHex(s)
if err != nil {
return err
}
h = &hash
return nil
}
func handlePrefix(s *string) {
if strings.HasPrefix(*s, "0x") || strings.HasPrefix(*s, "0X") {
*s = (*s)[2:]
}
if len(*s)%2 == 1 {
*s = "0" + *s
}
}
func decodeHexString(s string, length int) ([]byte, error) {
b, err := hex.DecodeString(s)
if err != nil {
return []byte{}, xerrors.Errorf("cannot parse hash: %w", err)
}
if len(b) > length {
return []byte{}, xerrors.Errorf("length of decoded bytes is longer than %d", length)
}
return b, nil
}
func EthHashFromCid(c cid.Cid) (EthHash, error) {
return EthHashFromHex(c.Hash().HexString()[8:])
}
func EthHashFromHex(s string) (EthHash, error) {
handlePrefix(&s)
b, err := decodeHexString(s, ETH_HASH_LENGTH)
if err != nil {
return EthHash{}, err
}
var h EthHash
copy(h[ETH_HASH_LENGTH-len(b):], b)
return h, nil
}
func (h EthHash) String() string {
return "0x" + hex.EncodeToString(h[:])
}
func (h EthHash) ToCid() cid.Cid {
// err is always nil
mh, _ := multihash.EncodeName(h[:], "blake2b-256")
return cid.NewCidV1(cid.DagCBOR, mh)
}

96
api/eth_types_test.go Normal file
View File

@ -0,0 +1,96 @@
//stm: #unit
package api
import (
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/big"
)
type TestCase struct {
Input interface{}
Output interface{}
}
func TestEthIntMarshalJSON(t *testing.T) {
// https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding
testcases := []TestCase{
{EthInt(0), []byte("\"0x0\"")},
{EthInt(65), []byte("\"0x41\"")},
{EthInt(1024), []byte("\"0x400\"")},
}
for _, tc := range testcases {
j, err := tc.Input.(EthInt).MarshalJSON()
require.Nil(t, err)
require.Equal(t, j, tc.Output)
}
}
func TestEthBigIntMarshalJSON(t *testing.T) {
testcases := []TestCase{
{EthBigInt(big.NewInt(0)), []byte("\"0x0\"")},
{EthBigInt(big.NewInt(65)), []byte("\"0x41\"")},
{EthBigInt(big.NewInt(1024)), []byte("\"0x400\"")},
{EthBigInt(big.Int{}), []byte("\"0x0\"")},
}
for _, tc := range testcases {
j, err := tc.Input.(EthBigInt).MarshalJSON()
require.Nil(t, err)
require.Equal(t, j, tc.Output)
}
}
func TestEthHash(t *testing.T) {
testcases := []string{
"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184",
"0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738",
}
for _, hash := range testcases {
h, err := EthHashFromHex(hash)
require.Nil(t, err)
require.Equal(t, h.String(), hash)
c := h.ToCid()
h1, err := EthHashFromCid(c)
require.Nil(t, err)
require.Equal(t, h, h1)
}
}
func TestEthAddr(t *testing.T) {
testcases := []string{
strings.ToLower("0xd4c5fb16488Aa48081296299d54b0c648C9333dA"),
strings.ToLower("0x2C2EC67e3e1FeA8e4A39601cB3A3Cd44f5fa830d"),
strings.ToLower("0x01184F793982104363F9a8a5845743f452dE0586"),
}
for _, addr := range testcases {
a, err := EthAddressFromHex(addr)
require.Nil(t, err)
require.Equal(t, a.String(), addr)
}
}
func TestParseEthAddr(t *testing.T) {
testcases := []uint64{
1, 2, 3, 100, 101,
}
for _, id := range testcases {
addr, err := address.NewIDAddress(id)
require.Nil(t, err)
eaddr, err := EthAddressFromFilecoinIDAddress(addr)
require.Nil(t, err)
faddr, err := eaddr.ToFilecoinAddress()
require.Nil(t, err)
require.Equal(t, addr, faddr)
}
}

View File

@ -921,6 +921,276 @@ func (mr *MockFullNodeMockRecorder) Discover(arg0 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Discover", reflect.TypeOf((*MockFullNode)(nil).Discover), arg0)
}
// EthAccounts mocks base method.
func (m *MockFullNode) EthAccounts(arg0 context.Context) ([]api.EthAddress, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthAccounts", arg0)
ret0, _ := ret[0].([]api.EthAddress)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthAccounts indicates an expected call of EthAccounts.
func (mr *MockFullNodeMockRecorder) EthAccounts(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthAccounts", reflect.TypeOf((*MockFullNode)(nil).EthAccounts), arg0)
}
// EthBlockNumber mocks base method.
func (m *MockFullNode) EthBlockNumber(arg0 context.Context) (api.EthInt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthBlockNumber", arg0)
ret0, _ := ret[0].(api.EthInt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthBlockNumber indicates an expected call of EthBlockNumber.
func (mr *MockFullNodeMockRecorder) EthBlockNumber(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthBlockNumber", reflect.TypeOf((*MockFullNode)(nil).EthBlockNumber), arg0)
}
// EthChainId mocks base method.
func (m *MockFullNode) EthChainId(arg0 context.Context) (api.EthInt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthChainId", arg0)
ret0, _ := ret[0].(api.EthInt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthChainId indicates an expected call of EthChainId.
func (mr *MockFullNodeMockRecorder) EthChainId(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthChainId", reflect.TypeOf((*MockFullNode)(nil).EthChainId), arg0)
}
// EthGasPrice mocks base method.
func (m *MockFullNode) EthGasPrice(arg0 context.Context) (api.EthInt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGasPrice", arg0)
ret0, _ := ret[0].(api.EthInt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGasPrice indicates an expected call of EthGasPrice.
func (mr *MockFullNodeMockRecorder) EthGasPrice(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGasPrice", reflect.TypeOf((*MockFullNode)(nil).EthGasPrice), arg0)
}
// EthGetBalance mocks base method.
func (m *MockFullNode) EthGetBalance(arg0 context.Context, arg1 api.EthAddress, arg2 string) (api.EthBigInt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetBalance", arg0, arg1, arg2)
ret0, _ := ret[0].(api.EthBigInt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetBalance indicates an expected call of EthGetBalance.
func (mr *MockFullNodeMockRecorder) EthGetBalance(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBalance", reflect.TypeOf((*MockFullNode)(nil).EthGetBalance), arg0, arg1, arg2)
}
// EthGetBlockByHash mocks base method.
func (m *MockFullNode) EthGetBlockByHash(arg0 context.Context, arg1 api.EthHash, arg2 bool) (api.EthBlock, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetBlockByHash", arg0, arg1, arg2)
ret0, _ := ret[0].(api.EthBlock)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetBlockByHash indicates an expected call of EthGetBlockByHash.
func (mr *MockFullNodeMockRecorder) EthGetBlockByHash(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockByHash", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockByHash), arg0, arg1, arg2)
}
// EthGetBlockByNumber mocks base method.
func (m *MockFullNode) EthGetBlockByNumber(arg0 context.Context, arg1 api.EthInt, arg2 bool) (api.EthBlock, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetBlockByNumber", arg0, arg1, arg2)
ret0, _ := ret[0].(api.EthBlock)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetBlockByNumber indicates an expected call of EthGetBlockByNumber.
func (mr *MockFullNodeMockRecorder) EthGetBlockByNumber(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockByNumber", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockByNumber), arg0, arg1, arg2)
}
// EthGetBlockTransactionCountByHash mocks base method.
func (m *MockFullNode) EthGetBlockTransactionCountByHash(arg0 context.Context, arg1 api.EthHash) (api.EthInt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetBlockTransactionCountByHash", arg0, arg1)
ret0, _ := ret[0].(api.EthInt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetBlockTransactionCountByHash indicates an expected call of EthGetBlockTransactionCountByHash.
func (mr *MockFullNodeMockRecorder) EthGetBlockTransactionCountByHash(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockTransactionCountByHash", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockTransactionCountByHash), arg0, arg1)
}
// EthGetBlockTransactionCountByNumber mocks base method.
func (m *MockFullNode) EthGetBlockTransactionCountByNumber(arg0 context.Context, arg1 api.EthInt) (api.EthInt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetBlockTransactionCountByNumber", arg0, arg1)
ret0, _ := ret[0].(api.EthInt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetBlockTransactionCountByNumber indicates an expected call of EthGetBlockTransactionCountByNumber.
func (mr *MockFullNodeMockRecorder) EthGetBlockTransactionCountByNumber(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockTransactionCountByNumber", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockTransactionCountByNumber), arg0, arg1)
}
// EthGetCode mocks base method.
func (m *MockFullNode) EthGetCode(arg0 context.Context, arg1 api.EthAddress) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetCode", arg0, arg1)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetCode indicates an expected call of EthGetCode.
func (mr *MockFullNodeMockRecorder) EthGetCode(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetCode", reflect.TypeOf((*MockFullNode)(nil).EthGetCode), arg0, arg1)
}
// EthGetStorageAt mocks base method.
func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 api.EthAddress, arg2 api.EthInt, arg3 string) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetStorageAt", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetStorageAt indicates an expected call of EthGetStorageAt.
func (mr *MockFullNodeMockRecorder) EthGetStorageAt(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetStorageAt", reflect.TypeOf((*MockFullNode)(nil).EthGetStorageAt), arg0, arg1, arg2, arg3)
}
// EthGetTransactionByBlockHashAndIndex mocks base method.
func (m *MockFullNode) EthGetTransactionByBlockHashAndIndex(arg0 context.Context, arg1 api.EthHash, arg2 api.EthInt) (api.EthTx, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetTransactionByBlockHashAndIndex", arg0, arg1, arg2)
ret0, _ := ret[0].(api.EthTx)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetTransactionByBlockHashAndIndex indicates an expected call of EthGetTransactionByBlockHashAndIndex.
func (mr *MockFullNodeMockRecorder) EthGetTransactionByBlockHashAndIndex(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionByBlockHashAndIndex", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionByBlockHashAndIndex), arg0, arg1, arg2)
}
// EthGetTransactionByBlockNumberAndIndex mocks base method.
func (m *MockFullNode) EthGetTransactionByBlockNumberAndIndex(arg0 context.Context, arg1, arg2 api.EthInt) (api.EthTx, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetTransactionByBlockNumberAndIndex", arg0, arg1, arg2)
ret0, _ := ret[0].(api.EthTx)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetTransactionByBlockNumberAndIndex indicates an expected call of EthGetTransactionByBlockNumberAndIndex.
func (mr *MockFullNodeMockRecorder) EthGetTransactionByBlockNumberAndIndex(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionByBlockNumberAndIndex", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionByBlockNumberAndIndex), arg0, arg1, arg2)
}
// EthGetTransactionByHash mocks base method.
func (m *MockFullNode) EthGetTransactionByHash(arg0 context.Context, arg1 api.EthHash) (api.EthTx, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetTransactionByHash", arg0, arg1)
ret0, _ := ret[0].(api.EthTx)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetTransactionByHash indicates an expected call of EthGetTransactionByHash.
func (mr *MockFullNodeMockRecorder) EthGetTransactionByHash(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionByHash", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionByHash), arg0, arg1)
}
// EthGetTransactionCount mocks base method.
func (m *MockFullNode) EthGetTransactionCount(arg0 context.Context, arg1 api.EthAddress, arg2 string) (api.EthInt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetTransactionCount", arg0, arg1, arg2)
ret0, _ := ret[0].(api.EthInt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetTransactionCount indicates an expected call of EthGetTransactionCount.
func (mr *MockFullNodeMockRecorder) EthGetTransactionCount(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionCount", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionCount), arg0, arg1, arg2)
}
// EthGetTransactionReceipt mocks base method.
func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 api.EthHash) (api.EthTxReceipt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetTransactionReceipt", arg0, arg1)
ret0, _ := ret[0].(api.EthTxReceipt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetTransactionReceipt indicates an expected call of EthGetTransactionReceipt.
func (mr *MockFullNodeMockRecorder) EthGetTransactionReceipt(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionReceipt", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionReceipt), arg0, arg1)
}
// EthMaxPriorityFeePerGas mocks base method.
func (m *MockFullNode) EthMaxPriorityFeePerGas(arg0 context.Context) (api.EthInt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthMaxPriorityFeePerGas", arg0)
ret0, _ := ret[0].(api.EthInt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthMaxPriorityFeePerGas indicates an expected call of EthMaxPriorityFeePerGas.
func (mr *MockFullNodeMockRecorder) EthMaxPriorityFeePerGas(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthMaxPriorityFeePerGas", reflect.TypeOf((*MockFullNode)(nil).EthMaxPriorityFeePerGas), arg0)
}
// EthProtocolVersion mocks base method.
func (m *MockFullNode) EthProtocolVersion(arg0 context.Context) (api.EthInt, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthProtocolVersion", arg0)
ret0, _ := ret[0].(api.EthInt)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthProtocolVersion indicates an expected call of EthProtocolVersion.
func (mr *MockFullNodeMockRecorder) EthProtocolVersion(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthProtocolVersion", reflect.TypeOf((*MockFullNode)(nil).EthProtocolVersion), arg0)
}
// GasEstimateFeeCap mocks base method.
func (m *MockFullNode) GasEstimateFeeCap(arg0 context.Context, arg1 *types.Message, arg2 int64, arg3 types.TipSetKey) (big.Int, error) {
m.ctrl.T.Helper()
@ -1843,6 +2113,21 @@ func (mr *MockFullNodeMockRecorder) NetLimit(arg0, arg1 interface{}) *gomock.Cal
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetLimit", reflect.TypeOf((*MockFullNode)(nil).NetLimit), arg0, arg1)
}
// NetListening mocks base method.
func (m *MockFullNode) NetListening(arg0 context.Context) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NetListening", arg0)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// NetListening indicates an expected call of NetListening.
func (mr *MockFullNodeMockRecorder) NetListening(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetListening", reflect.TypeOf((*MockFullNode)(nil).NetListening), arg0)
}
// NetPeerInfo mocks base method.
func (m *MockFullNode) NetPeerInfo(arg0 context.Context, arg1 peer.ID) (*api.ExtendedPeerInfo, error) {
m.ctrl.T.Helper()
@ -1975,6 +2260,21 @@ func (mr *MockFullNodeMockRecorder) NetStat(arg0, arg1 interface{}) *gomock.Call
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetStat", reflect.TypeOf((*MockFullNode)(nil).NetStat), arg0, arg1)
}
// NetVersion mocks base method.
func (m *MockFullNode) NetVersion(arg0 context.Context) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NetVersion", arg0)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// NetVersion indicates an expected call of NetVersion.
func (mr *MockFullNodeMockRecorder) NetVersion(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetVersion", reflect.TypeOf((*MockFullNode)(nil).NetVersion), arg0)
}
// NodeStatus mocks base method.
func (m *MockFullNode) NodeStatus(arg0 context.Context, arg1 bool) (api.NodeStatus, error) {
m.ctrl.T.Helper()

View File

@ -218,6 +218,42 @@ type FullNodeStruct struct {
CreateBackup func(p0 context.Context, p1 string) error `perm:"admin"`
EthAccounts func(p0 context.Context) ([]EthAddress, error) `perm:"read"`
EthBlockNumber func(p0 context.Context) (EthInt, error) `perm:"read"`
EthChainId func(p0 context.Context) (EthInt, error) `perm:"read"`
EthGasPrice func(p0 context.Context) (EthInt, error) ``
EthGetBalance func(p0 context.Context, p1 EthAddress, p2 string) (EthBigInt, error) `perm:"read"`
EthGetBlockByHash func(p0 context.Context, p1 EthHash, p2 bool) (EthBlock, error) `perm:"read"`
EthGetBlockByNumber func(p0 context.Context, p1 EthInt, p2 bool) (EthBlock, error) `perm:"read"`
EthGetBlockTransactionCountByHash func(p0 context.Context, p1 EthHash) (EthInt, error) `perm:"read"`
EthGetBlockTransactionCountByNumber func(p0 context.Context, p1 EthInt) (EthInt, error) `perm:"read"`
EthGetCode func(p0 context.Context, p1 EthAddress) (string, error) `perm:"read"`
EthGetStorageAt func(p0 context.Context, p1 EthAddress, p2 EthInt, p3 string) (string, error) `perm:"read"`
EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 EthHash, p2 EthInt) (EthTx, error) `perm:"read"`
EthGetTransactionByBlockNumberAndIndex func(p0 context.Context, p1 EthInt, p2 EthInt) (EthTx, error) `perm:"read"`
EthGetTransactionByHash func(p0 context.Context, p1 EthHash) (EthTx, error) `perm:"read"`
EthGetTransactionCount func(p0 context.Context, p1 EthAddress, p2 string) (EthInt, error) `perm:"read"`
EthGetTransactionReceipt func(p0 context.Context, p1 EthHash) (EthTxReceipt, error) `perm:"read"`
EthMaxPriorityFeePerGas func(p0 context.Context) (EthInt, error) `perm:"read"`
EthProtocolVersion func(p0 context.Context) (EthInt, error) `perm:"read"`
GasEstimateFeeCap func(p0 context.Context, p1 *types.Message, p2 int64, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"`
GasEstimateGasLimit func(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (int64, error) `perm:"read"`
@ -306,6 +342,10 @@ type FullNodeStruct struct {
MsigSwapPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 address.Address) (*MessagePrototype, error) `perm:"sign"`
NetListening func(p0 context.Context) (bool, error) `perm:"read"`
NetVersion func(p0 context.Context) (string, error) `perm:"read"`
NodeStatus func(p0 context.Context, p1 bool) (NodeStatus, error) `perm:"read"`
PaychAllocateLane func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"sign"`
@ -1791,6 +1831,204 @@ func (s *FullNodeStub) CreateBackup(p0 context.Context, p1 string) error {
return ErrNotSupported
}
func (s *FullNodeStruct) EthAccounts(p0 context.Context) ([]EthAddress, error) {
if s.Internal.EthAccounts == nil {
return *new([]EthAddress), ErrNotSupported
}
return s.Internal.EthAccounts(p0)
}
func (s *FullNodeStub) EthAccounts(p0 context.Context) ([]EthAddress, error) {
return *new([]EthAddress), ErrNotSupported
}
func (s *FullNodeStruct) EthBlockNumber(p0 context.Context) (EthInt, error) {
if s.Internal.EthBlockNumber == nil {
return *new(EthInt), ErrNotSupported
}
return s.Internal.EthBlockNumber(p0)
}
func (s *FullNodeStub) EthBlockNumber(p0 context.Context) (EthInt, error) {
return *new(EthInt), ErrNotSupported
}
func (s *FullNodeStruct) EthChainId(p0 context.Context) (EthInt, error) {
if s.Internal.EthChainId == nil {
return *new(EthInt), ErrNotSupported
}
return s.Internal.EthChainId(p0)
}
func (s *FullNodeStub) EthChainId(p0 context.Context) (EthInt, error) {
return *new(EthInt), ErrNotSupported
}
func (s *FullNodeStruct) EthGasPrice(p0 context.Context) (EthInt, error) {
if s.Internal.EthGasPrice == nil {
return *new(EthInt), ErrNotSupported
}
return s.Internal.EthGasPrice(p0)
}
func (s *FullNodeStub) EthGasPrice(p0 context.Context) (EthInt, error) {
return *new(EthInt), ErrNotSupported
}
func (s *FullNodeStruct) EthGetBalance(p0 context.Context, p1 EthAddress, p2 string) (EthBigInt, error) {
if s.Internal.EthGetBalance == nil {
return *new(EthBigInt), ErrNotSupported
}
return s.Internal.EthGetBalance(p0, p1, p2)
}
func (s *FullNodeStub) EthGetBalance(p0 context.Context, p1 EthAddress, p2 string) (EthBigInt, error) {
return *new(EthBigInt), ErrNotSupported
}
func (s *FullNodeStruct) EthGetBlockByHash(p0 context.Context, p1 EthHash, p2 bool) (EthBlock, error) {
if s.Internal.EthGetBlockByHash == nil {
return *new(EthBlock), ErrNotSupported
}
return s.Internal.EthGetBlockByHash(p0, p1, p2)
}
func (s *FullNodeStub) EthGetBlockByHash(p0 context.Context, p1 EthHash, p2 bool) (EthBlock, error) {
return *new(EthBlock), ErrNotSupported
}
func (s *FullNodeStruct) EthGetBlockByNumber(p0 context.Context, p1 EthInt, p2 bool) (EthBlock, error) {
if s.Internal.EthGetBlockByNumber == nil {
return *new(EthBlock), ErrNotSupported
}
return s.Internal.EthGetBlockByNumber(p0, p1, p2)
}
func (s *FullNodeStub) EthGetBlockByNumber(p0 context.Context, p1 EthInt, p2 bool) (EthBlock, error) {
return *new(EthBlock), ErrNotSupported
}
func (s *FullNodeStruct) EthGetBlockTransactionCountByHash(p0 context.Context, p1 EthHash) (EthInt, error) {
if s.Internal.EthGetBlockTransactionCountByHash == nil {
return *new(EthInt), ErrNotSupported
}
return s.Internal.EthGetBlockTransactionCountByHash(p0, p1)
}
func (s *FullNodeStub) EthGetBlockTransactionCountByHash(p0 context.Context, p1 EthHash) (EthInt, error) {
return *new(EthInt), ErrNotSupported
}
func (s *FullNodeStruct) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 EthInt) (EthInt, error) {
if s.Internal.EthGetBlockTransactionCountByNumber == nil {
return *new(EthInt), ErrNotSupported
}
return s.Internal.EthGetBlockTransactionCountByNumber(p0, p1)
}
func (s *FullNodeStub) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 EthInt) (EthInt, error) {
return *new(EthInt), ErrNotSupported
}
func (s *FullNodeStruct) EthGetCode(p0 context.Context, p1 EthAddress) (string, error) {
if s.Internal.EthGetCode == nil {
return "", ErrNotSupported
}
return s.Internal.EthGetCode(p0, p1)
}
func (s *FullNodeStub) EthGetCode(p0 context.Context, p1 EthAddress) (string, error) {
return "", ErrNotSupported
}
func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 EthAddress, p2 EthInt, p3 string) (string, error) {
if s.Internal.EthGetStorageAt == nil {
return "", ErrNotSupported
}
return s.Internal.EthGetStorageAt(p0, p1, p2, p3)
}
func (s *FullNodeStub) EthGetStorageAt(p0 context.Context, p1 EthAddress, p2 EthInt, p3 string) (string, error) {
return "", ErrNotSupported
}
func (s *FullNodeStruct) EthGetTransactionByBlockHashAndIndex(p0 context.Context, p1 EthHash, p2 EthInt) (EthTx, error) {
if s.Internal.EthGetTransactionByBlockHashAndIndex == nil {
return *new(EthTx), ErrNotSupported
}
return s.Internal.EthGetTransactionByBlockHashAndIndex(p0, p1, p2)
}
func (s *FullNodeStub) EthGetTransactionByBlockHashAndIndex(p0 context.Context, p1 EthHash, p2 EthInt) (EthTx, error) {
return *new(EthTx), ErrNotSupported
}
func (s *FullNodeStruct) EthGetTransactionByBlockNumberAndIndex(p0 context.Context, p1 EthInt, p2 EthInt) (EthTx, error) {
if s.Internal.EthGetTransactionByBlockNumberAndIndex == nil {
return *new(EthTx), ErrNotSupported
}
return s.Internal.EthGetTransactionByBlockNumberAndIndex(p0, p1, p2)
}
func (s *FullNodeStub) EthGetTransactionByBlockNumberAndIndex(p0 context.Context, p1 EthInt, p2 EthInt) (EthTx, error) {
return *new(EthTx), ErrNotSupported
}
func (s *FullNodeStruct) EthGetTransactionByHash(p0 context.Context, p1 EthHash) (EthTx, error) {
if s.Internal.EthGetTransactionByHash == nil {
return *new(EthTx), ErrNotSupported
}
return s.Internal.EthGetTransactionByHash(p0, p1)
}
func (s *FullNodeStub) EthGetTransactionByHash(p0 context.Context, p1 EthHash) (EthTx, error) {
return *new(EthTx), ErrNotSupported
}
func (s *FullNodeStruct) EthGetTransactionCount(p0 context.Context, p1 EthAddress, p2 string) (EthInt, error) {
if s.Internal.EthGetTransactionCount == nil {
return *new(EthInt), ErrNotSupported
}
return s.Internal.EthGetTransactionCount(p0, p1, p2)
}
func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 EthAddress, p2 string) (EthInt, error) {
return *new(EthInt), ErrNotSupported
}
func (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 EthHash) (EthTxReceipt, error) {
if s.Internal.EthGetTransactionReceipt == nil {
return *new(EthTxReceipt), ErrNotSupported
}
return s.Internal.EthGetTransactionReceipt(p0, p1)
}
func (s *FullNodeStub) EthGetTransactionReceipt(p0 context.Context, p1 EthHash) (EthTxReceipt, error) {
return *new(EthTxReceipt), ErrNotSupported
}
func (s *FullNodeStruct) EthMaxPriorityFeePerGas(p0 context.Context) (EthInt, error) {
if s.Internal.EthMaxPriorityFeePerGas == nil {
return *new(EthInt), ErrNotSupported
}
return s.Internal.EthMaxPriorityFeePerGas(p0)
}
func (s *FullNodeStub) EthMaxPriorityFeePerGas(p0 context.Context) (EthInt, error) {
return *new(EthInt), ErrNotSupported
}
func (s *FullNodeStruct) EthProtocolVersion(p0 context.Context) (EthInt, error) {
if s.Internal.EthProtocolVersion == nil {
return *new(EthInt), ErrNotSupported
}
return s.Internal.EthProtocolVersion(p0)
}
func (s *FullNodeStub) EthProtocolVersion(p0 context.Context) (EthInt, error) {
return *new(EthInt), ErrNotSupported
}
func (s *FullNodeStruct) GasEstimateFeeCap(p0 context.Context, p1 *types.Message, p2 int64, p3 types.TipSetKey) (types.BigInt, error) {
if s.Internal.GasEstimateFeeCap == nil {
return *new(types.BigInt), ErrNotSupported
@ -2275,6 +2513,28 @@ func (s *FullNodeStub) MsigSwapPropose(p0 context.Context, p1 address.Address, p
return nil, ErrNotSupported
}
func (s *FullNodeStruct) NetListening(p0 context.Context) (bool, error) {
if s.Internal.NetListening == nil {
return false, ErrNotSupported
}
return s.Internal.NetListening(p0)
}
func (s *FullNodeStub) NetListening(p0 context.Context) (bool, error) {
return false, ErrNotSupported
}
func (s *FullNodeStruct) NetVersion(p0 context.Context) (string, error) {
if s.Internal.NetVersion == nil {
return "", ErrNotSupported
}
return s.Internal.NetVersion(p0)
}
func (s *FullNodeStub) NetVersion(p0 context.Context) (string, error) {
return "", ErrNotSupported
}
func (s *FullNodeStruct) NodeStatus(p0 context.Context, p1 bool) (NodeStatus, error) {
if s.Internal.NodeStatus == nil {
return *new(NodeStatus), ErrNotSupported

View File

@ -1,6 +1,7 @@
package store
import (
"bytes"
"context"
"encoding/json"
"errors"
@ -649,6 +650,12 @@ func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet)
return nil
}
tskBlk, err := ts.Key().ToStorageBlock()
if err != nil {
log.Errorf("failed to create a block from tsk: %s", ts.Key())
}
_ = cs.chainLocalBlockstore.Put(ctx, tskBlk)
return nil
}
@ -1165,6 +1172,24 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
return cs.LoadTipSet(ctx, lbts.Parents())
}
func (cs *ChainStore) GetTipSetByCid(ctx context.Context, c cid.Cid) (*types.TipSet, error) {
blk, err := cs.chainBlockstore.Get(ctx, c)
if err != nil {
return nil, xerrors.Errorf("cannot find tipset with cid %s: %w", c, err)
}
tsk := new(types.TipSetKey)
if err := tsk.UnmarshalCBOR(bytes.NewReader(blk.RawData())); err != nil {
return nil, xerrors.Errorf("cannot unmarshal block into tipset key: %w", err)
}
ts, err := cs.GetTipSetFromKey(ctx, *tsk)
if err != nil {
return nil, xerrors.Errorf("cannot get tipset from key: %w", err)
}
return ts, nil
}
func (cs *ChainStore) Weight(ctx context.Context, hts *types.TipSet) (types.BigInt, error) { // todo remove
return cs.weight(ctx, cs.StateBlockstore(), hts)
}

View File

@ -7,6 +7,7 @@ import (
"io"
"strings"
block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
typegen "github.com/whyrusleeping/cbor-gen"
@ -98,6 +99,20 @@ func (k *TipSetKey) UnmarshalJSON(b []byte) error {
return nil
}
func (k TipSetKey) ToStorageBlock() (block.Block, error) {
buf := new(bytes.Buffer)
if err := k.MarshalCBOR(buf); err != nil {
log.Errorf("failed to marshal ts key as CBOR: %s", k)
}
cid, err := abi.CidBuilder.Sum(buf.Bytes())
if err != nil {
return nil, err
}
return block.NewBlockWithCid(buf.Bytes(), cid)
}
func (k TipSetKey) MarshalCBOR(writer io.Writer) error {
if err := typegen.WriteMajorTypeHeader(writer, typegen.MajByteString, uint64(len(k.Bytes()))); err != nil {
return err

View File

@ -65,6 +65,25 @@
* [ClientStatelessDeal](#ClientStatelessDeal)
* [Create](#Create)
* [CreateBackup](#CreateBackup)
* [Eth](#Eth)
* [EthAccounts](#EthAccounts)
* [EthBlockNumber](#EthBlockNumber)
* [EthChainId](#EthChainId)
* [EthGasPrice](#EthGasPrice)
* [EthGetBalance](#EthGetBalance)
* [EthGetBlockByHash](#EthGetBlockByHash)
* [EthGetBlockByNumber](#EthGetBlockByNumber)
* [EthGetBlockTransactionCountByHash](#EthGetBlockTransactionCountByHash)
* [EthGetBlockTransactionCountByNumber](#EthGetBlockTransactionCountByNumber)
* [EthGetCode](#EthGetCode)
* [EthGetStorageAt](#EthGetStorageAt)
* [EthGetTransactionByBlockHashAndIndex](#EthGetTransactionByBlockHashAndIndex)
* [EthGetTransactionByBlockNumberAndIndex](#EthGetTransactionByBlockNumberAndIndex)
* [EthGetTransactionByHash](#EthGetTransactionByHash)
* [EthGetTransactionCount](#EthGetTransactionCount)
* [EthGetTransactionReceipt](#EthGetTransactionReceipt)
* [EthMaxPriorityFeePerGas](#EthMaxPriorityFeePerGas)
* [EthProtocolVersion](#EthProtocolVersion)
* [Gas](#Gas)
* [GasEstimateFeeCap](#GasEstimateFeeCap)
* [GasEstimateGasLimit](#GasEstimateGasLimit)
@ -135,6 +154,7 @@
* [NetDisconnect](#NetDisconnect)
* [NetFindPeer](#NetFindPeer)
* [NetLimit](#NetLimit)
* [NetListening](#NetListening)
* [NetPeerInfo](#NetPeerInfo)
* [NetPeers](#NetPeers)
* [NetPing](#NetPing)
@ -144,6 +164,7 @@
* [NetPubsubScores](#NetPubsubScores)
* [NetSetLimit](#NetSetLimit)
* [NetStat](#NetStat)
* [NetVersion](#NetVersion)
* [Node](#Node)
* [NodeStatus](#NodeStatus)
* [Paych](#Paych)
@ -2122,6 +2143,405 @@ Inputs:
Response: `{}`
## Eth
These methods are used for Ethereum-compatible JSON-RPC calls
EthAccounts will always return [] since we don't expect Lotus to manage private keys
### EthAccounts
There are not yet any comments for this method.
Perms: read
Inputs: `null`
Response:
```json
[
"0x0707070707070707070707070707070707070707"
]
```
### EthBlockNumber
EthBlockNumber returns the height of the latest (heaviest) TipSet
Perms: read
Inputs: `null`
Response: `"0x5"`
### EthChainId
Perms: read
Inputs: `null`
Response: `"0x5"`
### EthGasPrice
Perms:
Inputs: `null`
Response: `"0x5"`
### EthGetBalance
Perms: read
Inputs:
```json
[
"0x0707070707070707070707070707070707070707",
"string value"
]
```
Response: `"0x0"`
### EthGetBlockByHash
Perms: read
Inputs:
```json
[
"0x0707070707070707070707070707070707070707070707070707070707070707",
true
]
```
Response:
```json
{
"parentHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"sha3Uncles": "0x0707070707070707070707070707070707070707070707070707070707070707",
"miner": "0x0707070707070707070707070707070707070707",
"stateRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
"transactionsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
"receiptsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
"difficulty": "0x5",
"number": "0x5",
"gasLimit": "0x5",
"gasUsed": "0x5",
"timestamp": "0x5",
"extraData": "Ynl0ZSBhcnJheQ==",
"mixHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"nonce": "0x0707070707070707",
"baseFeePerGas": "0x5",
"transactions": {
"chainId": "0x5",
"nonce": 42,
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"blockNumber": "0x0707070707070707070707070707070707070707070707070707070707070707",
"transacionIndex": "0x5",
"from": "0x0707070707070707070707070707070707070707",
"to": "0x0707070707070707070707070707070707070707",
"value": "0x0",
"type": "0x5",
"input": "Ynl0ZSBhcnJheQ==",
"gas": "0x5",
"maxFeePerGas": "0x0",
"maxPriorityFeePerGas": "0x0",
"v": "0x0",
"r": "0x0",
"s": "0x0"
}
}
```
### EthGetBlockByNumber
Perms: read
Inputs:
```json
[
"0x5",
true
]
```
Response:
```json
{
"parentHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"sha3Uncles": "0x0707070707070707070707070707070707070707070707070707070707070707",
"miner": "0x0707070707070707070707070707070707070707",
"stateRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
"transactionsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
"receiptsRoot": "0x0707070707070707070707070707070707070707070707070707070707070707",
"difficulty": "0x5",
"number": "0x5",
"gasLimit": "0x5",
"gasUsed": "0x5",
"timestamp": "0x5",
"extraData": "Ynl0ZSBhcnJheQ==",
"mixHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"nonce": "0x0707070707070707",
"baseFeePerGas": "0x5",
"transactions": {
"chainId": "0x5",
"nonce": 42,
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"blockNumber": "0x0707070707070707070707070707070707070707070707070707070707070707",
"transacionIndex": "0x5",
"from": "0x0707070707070707070707070707070707070707",
"to": "0x0707070707070707070707070707070707070707",
"value": "0x0",
"type": "0x5",
"input": "Ynl0ZSBhcnJheQ==",
"gas": "0x5",
"maxFeePerGas": "0x0",
"maxPriorityFeePerGas": "0x0",
"v": "0x0",
"r": "0x0",
"s": "0x0"
}
}
```
### EthGetBlockTransactionCountByHash
EthGetBlockTransactionCountByHash returns the number of messages in the TipSet
Perms: read
Inputs:
```json
[
"0x0707070707070707070707070707070707070707070707070707070707070707"
]
```
Response: `"0x5"`
### EthGetBlockTransactionCountByNumber
EthGetBlockTransactionCountByNumber returns the number of messages in the TipSet
Perms: read
Inputs:
```json
[
"0x5"
]
```
Response: `"0x5"`
### EthGetCode
Perms: read
Inputs:
```json
[
"0x0707070707070707070707070707070707070707"
]
```
Response: `"string value"`
### EthGetStorageAt
Perms: read
Inputs:
```json
[
"0x0707070707070707070707070707070707070707",
"0x5",
"string value"
]
```
Response: `"string value"`
### EthGetTransactionByBlockHashAndIndex
Perms: read
Inputs:
```json
[
"0x0707070707070707070707070707070707070707070707070707070707070707",
"0x5"
]
```
Response:
```json
{
"chainId": "0x5",
"nonce": 42,
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"blockNumber": "0x0707070707070707070707070707070707070707070707070707070707070707",
"transacionIndex": "0x5",
"from": "0x0707070707070707070707070707070707070707",
"to": "0x0707070707070707070707070707070707070707",
"value": "0x0",
"type": "0x5",
"input": "Ynl0ZSBhcnJheQ==",
"gas": "0x5",
"maxFeePerGas": "0x0",
"maxPriorityFeePerGas": "0x0",
"v": "0x0",
"r": "0x0",
"s": "0x0"
}
```
### EthGetTransactionByBlockNumberAndIndex
Perms: read
Inputs:
```json
[
"0x5",
"0x5"
]
```
Response:
```json
{
"chainId": "0x5",
"nonce": 42,
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"blockNumber": "0x0707070707070707070707070707070707070707070707070707070707070707",
"transacionIndex": "0x5",
"from": "0x0707070707070707070707070707070707070707",
"to": "0x0707070707070707070707070707070707070707",
"value": "0x0",
"type": "0x5",
"input": "Ynl0ZSBhcnJheQ==",
"gas": "0x5",
"maxFeePerGas": "0x0",
"maxPriorityFeePerGas": "0x0",
"v": "0x0",
"r": "0x0",
"s": "0x0"
}
```
### EthGetTransactionByHash
Perms: read
Inputs:
```json
[
"0x0707070707070707070707070707070707070707070707070707070707070707"
]
```
Response:
```json
{
"chainId": "0x5",
"nonce": 42,
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"blockNumber": "0x0707070707070707070707070707070707070707070707070707070707070707",
"transacionIndex": "0x5",
"from": "0x0707070707070707070707070707070707070707",
"to": "0x0707070707070707070707070707070707070707",
"value": "0x0",
"type": "0x5",
"input": "Ynl0ZSBhcnJheQ==",
"gas": "0x5",
"maxFeePerGas": "0x0",
"maxPriorityFeePerGas": "0x0",
"v": "0x0",
"r": "0x0",
"s": "0x0"
}
```
### EthGetTransactionCount
Perms: read
Inputs:
```json
[
"0x0707070707070707070707070707070707070707",
"string value"
]
```
Response: `"0x5"`
### EthGetTransactionReceipt
Perms: read
Inputs:
```json
[
"0x0707070707070707070707070707070707070707070707070707070707070707"
]
```
Response:
```json
{
"transactionHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"transacionIndex": "0x5",
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
"blockNumber": "0x0707070707070707070707070707070707070707070707070707070707070707",
"from": "0x0707070707070707070707070707070707070707",
"to": "0x0707070707070707070707070707070707070707",
"root": "0x0707070707070707070707070707070707070707070707070707070707070707",
"status": "0x5",
"contractAddress": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
"cumulativeGasUsed": "0x0",
"gasUsed": "0x0",
"effectiveGasPrice": "0x0"
}
```
### EthMaxPriorityFeePerGas
Perms: read
Inputs: `null`
Response: `"0x5"`
### EthProtocolVersion
Perms: read
Inputs: `null`
Response: `"0x5"`
## Gas
@ -4245,6 +4665,15 @@ Response:
}
```
### NetListening
Perms: read
Inputs: `null`
Response: `true`
### NetPeerInfo
@ -4478,6 +4907,15 @@ Response:
}
```
### NetVersion
Perms: read
Inputs: `null`
Response: `"string value"`
## Node
These methods are general node management and status commands

View File

@ -153,6 +153,7 @@ var ChainNode = Options(
Override(new(messagepool.Provider), messagepool.NewProvider),
Override(new(messagesigner.MpoolNonceAPI), From(new(*messagepool.MessagePool))),
Override(new(full.ChainModuleAPI), From(new(full.ChainModule))),
Override(new(full.EthModuleAPI), From(new(full.EthModule))),
Override(new(full.GasModuleAPI), From(new(full.GasModule))),
Override(new(full.MpoolModuleAPI), From(new(full.MpoolModule))),
Override(new(full.StateModuleAPI), From(new(full.StateModule))),

View File

@ -34,6 +34,7 @@ type FullNodeAPI struct {
full.MsigAPI
full.WalletAPI
full.SyncAPI
full.EthAPI
DS dtypes.MetadataDS
NetworkName dtypes.NetworkName

197
node/impl/full/eth.go Normal file
View File

@ -0,0 +1,197 @@
package full
import (
"context"
"strconv"
"go.uber.org/fx"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
)
type EthModuleAPI interface {
EthBlockNumber(ctx context.Context) (api.EthInt, error)
EthAccounts(ctx context.Context) ([]api.EthAddress, error)
EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum api.EthInt) (api.EthInt, error)
EthGetBlockTransactionCountByHash(ctx context.Context, blkHash api.EthHash) (api.EthInt, error)
EthGetBlockByHash(ctx context.Context, blkHash api.EthHash, fullTxInfo bool) (api.EthBlock, error)
EthGetBlockByNumber(ctx context.Context, blkNum api.EthInt, fullTxInfo bool) (api.EthBlock, error)
EthGetTransactionByHash(ctx context.Context, txHash api.EthHash) (api.EthTx, error)
EthGetTransactionCount(ctx context.Context, sender api.EthAddress, blkOpt string) (api.EthInt, error)
EthGetTransactionReceipt(ctx context.Context, blkHash api.EthHash) (api.EthTxReceipt, error)
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash api.EthHash, txIndex api.EthInt) (api.EthTx, error)
EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum api.EthInt, txIndex api.EthInt) (api.EthTx, error)
EthGetCode(ctx context.Context, address api.EthAddress) (string, error)
EthGetStorageAt(ctx context.Context, address api.EthAddress, position api.EthInt, blkParam string) (string, error)
EthGetBalance(ctx context.Context, address api.EthAddress, blkParam string) (api.EthBigInt, error)
EthChainId(ctx context.Context) (api.EthInt, error)
NetVersion(ctx context.Context) (string, error)
NetListening(ctx context.Context) (bool, error)
EthProtocolVersion(ctx context.Context) (api.EthInt, error)
EthMaxPriorityFeePerGas(ctx context.Context) (api.EthInt, error)
EthGasPrice(ctx context.Context) (api.EthInt, error)
// EthSendRawTransaction(ctx context.Context, tx api.EthTx) (api.EthHash, error)
}
var _ EthModuleAPI = *new(api.FullNode)
// EthModule provides a default implementation of EthModuleAPI.
// It can be swapped out with another implementation through Dependency
// Injection (for example with a thin RPC client).
type EthModule struct {
fx.In
Chain *store.ChainStore
StateAPI
}
var _ EthModuleAPI = (*EthModule)(nil)
type EthAPI struct {
fx.In
Chain *store.ChainStore
EthModuleAPI
}
func (a *EthModule) EthBlockNumber(context.Context) (api.EthInt, error) {
height := a.Chain.GetHeaviestTipSet().Height()
return api.EthInt(height), nil
}
func (a *EthModule) EthAccounts(context.Context) ([]api.EthAddress, error) {
// The lotus node is not expected to hold manage accounts, so we'll always return an empty array
return []api.EthAddress{}, nil
}
func (a *EthModule) countTipsetMsgs(ctx context.Context, ts *types.TipSet) (int, error) {
blkMsgs, err := a.Chain.BlockMsgsForTipset(ctx, ts)
if err != nil {
return 0, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err)
}
count := 0
for _, blkMsg := range blkMsgs {
// TODO: may need to run canonical ordering and deduplication here
count += len(blkMsg.BlsMessages) + len(blkMsg.SecpkMessages)
}
return count, nil
}
func (a *EthModule) EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum api.EthInt) (api.EthInt, error) {
ts, err := a.Chain.GetTipsetByHeight(ctx, abi.ChainEpoch(blkNum), nil, false)
if err != nil {
return api.EthInt(0), xerrors.Errorf("error loading tipset %s: %w", ts, err)
}
count, err := a.countTipsetMsgs(ctx, ts)
return api.EthInt(count), err
}
func (a *EthModule) EthGetBlockTransactionCountByHash(ctx context.Context, blkHash api.EthHash) (api.EthInt, error) {
ts, err := a.Chain.GetTipSetByCid(ctx, blkHash.ToCid())
if err != nil {
return api.EthInt(0), xerrors.Errorf("error loading tipset %s: %w", ts, err)
}
count, err := a.countTipsetMsgs(ctx, ts)
return api.EthInt(count), err
}
func (a *EthModule) EthGetBlockByHash(ctx context.Context, blkHash api.EthHash, fullTxInfo bool) (api.EthBlock, error) {
return api.EthBlock{}, nil
}
func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkNum api.EthInt, fullTxInfo bool) (api.EthBlock, error) {
return api.EthBlock{}, nil
}
func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash api.EthHash) (api.EthTx, error) {
return api.EthTx{}, nil
}
func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender api.EthAddress, blkParam string) (api.EthInt, error) {
return api.EthInt(0), nil
}
func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, blkHash api.EthHash) (api.EthTxReceipt, error) {
return api.EthTxReceipt{}, nil
}
func (a *EthModule) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash api.EthHash, txIndex api.EthInt) (api.EthTx, error) {
return api.EthTx{}, nil
}
func (a *EthModule) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum api.EthInt, txIndex api.EthInt) (api.EthTx, error) {
return api.EthTx{}, nil
}
// EthGetCode returns string value of the compiled bytecode
func (a *EthModule) EthGetCode(ctx context.Context, address api.EthAddress) (string, error) {
return "", nil
}
func (a *EthModule) EthGetStorageAt(ctx context.Context, address api.EthAddress, position api.EthInt, blkParam string) (string, error) {
return "", nil
}
func (a *EthModule) EthGetBalance(ctx context.Context, address api.EthAddress, blkParam string) (api.EthBigInt, error) {
filAddr, err := address.ToFilecoinAddress()
if err != nil {
return api.EthBigInt{}, err
}
actor, err := a.StateGetActor(ctx, filAddr, types.EmptyTSK)
if err != nil {
return api.EthBigInt{}, err
}
return api.EthBigInt{Int: actor.Balance.Int}, nil
}
func (a *EthModule) EthChainId(ctx context.Context) (api.EthInt, error) {
return api.EthInt(0), nil
}
func (a *EthModule) NetVersion(ctx context.Context) (string, error) {
// Note that networkId is not encoded in hex
nv, err := a.StateNetworkVersion(ctx, types.EmptyTSK)
if err != nil {
return "", err
}
return strconv.FormatUint(uint64(nv), 10), nil
}
func (a *EthModule) NetListening(ctx context.Context) (bool, error) {
return true, nil
}
func (a *EthModule) EthProtocolVersion(ctx context.Context) (api.EthInt, error) {
return api.EthInt(0), nil
}
func (a *EthModule) EthMaxPriorityFeePerGas(ctx context.Context) (api.EthInt, error) {
return api.EthInt(0), nil
}
func (a *EthModule) EthGasPrice(ctx context.Context) (api.EthInt, error) {
return api.EthInt(0), nil
}
// func (a *EthModule) EthSendRawTransaction(ctx context.Context tx api.EthTx) (api.EthHash, error) {
// return api.EthHash{}, nil
// }
// func (a *EthModule) EthEstimateGas(ctx context.Context, tx api.EthTx, blkParam string) (api.EthInt, error) {
// return api.EthInt(0), nil
// }
//
// func (a *EthModule) EthCall(ctx context.Context, tx api.EthTx, blkParam string) (string, error) {
// return "", nil
// }
//

View File

@ -73,6 +73,34 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server
rpcServer.Register("Filecoin", hnd)
rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover")
// TODO: use reflect to automatically register all the eth aliases
rpcServer.AliasMethod("eth_accounts", "Filecoin.EthAccounts")
rpcServer.AliasMethod("eth_blockNumber", "Filecoin.EthBlockNumber")
rpcServer.AliasMethod("eth_getBlockTransactionCountByNumber", "Filecoin.EthGetBlockTransactionCountByNumber")
rpcServer.AliasMethod("eth_getBlockTransactionCountByHash", "Filecoin.EthGetBlockTransactionCountByHash")
rpcServer.AliasMethod("eth_getBlockByHash", "Filecoin.EthGetBlockByHash")
rpcServer.AliasMethod("eth_getBlockByNumber", "Filecoin.EthGetBlockByNumber")
rpcServer.AliasMethod("eth_getTransactionByHash", "Filecoin.EthGetTransactionByHash")
rpcServer.AliasMethod("eth_getTransactionCount", "Filecoin.EthGetTransactionCount")
rpcServer.AliasMethod("eth_getTransactionReceipt", "Filecoin.EthGetTransactionReceipt")
rpcServer.AliasMethod("eth_getTransactionByBlockHashAndIndex", "Filecoin.EthGetTransactionByBlockHashAndIndex")
rpcServer.AliasMethod("eth_getTransactionByBlockNumberAndIndex", "Filecoin.EthGetTransactionByBlockNumberAndIndex")
rpcServer.AliasMethod("eth_getCode", "Filecoin.EthGetCode")
rpcServer.AliasMethod("eth_getStorageAt", "Filecoin.EthGetStorageAt")
rpcServer.AliasMethod("eth_getBalance", "Filecoin.EthGetBalance")
rpcServer.AliasMethod("eth_chainId", "Filecoin.EthChainId")
rpcServer.AliasMethod("eth_protocolVersion", "Filecoin.EthProtocolVersion")
rpcServer.AliasMethod("eth_maxPriorityFeePerGas", "Filecoin.EthMaxPriorityFeePerGas")
rpcServer.AliasMethod("eth_gasPrice", "Filecoin.EthGasPrice")
rpcServer.AliasMethod("eth_sendRawTransaction", "Filecoin.EthSendRawTransaction")
// rpcServer.AliasMethod("eth_estimateGas", "Filecoin.EthEstimateGas")
// rpcServer.AliasMethod("eth_call", "Filecoin.EthCall")
rpcServer.AliasMethod("net_version", "Filecoin.NetVersion")
rpcServer.AliasMethod("net_listening", "Filecoin.NetListening")
var handler http.Handler = rpcServer
if permissioned {
handler = &auth.Handler{Verify: a.AuthVerify, Next: rpcServer.ServeHTTP}