feat: ethrpc: implement EthBlock and EthTx structs (#9287)
Co-authored-by: Raúl Kripalani <raul@protocol.ai>
This commit is contained in:
committed by
vyzo
co-authored by
Raúl Kripalani
parent
4652d8559f
commit
e5bb5b7430
+3
-2
@@ -785,9 +785,10 @@ type FullNode interface {
|
||||
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
|
||||
EthMaxPriorityFeePerGas(ctx context.Context) (EthInt, error) //perm:read
|
||||
EthEstimateGas(ctx context.Context, tx EthCall, blkParam string) (EthInt, error) //perm:read
|
||||
EthCall(ctx context.Context, tx EthCall, blkParam string) (string, error) //perm:read
|
||||
|
||||
// CreateBackup creates node backup onder the specified file name. The
|
||||
// method requires that the lotus daemon is running with the
|
||||
|
||||
+86
-16
@@ -5,15 +5,18 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
mathbig "math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/multiformats/go-multihash"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
|
||||
type EthInt int64
|
||||
@@ -32,12 +35,16 @@ func (e *EthInt) UnmarshalJSON(b []byte) error {
|
||||
return err
|
||||
}
|
||||
eint := EthInt(parsedInt)
|
||||
e = &eint
|
||||
*e = eint
|
||||
return nil
|
||||
}
|
||||
|
||||
type EthBigInt big.Int
|
||||
|
||||
var (
|
||||
EthBigIntZero = EthBigInt{Int: big.Zero().Int}
|
||||
)
|
||||
|
||||
func (e EthBigInt) MarshalJSON() ([]byte, error) {
|
||||
if e.Int == nil {
|
||||
return json.Marshal("0x0")
|
||||
@@ -45,6 +52,24 @@ func (e EthBigInt) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(fmt.Sprintf("0x%x", e.Int))
|
||||
}
|
||||
|
||||
func (e *EthBigInt) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
replaced := strings.Replace(s, "0x", "", -1)
|
||||
if len(replaced)%2 == 1 {
|
||||
replaced = "0" + replaced
|
||||
}
|
||||
|
||||
i := new(mathbig.Int)
|
||||
i.SetString(replaced, 16)
|
||||
|
||||
*e = EthBigInt(big.NewFromGo(i))
|
||||
return nil
|
||||
}
|
||||
|
||||
type EthBlock struct {
|
||||
ParentHash EthHash `json:"parentHash"`
|
||||
Sha3Uncles EthHash `json:"sha3Uncles"`
|
||||
@@ -53,24 +78,49 @@ type EthBlock struct {
|
||||
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"`
|
||||
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 EthBigInt `json:"baseFeePerGas"`
|
||||
Size EthInt `json:"size"`
|
||||
// can be []EthTx or []string depending on query params
|
||||
Transactions []interface{} `json:"transactions"`
|
||||
Uncles []EthHash `json:"uncles"`
|
||||
}
|
||||
|
||||
var (
|
||||
EmptyEthHash = EthHash{}
|
||||
EmptyEthInt = EthInt(0)
|
||||
EmptyEthNonce = [8]byte{0, 0, 0, 0, 0, 0, 0, 0}
|
||||
)
|
||||
|
||||
func NewEthBlock() EthBlock {
|
||||
return EthBlock{
|
||||
Sha3Uncles: EmptyEthHash,
|
||||
StateRoot: EmptyEthHash,
|
||||
TransactionsRoot: EmptyEthHash,
|
||||
ReceiptsRoot: EmptyEthHash,
|
||||
Difficulty: EmptyEthInt,
|
||||
Extradata: []byte{},
|
||||
MixHash: EmptyEthHash,
|
||||
Nonce: EmptyEthNonce,
|
||||
GasLimit: EthInt(build.BlockGasLimit), // TODO we map Ethereum blocks to Filecoin tipsets; this is inconsistent.
|
||||
Uncles: []EthHash{},
|
||||
Transactions: []interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
type EthTx struct {
|
||||
ChainID *EthInt `json:"chainId"`
|
||||
ChainID EthInt `json:"chainId"`
|
||||
Nonce uint64 `json:"nonce"`
|
||||
Hash EthHash `json:"hash"`
|
||||
BlockHash EthHash `json:"blockHash"`
|
||||
BlockNumber EthHash `json:"blockNumber"`
|
||||
BlockNumber EthInt `json:"blockNumber"`
|
||||
TransactionIndex EthInt `json:"transacionIndex"`
|
||||
From EthAddress `json:"from"`
|
||||
To EthAddress `json:"to"`
|
||||
@@ -85,6 +135,26 @@ type EthTx struct {
|
||||
S EthBigInt `json:"s"`
|
||||
}
|
||||
|
||||
type EthCall struct {
|
||||
From EthAddress `json:"from"`
|
||||
To EthAddress `json:"to"`
|
||||
Gas EthInt `json:"gas"`
|
||||
GasPrice EthBigInt `json:"gasPrice"`
|
||||
Value EthBigInt `json:"value"`
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
|
||||
func (c *EthCall) UnmarshalJSON(b []byte) error {
|
||||
type TempEthCall EthCall
|
||||
var params TempEthCall
|
||||
|
||||
if err := json.Unmarshal(b, ¶ms); err != nil {
|
||||
return err
|
||||
}
|
||||
*c = EthCall(params)
|
||||
return nil
|
||||
}
|
||||
|
||||
type EthTxReceipt struct {
|
||||
TransactionHash EthHash `json:"transactionHash"`
|
||||
TransactionIndex EthInt `json:"transacionIndex"`
|
||||
@@ -136,7 +206,7 @@ func (a *EthAddress) UnmarshalJSON(b []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a = &addr
|
||||
copy(a[:], addr[:])
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -185,7 +255,7 @@ func (h *EthHash) UnmarshalJSON(b []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h = &hash
|
||||
copy(h[:], hash[:])
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+51
-9
@@ -30,6 +30,20 @@ func TestEthIntMarshalJSON(t *testing.T) {
|
||||
require.Equal(t, j, tc.Output)
|
||||
}
|
||||
}
|
||||
func TestEthIntUnmarshalJSON(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
{[]byte("\"0x0\""), EthInt(0)},
|
||||
{[]byte("\"0x41\""), EthInt(65)},
|
||||
{[]byte("\"0x400\""), EthInt(1024)},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
var i EthInt
|
||||
err := i.UnmarshalJSON(tc.Input.([]byte))
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, i, tc.Output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthBigIntMarshalJSON(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
@@ -45,16 +59,34 @@ func TestEthBigIntMarshalJSON(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthBigIntUnmarshalJSON(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
{[]byte("\"0x0\""), EthBigInt(big.MustFromString("0"))},
|
||||
{[]byte("\"0x41\""), EthBigInt(big.MustFromString("65"))},
|
||||
{[]byte("\"0x400\""), EthBigInt(big.MustFromString("1024"))},
|
||||
{[]byte("\"0xff1000000000000000000000000\""), EthBigInt(big.MustFromString("323330131220712761719252861321216"))},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
var i EthBigInt
|
||||
err := i.UnmarshalJSON(tc.Input.([]byte))
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, i, tc.Output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthHash(t *testing.T) {
|
||||
testcases := []string{
|
||||
"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184",
|
||||
"0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738",
|
||||
`"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"`,
|
||||
`"0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"`,
|
||||
}
|
||||
|
||||
for _, hash := range testcases {
|
||||
h, err := EthHashFromHex(hash)
|
||||
var h EthHash
|
||||
err := h.UnmarshalJSON([]byte(hash))
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, h.String(), hash)
|
||||
require.Equal(t, h.String(), strings.Replace(hash, `"`, "", -1))
|
||||
|
||||
c := h.ToCid()
|
||||
h1, err := EthHashFromCid(c)
|
||||
@@ -65,15 +97,17 @@ func TestEthHash(t *testing.T) {
|
||||
|
||||
func TestEthAddr(t *testing.T) {
|
||||
testcases := []string{
|
||||
strings.ToLower("0xd4c5fb16488Aa48081296299d54b0c648C9333dA"),
|
||||
strings.ToLower("0x2C2EC67e3e1FeA8e4A39601cB3A3Cd44f5fa830d"),
|
||||
strings.ToLower("0x01184F793982104363F9a8a5845743f452dE0586"),
|
||||
strings.ToLower(`"0xd4c5fb16488Aa48081296299d54b0c648C9333dA"`),
|
||||
strings.ToLower(`"0x2C2EC67e3e1FeA8e4A39601cB3A3Cd44f5fa830d"`),
|
||||
strings.ToLower(`"0x01184F793982104363F9a8a5845743f452dE0586"`),
|
||||
}
|
||||
|
||||
for _, addr := range testcases {
|
||||
a, err := EthAddressFromHex(addr)
|
||||
var a EthAddress
|
||||
err := a.UnmarshalJSON([]byte(addr))
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, a.String(), addr)
|
||||
require.Equal(t, a.String(), strings.Replace(addr, `"`, "", -1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,3 +128,11 @@ func TestParseEthAddr(t *testing.T) {
|
||||
require.Equal(t, addr, faddr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalEthCall(t *testing.T) {
|
||||
data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","data":""}`
|
||||
|
||||
var c EthCall
|
||||
err := c.UnmarshalJSON([]byte(data))
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
@@ -951,6 +951,21 @@ func (mr *MockFullNodeMockRecorder) EthBlockNumber(arg0 interface{}) *gomock.Cal
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthBlockNumber", reflect.TypeOf((*MockFullNode)(nil).EthBlockNumber), arg0)
|
||||
}
|
||||
|
||||
// EthCall mocks base method.
|
||||
func (m *MockFullNode) EthCall(arg0 context.Context, arg1 api.EthCall, arg2 string) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthCall", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthCall indicates an expected call of EthCall.
|
||||
func (mr *MockFullNodeMockRecorder) EthCall(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthCall", reflect.TypeOf((*MockFullNode)(nil).EthCall), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthChainId mocks base method.
|
||||
func (m *MockFullNode) EthChainId(arg0 context.Context) (api.EthInt, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -966,6 +981,21 @@ func (mr *MockFullNodeMockRecorder) EthChainId(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthChainId", reflect.TypeOf((*MockFullNode)(nil).EthChainId), arg0)
|
||||
}
|
||||
|
||||
// EthEstimateGas mocks base method.
|
||||
func (m *MockFullNode) EthEstimateGas(arg0 context.Context, arg1 api.EthCall, arg2 string) (api.EthInt, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthEstimateGas", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(api.EthInt)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthEstimateGas indicates an expected call of EthEstimateGas.
|
||||
func (mr *MockFullNodeMockRecorder) EthEstimateGas(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthEstimateGas", reflect.TypeOf((*MockFullNode)(nil).EthEstimateGas), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthGasPrice mocks base method.
|
||||
func (m *MockFullNode) EthGasPrice(arg0 context.Context) (api.EthInt, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
+27
-1
@@ -222,9 +222,13 @@ type FullNodeStruct struct {
|
||||
|
||||
EthBlockNumber func(p0 context.Context) (EthInt, error) `perm:"read"`
|
||||
|
||||
EthCall func(p0 context.Context, p1 EthCall, p2 string) (string, error) `perm:"read"`
|
||||
|
||||
EthChainId func(p0 context.Context) (EthInt, error) `perm:"read"`
|
||||
|
||||
EthGasPrice func(p0 context.Context) (EthInt, error) ``
|
||||
EthEstimateGas func(p0 context.Context, p1 EthCall, p2 string) (EthInt, error) `perm:"read"`
|
||||
|
||||
EthGasPrice func(p0 context.Context) (EthInt, error) `perm:"read"`
|
||||
|
||||
EthGetBalance func(p0 context.Context, p1 EthAddress, p2 string) (EthBigInt, error) `perm:"read"`
|
||||
|
||||
@@ -1853,6 +1857,17 @@ func (s *FullNodeStub) EthBlockNumber(p0 context.Context) (EthInt, error) {
|
||||
return *new(EthInt), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthCall(p0 context.Context, p1 EthCall, p2 string) (string, error) {
|
||||
if s.Internal.EthCall == nil {
|
||||
return "", ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthCall(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthCall(p0 context.Context, p1 EthCall, p2 string) (string, error) {
|
||||
return "", ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthChainId(p0 context.Context) (EthInt, error) {
|
||||
if s.Internal.EthChainId == nil {
|
||||
return *new(EthInt), ErrNotSupported
|
||||
@@ -1864,6 +1879,17 @@ func (s *FullNodeStub) EthChainId(p0 context.Context) (EthInt, error) {
|
||||
return *new(EthInt), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthEstimateGas(p0 context.Context, p1 EthCall, p2 string) (EthInt, error) {
|
||||
if s.Internal.EthEstimateGas == nil {
|
||||
return *new(EthInt), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthEstimateGas(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthEstimateGas(p0 context.Context, p1 EthCall, p2 string) (EthInt, error) {
|
||||
return *new(EthInt), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGasPrice(p0 context.Context) (EthInt, error) {
|
||||
if s.Internal.EthGasPrice == nil {
|
||||
return *new(EthInt), ErrNotSupported
|
||||
|
||||
Reference in New Issue
Block a user