feat: ethrpc: implement EthBlock and EthTx structs (#9287)
Co-authored-by: Raúl Kripalani <raul@protocol.ai>
This commit is contained in:
parent
4652d8559f
commit
e5bb5b7430
@ -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
|
||||
|
@ -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"`
|
||||
@ -61,16 +86,41 @@ type EthBlock struct {
|
||||
Extradata []byte `json:"extraData"`
|
||||
MixHash EthHash `json:"mixHash"`
|
||||
Nonce EthNonce `json:"nonce"`
|
||||
BaseFeePerGas EthInt `json:"baseFeePerGas"`
|
||||
Transactions EthTx `json:"transactions"`
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -131,4 +131,8 @@ const InteractivePoRepConfidence = 6
|
||||
|
||||
const BootstrapPeerThreshold = 1
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 31415926
|
||||
|
||||
var WhitelistedBlock = cid.Undef
|
||||
|
@ -81,4 +81,8 @@ const PropagationDelaySecs = uint64(6)
|
||||
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
|
||||
const BootstrapPeerThreshold = 2
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 3141592
|
||||
|
||||
var WhitelistedBlock = cid.Undef
|
||||
|
@ -114,4 +114,8 @@ var PropagationDelaySecs = uint64(10)
|
||||
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
|
||||
const BootstrapPeerThreshold = 4
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 314159
|
||||
|
||||
var WhitelistedBlock = cid.Undef
|
||||
|
@ -119,4 +119,9 @@ const PropagationDelaySecs = uint64(6)
|
||||
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
|
||||
const BootstrapPeerThreshold = 2
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
// TODO same as butterfly for now, as we didn't submit an assignment for interopnet.
|
||||
const Eip155ChainId = 3141592
|
||||
|
||||
var WhitelistedBlock = cid.Undef
|
||||
|
@ -127,5 +127,9 @@ const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
|
||||
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
|
||||
const BootstrapPeerThreshold = 4
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 314
|
||||
|
||||
// we skip checks on message validity in this block to sidestep the zero-bls signature
|
||||
var WhitelistedBlock = MustParseCid("bafy2bzaceapyg2uyzk7vueh3xccxkuwbz3nxewjyguoxvhx77malc2lzn2ybi")
|
||||
|
@ -130,3 +130,7 @@ var (
|
||||
)
|
||||
|
||||
const BootstrapPeerThreshold = 1
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 31415926
|
||||
|
@ -85,4 +85,8 @@ const PropagationDelaySecs = uint64(6)
|
||||
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
|
||||
const BootstrapPeerThreshold = 2
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 31415
|
||||
|
||||
var WhitelistedBlock = cid.Undef
|
||||
|
@ -99,6 +99,14 @@ func (k *TipSetKey) UnmarshalJSON(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k TipSetKey) Cid() (cid.Cid, error) {
|
||||
blk, err := k.ToStorageBlock()
|
||||
if err != nil {
|
||||
return cid.Cid{}, err
|
||||
}
|
||||
return blk.Cid(), nil
|
||||
}
|
||||
|
||||
func (k TipSetKey) ToStorageBlock() (block.Block, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
if err := k.MarshalCBOR(buf); err != nil {
|
||||
|
@ -68,7 +68,9 @@
|
||||
* [Eth](#Eth)
|
||||
* [EthAccounts](#EthAccounts)
|
||||
* [EthBlockNumber](#EthBlockNumber)
|
||||
* [EthCall](#EthCall)
|
||||
* [EthChainId](#EthChainId)
|
||||
* [EthEstimateGas](#EthEstimateGas)
|
||||
* [EthGasPrice](#EthGasPrice)
|
||||
* [EthGetBalance](#EthGetBalance)
|
||||
* [EthGetBlockByHash](#EthGetBlockByHash)
|
||||
@ -2173,6 +2175,28 @@ Inputs: `null`
|
||||
|
||||
Response: `"0x5"`
|
||||
|
||||
### EthCall
|
||||
|
||||
|
||||
Perms: read
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"from": "0x0707070707070707070707070707070707070707",
|
||||
"to": "0x0707070707070707070707070707070707070707",
|
||||
"gas": "0x5",
|
||||
"gasPrice": "0x0",
|
||||
"value": "0x0",
|
||||
"data": "Ynl0ZSBhcnJheQ=="
|
||||
},
|
||||
"string value"
|
||||
]
|
||||
```
|
||||
|
||||
Response: `"string value"`
|
||||
|
||||
### EthChainId
|
||||
|
||||
|
||||
@ -2182,10 +2206,32 @@ Inputs: `null`
|
||||
|
||||
Response: `"0x5"`
|
||||
|
||||
### EthEstimateGas
|
||||
|
||||
|
||||
Perms: read
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"from": "0x0707070707070707070707070707070707070707",
|
||||
"to": "0x0707070707070707070707070707070707070707",
|
||||
"gas": "0x5",
|
||||
"gasPrice": "0x0",
|
||||
"value": "0x0",
|
||||
"data": "Ynl0ZSBhcnJheQ=="
|
||||
},
|
||||
"string value"
|
||||
]
|
||||
```
|
||||
|
||||
Response: `"0x5"`
|
||||
|
||||
### EthGasPrice
|
||||
|
||||
|
||||
Perms:
|
||||
Perms: read
|
||||
|
||||
Inputs: `null`
|
||||
|
||||
@ -2236,26 +2282,14 @@ Response:
|
||||
"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"
|
||||
}
|
||||
"baseFeePerGas": "0x0",
|
||||
"size": "0x5",
|
||||
"transactions": [
|
||||
{}
|
||||
],
|
||||
"uncles": [
|
||||
"0x0707070707070707070707070707070707070707070707070707070707070707"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@ -2289,26 +2323,14 @@ Response:
|
||||
"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"
|
||||
}
|
||||
"baseFeePerGas": "0x0",
|
||||
"size": "0x5",
|
||||
"transactions": [
|
||||
{}
|
||||
],
|
||||
"uncles": [
|
||||
"0x0707070707070707070707070707070707070707070707070707070707070707"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@ -2392,7 +2414,7 @@ Response:
|
||||
"nonce": 42,
|
||||
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockNumber": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockNumber": "0x5",
|
||||
"transacionIndex": "0x5",
|
||||
"from": "0x0707070707070707070707070707070707070707",
|
||||
"to": "0x0707070707070707070707070707070707070707",
|
||||
@ -2428,7 +2450,7 @@ Response:
|
||||
"nonce": 42,
|
||||
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockNumber": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockNumber": "0x5",
|
||||
"transacionIndex": "0x5",
|
||||
"from": "0x0707070707070707070707070707070707070707",
|
||||
"to": "0x0707070707070707070707070707070707070707",
|
||||
@ -2463,7 +2485,7 @@ Response:
|
||||
"nonce": 42,
|
||||
"hash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockHash": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockNumber": "0x0707070707070707070707070707070707070707070707070707070707070707",
|
||||
"blockNumber": "0x5",
|
||||
"transacionIndex": "0x5",
|
||||
"from": "0x0707070707070707070707070707070707070707",
|
||||
"to": "0x0707070707070707070707070707070707070707",
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
@ -33,8 +34,10 @@ type EthModuleAPI interface {
|
||||
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)
|
||||
EthEstimateGas(ctx context.Context, tx api.EthCall, blkParam string) (api.EthInt, error)
|
||||
EthCall(ctx context.Context, tx api.EthCall, blkParam string) (string, error)
|
||||
EthMaxPriorityFeePerGas(ctx context.Context) (api.EthInt, error)
|
||||
// EthSendRawTransaction(ctx context.Context, tx api.EthTx) (api.EthHash, error)
|
||||
}
|
||||
|
||||
@ -47,6 +50,8 @@ type EthModule struct {
|
||||
fx.In
|
||||
|
||||
Chain *store.ChainStore
|
||||
|
||||
ChainAPI
|
||||
StateAPI
|
||||
}
|
||||
|
||||
@ -104,17 +109,36 @@ func (a *EthModule) EthGetBlockTransactionCountByHash(ctx context.Context, blkHa
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetBlockByHash(ctx context.Context, blkHash api.EthHash, fullTxInfo bool) (api.EthBlock, error) {
|
||||
return api.EthBlock{}, nil
|
||||
ts, err := a.Chain.GetTipSetByCid(ctx, blkHash.ToCid())
|
||||
if err != nil {
|
||||
return api.EthBlock{}, xerrors.Errorf("error loading tipset %s: %w", ts, err)
|
||||
}
|
||||
return a.ethBlockFromFilecoinTipSet(ctx, ts, fullTxInfo)
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkNum api.EthInt, fullTxInfo bool) (api.EthBlock, error) {
|
||||
return api.EthBlock{}, nil
|
||||
ts, err := a.Chain.GetTipsetByHeight(ctx, abi.ChainEpoch(blkNum), nil, false)
|
||||
if err != nil {
|
||||
return api.EthBlock{}, xerrors.Errorf("error loading tipset %s: %w", ts, err)
|
||||
}
|
||||
return a.ethBlockFromFilecoinTipSet(ctx, ts, fullTxInfo)
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash api.EthHash) (api.EthTx, error) {
|
||||
cid := txHash.ToCid()
|
||||
|
||||
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, cid, api.LookbackNoLimit, true)
|
||||
if err != nil {
|
||||
return api.EthTx{}, nil
|
||||
}
|
||||
|
||||
tx, err := a.ethTxFromFilecoinMessageLookup(ctx, msgLookup)
|
||||
if err != nil {
|
||||
return api.EthTx{}, err
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender api.EthAddress, blkParam string) (api.EthInt, error) {
|
||||
return api.EthInt(0), nil
|
||||
}
|
||||
@ -155,7 +179,7 @@ func (a *EthModule) EthGetBalance(ctx context.Context, address api.EthAddress, b
|
||||
}
|
||||
|
||||
func (a *EthModule) EthChainId(ctx context.Context) (api.EthInt, error) {
|
||||
return api.EthInt(0), nil
|
||||
return api.EthInt(build.Eip155ChainId), nil
|
||||
}
|
||||
|
||||
func (a *EthModule) NetVersion(ctx context.Context) (string, error) {
|
||||
@ -187,11 +211,127 @@ func (a *EthModule) EthGasPrice(ctx context.Context) (api.EthInt, 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
|
||||
// }
|
||||
//
|
||||
func (a *EthModule) EthEstimateGas(ctx context.Context, tx api.EthCall, blkParam string) (api.EthInt, error) {
|
||||
return api.EthInt(0), nil
|
||||
}
|
||||
|
||||
func (a *EthModule) EthCall(ctx context.Context, tx api.EthCall, blkParam string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (a *EthModule) ethBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTxInfo bool) (api.EthBlock, error) {
|
||||
parent, err := a.Chain.LoadTipSet(ctx, ts.Parents())
|
||||
if err != nil {
|
||||
return api.EthBlock{}, err
|
||||
}
|
||||
parentKeyCid, err := parent.Key().Cid()
|
||||
if err != nil {
|
||||
return api.EthBlock{}, err
|
||||
}
|
||||
parentBlkHash, err := api.EthHashFromCid(parentKeyCid)
|
||||
if err != nil {
|
||||
return api.EthBlock{}, err
|
||||
}
|
||||
|
||||
blkMsgs, err := a.Chain.BlockMsgsForTipset(ctx, ts)
|
||||
if err != nil {
|
||||
return api.EthBlock{}, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err)
|
||||
}
|
||||
|
||||
block := api.NewEthBlock()
|
||||
|
||||
// this seems to be a very expensive way to get gasUsed of the block. may need to find an efficient way to do it
|
||||
gasUsed := int64(0)
|
||||
for _, blkMsg := range blkMsgs {
|
||||
for _, msg := range append(blkMsg.BlsMessages, blkMsg.SecpkMessages...) {
|
||||
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, msg.Cid(), api.LookbackNoLimit, true)
|
||||
if err != nil {
|
||||
return api.EthBlock{}, nil
|
||||
}
|
||||
gasUsed += msgLookup.Receipt.GasUsed
|
||||
|
||||
if fullTxInfo {
|
||||
tx, err := a.ethTxFromFilecoinMessageLookup(ctx, msgLookup)
|
||||
if err != nil {
|
||||
return api.EthBlock{}, nil
|
||||
}
|
||||
block.Transactions = append(block.Transactions, tx)
|
||||
} else {
|
||||
hash, err := api.EthHashFromCid(msg.Cid())
|
||||
if err != nil {
|
||||
return api.EthBlock{}, err
|
||||
}
|
||||
block.Transactions = append(block.Transactions, hash.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
block.Number = api.EthInt(ts.Height())
|
||||
block.ParentHash = parentBlkHash
|
||||
block.Timestamp = api.EthInt(ts.Blocks()[0].Timestamp)
|
||||
block.BaseFeePerGas = api.EthBigInt{Int: ts.Blocks()[0].ParentBaseFee.Int}
|
||||
block.GasUsed = api.EthInt(gasUsed)
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLookup) (api.EthTx, error) {
|
||||
cid := msgLookup.Message
|
||||
txHash, err := api.EthHashFromCid(cid)
|
||||
if err != nil {
|
||||
return api.EthTx{}, err
|
||||
}
|
||||
|
||||
tsCid, err := msgLookup.TipSet.Cid()
|
||||
if err != nil {
|
||||
return api.EthTx{}, err
|
||||
}
|
||||
|
||||
blkHash, err := api.EthHashFromCid(tsCid)
|
||||
if err != nil {
|
||||
return api.EthTx{}, err
|
||||
}
|
||||
|
||||
msg, err := a.ChainAPI.ChainGetMessage(ctx, msgLookup.Message)
|
||||
if err != nil {
|
||||
return api.EthTx{}, err
|
||||
}
|
||||
|
||||
fromFilIdAddr, err := a.StateAPI.StateLookupID(ctx, msg.From, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return api.EthTx{}, err
|
||||
}
|
||||
|
||||
fromEthAddr, err := api.EthAddressFromFilecoinIDAddress(fromFilIdAddr)
|
||||
if err != nil {
|
||||
return api.EthTx{}, err
|
||||
}
|
||||
|
||||
toFilAddr, err := a.StateAPI.StateLookupID(ctx, msg.From, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return api.EthTx{}, err
|
||||
}
|
||||
|
||||
toEthAddr, err := api.EthAddressFromFilecoinIDAddress(toFilAddr)
|
||||
if err != nil {
|
||||
return api.EthTx{}, err
|
||||
}
|
||||
|
||||
tx := api.EthTx{
|
||||
ChainID: api.EthInt(build.Eip155ChainId),
|
||||
Hash: txHash,
|
||||
BlockHash: blkHash,
|
||||
BlockNumber: api.EthInt(msgLookup.Height),
|
||||
From: fromEthAddr,
|
||||
To: toEthAddr,
|
||||
Value: api.EthBigInt(msg.Value),
|
||||
Type: api.EthInt(2),
|
||||
Gas: api.EthInt(msg.GasLimit),
|
||||
MaxFeePerGas: api.EthBigInt(msg.GasFeeCap),
|
||||
MaxPriorityFeePerGas: api.EthBigInt(msg.GasPremium),
|
||||
V: api.EthBigIntZero,
|
||||
R: api.EthBigIntZero,
|
||||
S: api.EthBigIntZero,
|
||||
// TODO: Input:
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
|
@ -95,8 +95,8 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server
|
||||
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("eth_estimateGas", "Filecoin.EthEstimateGas")
|
||||
rpcServer.AliasMethod("eth_call", "Filecoin.EthCall")
|
||||
|
||||
rpcServer.AliasMethod("net_version", "Filecoin.NetVersion")
|
||||
rpcServer.AliasMethod("net_listening", "Filecoin.NetListening")
|
||||
|
Loading…
Reference in New Issue
Block a user