diff --git a/api/api_gateway.go b/api/api_gateway.go index b95299493..c78710026 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -13,6 +13,7 @@ import ( apitypes "github.com/filecoin-project/lotus/api/types" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" ) // MODIFYING THE API INTERFACE @@ -69,4 +70,38 @@ type Gateway interface { WalletBalance(context.Context, address.Address) (types.BigInt, error) Version(context.Context) (APIVersion, error) Discover(context.Context) (apitypes.OpenRPCDocument, error) + + EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) + EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) + EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) + EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) + EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) + EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) + EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) + EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) + EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) + EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) + EthChainId(ctx context.Context) (ethtypes.EthUint64, error) + NetVersion(ctx context.Context) (string, error) + NetListening(ctx context.Context) (bool, error) + EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) + EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) + EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) + EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) + EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) + EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) + EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) + EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) + EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) + EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) + EthNewFilter(ctx context.Context, filter *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) + EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) + EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) + EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) + EthSubscribe(ctx context.Context, eventType string, params *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) + EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) } diff --git a/api/eth_aliases.go b/api/eth_aliases.go new file mode 100644 index 000000000..cf69bfff7 --- /dev/null +++ b/api/eth_aliases.go @@ -0,0 +1,44 @@ +package api + +import apitypes "github.com/filecoin-project/lotus/api/types" + +func CreateEthRPCAliases(as apitypes.Aliaser) { + // TODO: maybe use reflect to automatically register all the eth aliases + as.AliasMethod("eth_accounts", "Filecoin.EthAccounts") + as.AliasMethod("eth_blockNumber", "Filecoin.EthBlockNumber") + as.AliasMethod("eth_getBlockTransactionCountByNumber", "Filecoin.EthGetBlockTransactionCountByNumber") + as.AliasMethod("eth_getBlockTransactionCountByHash", "Filecoin.EthGetBlockTransactionCountByHash") + + as.AliasMethod("eth_getBlockByHash", "Filecoin.EthGetBlockByHash") + as.AliasMethod("eth_getBlockByNumber", "Filecoin.EthGetBlockByNumber") + as.AliasMethod("eth_getTransactionByHash", "Filecoin.EthGetTransactionByHash") + as.AliasMethod("eth_getTransactionCount", "Filecoin.EthGetTransactionCount") + as.AliasMethod("eth_getTransactionReceipt", "Filecoin.EthGetTransactionReceipt") + as.AliasMethod("eth_getTransactionByBlockHashAndIndex", "Filecoin.EthGetTransactionByBlockHashAndIndex") + as.AliasMethod("eth_getTransactionByBlockNumberAndIndex", "Filecoin.EthGetTransactionByBlockNumberAndIndex") + + as.AliasMethod("eth_getCode", "Filecoin.EthGetCode") + as.AliasMethod("eth_getStorageAt", "Filecoin.EthGetStorageAt") + as.AliasMethod("eth_getBalance", "Filecoin.EthGetBalance") + as.AliasMethod("eth_chainId", "Filecoin.EthChainId") + as.AliasMethod("eth_feeHistory", "Filecoin.EthFeeHistory") + as.AliasMethod("eth_protocolVersion", "Filecoin.EthProtocolVersion") + as.AliasMethod("eth_maxPriorityFeePerGas", "Filecoin.EthMaxPriorityFeePerGas") + as.AliasMethod("eth_gasPrice", "Filecoin.EthGasPrice") + as.AliasMethod("eth_sendRawTransaction", "Filecoin.EthSendRawTransaction") + as.AliasMethod("eth_estimateGas", "Filecoin.EthEstimateGas") + as.AliasMethod("eth_call", "Filecoin.EthCall") + + as.AliasMethod("eth_getLogs", "Filecoin.EthGetLogs") + as.AliasMethod("eth_getFilterChanges", "Filecoin.EthGetFilterChanges") + as.AliasMethod("eth_getFilterLogs", "Filecoin.EthGetFilterLogs") + as.AliasMethod("eth_newFilter", "Filecoin.EthNewFilter") + as.AliasMethod("eth_newBlockFilter", "Filecoin.EthNewBlockFilter") + as.AliasMethod("eth_newPendingTransactionFilter", "Filecoin.EthNewPendingTransactionFilter") + as.AliasMethod("eth_uninstallFilter", "Filecoin.EthUninstallFilter") + as.AliasMethod("eth_subscribe", "Filecoin.EthSubscribe") + as.AliasMethod("eth_unsubscribe", "Filecoin.EthUnsubscribe") + + as.AliasMethod("net_version", "Filecoin.NetVersion") + as.AliasMethod("net_listening", "Filecoin.NetListening") +} diff --git a/api/proxy_gen.go b/api/proxy_gen.go index d308533e9..67249bb5f 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -619,6 +619,68 @@ type GatewayStruct struct { Discover func(p0 context.Context) (apitypes.OpenRPCDocument, error) `` + EthAccounts func(p0 context.Context) ([]ethtypes.EthAddress, error) `` + + EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `` + + EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) `` + + EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `` + + EthEstimateGas func(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) `` + + EthFeeHistory func(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) `` + + EthGasPrice func(p0 context.Context) (ethtypes.EthBigInt, error) `` + + EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) `` + + EthGetBlockByHash func(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) `` + + EthGetBlockByNumber func(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) `` + + EthGetBlockTransactionCountByHash func(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) `` + + EthGetBlockTransactionCountByNumber func(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) `` + + EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) `` + + EthGetFilterChanges func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `` + + EthGetFilterLogs func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `` + + EthGetLogs func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) `` + + EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `` + + EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `` + + EthGetTransactionByBlockNumberAndIndex func(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `` + + EthGetTransactionByHash func(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) `` + + EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `` + + EthGetTransactionReceipt func(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) `` + + EthMaxPriorityFeePerGas func(p0 context.Context) (ethtypes.EthBigInt, error) `` + + EthNewBlockFilter func(p0 context.Context) (ethtypes.EthFilterID, error) `` + + EthNewFilter func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) `` + + EthNewPendingTransactionFilter func(p0 context.Context) (ethtypes.EthFilterID, error) `` + + EthProtocolVersion func(p0 context.Context) (ethtypes.EthUint64, error) `` + + EthSendRawTransaction func(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) `` + + EthSubscribe func(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) `` + + EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) `` + + EthUnsubscribe func(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) `` + GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `` MpoolPush func(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) `` @@ -631,6 +693,10 @@ type GatewayStruct struct { MsigGetVestingSchedule func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MsigVesting, error) `` + NetListening func(p0 context.Context) (bool, error) `` + + NetVersion func(p0 context.Context) (string, error) `` + StateAccountKey func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `` StateDealProviderCollateralBounds func(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (DealCollateralBounds, error) `` @@ -4009,6 +4075,347 @@ func (s *GatewayStub) Discover(p0 context.Context) (apitypes.OpenRPCDocument, er return *new(apitypes.OpenRPCDocument), ErrNotSupported } +func (s *GatewayStruct) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, error) { + if s.Internal.EthAccounts == nil { + return *new([]ethtypes.EthAddress), ErrNotSupported + } + return s.Internal.EthAccounts(p0) +} + +func (s *GatewayStub) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, error) { + return *new([]ethtypes.EthAddress), ErrNotSupported +} + +func (s *GatewayStruct) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) { + if s.Internal.EthBlockNumber == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthBlockNumber(p0) +} + +func (s *GatewayStub) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) { + if s.Internal.EthCall == nil { + return *new(ethtypes.EthBytes), ErrNotSupported + } + return s.Internal.EthCall(p0, p1, p2) +} + +func (s *GatewayStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) { + return *new(ethtypes.EthBytes), ErrNotSupported +} + +func (s *GatewayStruct) EthChainId(p0 context.Context) (ethtypes.EthUint64, error) { + if s.Internal.EthChainId == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthChainId(p0) +} + +func (s *GatewayStub) EthChainId(p0 context.Context) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) { + if s.Internal.EthEstimateGas == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthEstimateGas(p0, p1) +} + +func (s *GatewayStub) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthFeeHistory(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) { + if s.Internal.EthFeeHistory == nil { + return *new(ethtypes.EthFeeHistory), ErrNotSupported + } + return s.Internal.EthFeeHistory(p0, p1, p2, p3) +} + +func (s *GatewayStub) EthFeeHistory(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) { + return *new(ethtypes.EthFeeHistory), ErrNotSupported +} + +func (s *GatewayStruct) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error) { + if s.Internal.EthGasPrice == nil { + return *new(ethtypes.EthBigInt), ErrNotSupported + } + return s.Internal.EthGasPrice(p0) +} + +func (s *GatewayStub) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error) { + return *new(ethtypes.EthBigInt), ErrNotSupported +} + +func (s *GatewayStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) { + if s.Internal.EthGetBalance == nil { + return *new(ethtypes.EthBigInt), ErrNotSupported + } + return s.Internal.EthGetBalance(p0, p1, p2) +} + +func (s *GatewayStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) { + return *new(ethtypes.EthBigInt), ErrNotSupported +} + +func (s *GatewayStruct) EthGetBlockByHash(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) { + if s.Internal.EthGetBlockByHash == nil { + return *new(ethtypes.EthBlock), ErrNotSupported + } + return s.Internal.EthGetBlockByHash(p0, p1, p2) +} + +func (s *GatewayStub) EthGetBlockByHash(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) { + return *new(ethtypes.EthBlock), ErrNotSupported +} + +func (s *GatewayStruct) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) { + if s.Internal.EthGetBlockByNumber == nil { + return *new(ethtypes.EthBlock), ErrNotSupported + } + return s.Internal.EthGetBlockByNumber(p0, p1, p2) +} + +func (s *GatewayStub) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) { + return *new(ethtypes.EthBlock), ErrNotSupported +} + +func (s *GatewayStruct) EthGetBlockTransactionCountByHash(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) { + if s.Internal.EthGetBlockTransactionCountByHash == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthGetBlockTransactionCountByHash(p0, p1) +} + +func (s *GatewayStub) EthGetBlockTransactionCountByHash(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) { + if s.Internal.EthGetBlockTransactionCountByNumber == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthGetBlockTransactionCountByNumber(p0, p1) +} + +func (s *GatewayStub) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) { + if s.Internal.EthGetCode == nil { + return *new(ethtypes.EthBytes), ErrNotSupported + } + return s.Internal.EthGetCode(p0, p1, p2) +} + +func (s *GatewayStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) { + return *new(ethtypes.EthBytes), ErrNotSupported +} + +func (s *GatewayStruct) EthGetFilterChanges(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if s.Internal.EthGetFilterChanges == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetFilterChanges(p0, p1) +} + +func (s *GatewayStub) EthGetFilterChanges(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthGetFilterLogs(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if s.Internal.EthGetFilterLogs == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetFilterLogs(p0, p1) +} + +func (s *GatewayStub) EthGetFilterLogs(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) { + if s.Internal.EthGetLogs == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetLogs(p0, p1) +} + +func (s *GatewayStub) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) { + if s.Internal.EthGetStorageAt == nil { + return *new(ethtypes.EthBytes), ErrNotSupported + } + return s.Internal.EthGetStorageAt(p0, p1, p2, p3) +} + +func (s *GatewayStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) { + return *new(ethtypes.EthBytes), ErrNotSupported +} + +func (s *GatewayStruct) EthGetTransactionByBlockHashAndIndex(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + if s.Internal.EthGetTransactionByBlockHashAndIndex == nil { + return *new(ethtypes.EthTx), ErrNotSupported + } + return s.Internal.EthGetTransactionByBlockHashAndIndex(p0, p1, p2) +} + +func (s *GatewayStub) EthGetTransactionByBlockHashAndIndex(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + return *new(ethtypes.EthTx), ErrNotSupported +} + +func (s *GatewayStruct) EthGetTransactionByBlockNumberAndIndex(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + if s.Internal.EthGetTransactionByBlockNumberAndIndex == nil { + return *new(ethtypes.EthTx), ErrNotSupported + } + return s.Internal.EthGetTransactionByBlockNumberAndIndex(p0, p1, p2) +} + +func (s *GatewayStub) EthGetTransactionByBlockNumberAndIndex(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) { + return *new(ethtypes.EthTx), ErrNotSupported +} + +func (s *GatewayStruct) EthGetTransactionByHash(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) { + if s.Internal.EthGetTransactionByHash == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetTransactionByHash(p0, p1) +} + +func (s *GatewayStub) EthGetTransactionByHash(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) { + if s.Internal.EthGetTransactionCount == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthGetTransactionCount(p0, p1, p2) +} + +func (s *GatewayStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) { + if s.Internal.EthGetTransactionReceipt == nil { + return nil, ErrNotSupported + } + return s.Internal.EthGetTransactionReceipt(p0, p1) +} + +func (s *GatewayStub) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthMaxPriorityFeePerGas(p0 context.Context) (ethtypes.EthBigInt, error) { + if s.Internal.EthMaxPriorityFeePerGas == nil { + return *new(ethtypes.EthBigInt), ErrNotSupported + } + return s.Internal.EthMaxPriorityFeePerGas(p0) +} + +func (s *GatewayStub) EthMaxPriorityFeePerGas(p0 context.Context) (ethtypes.EthBigInt, error) { + return *new(ethtypes.EthBigInt), ErrNotSupported +} + +func (s *GatewayStruct) EthNewBlockFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + if s.Internal.EthNewBlockFilter == nil { + return *new(ethtypes.EthFilterID), ErrNotSupported + } + return s.Internal.EthNewBlockFilter(p0) +} + +func (s *GatewayStub) EthNewBlockFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + return *new(ethtypes.EthFilterID), ErrNotSupported +} + +func (s *GatewayStruct) EthNewFilter(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) { + if s.Internal.EthNewFilter == nil { + return *new(ethtypes.EthFilterID), ErrNotSupported + } + return s.Internal.EthNewFilter(p0, p1) +} + +func (s *GatewayStub) EthNewFilter(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) { + return *new(ethtypes.EthFilterID), ErrNotSupported +} + +func (s *GatewayStruct) EthNewPendingTransactionFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + if s.Internal.EthNewPendingTransactionFilter == nil { + return *new(ethtypes.EthFilterID), ErrNotSupported + } + return s.Internal.EthNewPendingTransactionFilter(p0) +} + +func (s *GatewayStub) EthNewPendingTransactionFilter(p0 context.Context) (ethtypes.EthFilterID, error) { + return *new(ethtypes.EthFilterID), ErrNotSupported +} + +func (s *GatewayStruct) EthProtocolVersion(p0 context.Context) (ethtypes.EthUint64, error) { + if s.Internal.EthProtocolVersion == nil { + return *new(ethtypes.EthUint64), ErrNotSupported + } + return s.Internal.EthProtocolVersion(p0) +} + +func (s *GatewayStub) EthProtocolVersion(p0 context.Context) (ethtypes.EthUint64, error) { + return *new(ethtypes.EthUint64), ErrNotSupported +} + +func (s *GatewayStruct) EthSendRawTransaction(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) { + if s.Internal.EthSendRawTransaction == nil { + return *new(ethtypes.EthHash), ErrNotSupported + } + return s.Internal.EthSendRawTransaction(p0, p1) +} + +func (s *GatewayStub) EthSendRawTransaction(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) { + return *new(ethtypes.EthHash), ErrNotSupported +} + +func (s *GatewayStruct) EthSubscribe(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) { + if s.Internal.EthSubscribe == nil { + return nil, ErrNotSupported + } + return s.Internal.EthSubscribe(p0, p1, p2) +} + +func (s *GatewayStub) EthSubscribe(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) { + return nil, ErrNotSupported +} + +func (s *GatewayStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) { + if s.Internal.EthUninstallFilter == nil { + return false, ErrNotSupported + } + return s.Internal.EthUninstallFilter(p0, p1) +} + +func (s *GatewayStub) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) { + return false, ErrNotSupported +} + +func (s *GatewayStruct) EthUnsubscribe(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) { + if s.Internal.EthUnsubscribe == nil { + return false, ErrNotSupported + } + return s.Internal.EthUnsubscribe(p0, p1) +} + +func (s *GatewayStub) EthUnsubscribe(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) { + return false, ErrNotSupported +} + func (s *GatewayStruct) GasEstimateMessageGas(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) { if s.Internal.GasEstimateMessageGas == nil { return nil, ErrNotSupported @@ -4075,6 +4482,28 @@ func (s *GatewayStub) MsigGetVestingSchedule(p0 context.Context, p1 address.Addr return *new(MsigVesting), ErrNotSupported } +func (s *GatewayStruct) NetListening(p0 context.Context) (bool, error) { + if s.Internal.NetListening == nil { + return false, ErrNotSupported + } + return s.Internal.NetListening(p0) +} + +func (s *GatewayStub) NetListening(p0 context.Context) (bool, error) { + return false, ErrNotSupported +} + +func (s *GatewayStruct) NetVersion(p0 context.Context) (string, error) { + if s.Internal.NetVersion == nil { + return "", ErrNotSupported + } + return s.Internal.NetVersion(p0) +} + +func (s *GatewayStub) NetVersion(p0 context.Context) (string, error) { + return "", ErrNotSupported +} + func (s *GatewayStruct) StateAccountKey(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) { if s.Internal.StateAccountKey == nil { return *new(address.Address), ErrNotSupported diff --git a/api/types/rpc.go b/api/types/rpc.go new file mode 100644 index 000000000..4bde6dfbc --- /dev/null +++ b/api/types/rpc.go @@ -0,0 +1,5 @@ +package apitypes + +type Aliaser interface { + AliasMethod(alias, original string) +} diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index b59fd8860..6b4fc7b4f 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index 9277b2d1f..cc3870a49 100644 Binary files a/build/openrpc/gateway.json.gz and b/build/openrpc/gateway.json.gz differ diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 3937893cb..4f67b5393 100644 Binary files a/build/openrpc/miner.json.gz and b/build/openrpc/miner.json.gz differ diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index 3ecfb6abf..88e449804 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/gateway/handler.go b/gateway/handler.go index be824b430..e9bee6d52 100644 --- a/gateway/handler.go +++ b/gateway/handler.go @@ -25,6 +25,10 @@ type perConnLimiterKeyType string const perConnLimiterKey perConnLimiterKeyType = "limiter" +type filterTrackerKeyType string + +const filterTrackerKey filterTrackerKeyType = "filterTracker" + // Handler returns a gateway http.Handler, to be mounted as-is on the server. func Handler(gwapi lapi.Gateway, api lapi.FullNode, rateLimit int64, connPerMinute int64, opts ...jsonrpc.ServerOption) (http.Handler, error) { m := mux.NewRouter() @@ -34,6 +38,8 @@ func Handler(gwapi lapi.Gateway, api lapi.FullNode, rateLimit int64, connPerMinu rpcServer.Register("Filecoin", hnd) rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover") + lapi.CreateEthRPCAliases(rpcServer) + m.Handle(path, rpcServer) } @@ -81,8 +87,12 @@ type RateLimiterHandler struct { } func (h RateLimiterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - r2 := r.WithContext(context.WithValue(r.Context(), perConnLimiterKey, h.limiter)) - h.handler.ServeHTTP(w, r2) + r = r.WithContext(context.WithValue(r.Context(), perConnLimiterKey, h.limiter)) + + // also add a filter tracker to the context + r = r.WithContext(context.WithValue(r.Context(), filterTrackerKey, newFilterTracker())) + + h.handler.ServeHTTP(w, r) } // this blocks new connections if there have already been too many. diff --git a/gateway/node.go b/gateway/node.go index 13ac57c82..f18189ae2 100644 --- a/gateway/node.go +++ b/gateway/node.go @@ -9,21 +9,18 @@ import ( "github.com/ipfs/go-cid" "go.opencensus.io/stats" "golang.org/x/time/rate" - "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/api" - apitypes "github.com/filecoin-project/lotus/api/types" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/lib/sigs" + "github.com/filecoin-project/lotus/chain/types/ethtypes" _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/delegated" _ "github.com/filecoin-project/lotus/lib/sigs/secp" @@ -88,7 +85,40 @@ type TargetAPI interface { StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (api.CirculatingSupply, error) - WalletBalance(context.Context, address.Address) (types.BigInt, error) //perm:read + WalletBalance(context.Context, address.Address) (types.BigInt, error) + + EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) + EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) + EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) + EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) + EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) + EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) + EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) + EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) + EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) + EthChainId(ctx context.Context) (ethtypes.EthUint64, error) + NetVersion(ctx context.Context) (string, error) + NetListening(ctx context.Context) (bool, error) + EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) + EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) + EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) + EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) + EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) + EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) + EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) + EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) + EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) + EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) + EthNewFilter(ctx context.Context, filter *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) + EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) + EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) + EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) + EthSubscribe(ctx context.Context, eventType string, params *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) + EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) } var _ TargetAPI = *new(api.FullNode) // gateway depends on latest @@ -184,462 +214,3 @@ func (gw *Node) limit(ctx context.Context, tokens int) error { } return nil } - -func (gw *Node) Discover(ctx context.Context) (apitypes.OpenRPCDocument, error) { - return build.OpenRPCDiscoverJSON_Gateway(), nil -} - -func (gw *Node) Version(ctx context.Context) (api.APIVersion, error) { - if err := gw.limit(ctx, basicRateLimitTokens); err != nil { - return api.APIVersion{}, err - } - return gw.target.Version(ctx) -} - -func (gw *Node) ChainGetParentMessages(ctx context.Context, c cid.Cid) ([]api.Message, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetParentMessages(ctx, c) -} - -func (gw *Node) ChainGetParentReceipts(ctx context.Context, c cid.Cid) ([]*types.MessageReceipt, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetParentReceipts(ctx, c) -} - -func (gw *Node) ChainGetBlockMessages(ctx context.Context, c cid.Cid) (*api.BlockMessages, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetBlockMessages(ctx, c) -} - -func (gw *Node) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return false, err - } - return gw.target.ChainHasObj(ctx, c) -} - -func (gw *Node) ChainHead(ctx context.Context) (*types.TipSet, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - - return gw.target.ChainHead(ctx) -} - -func (gw *Node) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetMessage(ctx, mc) -} - -func (gw *Node) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetTipSet(ctx, tsk) -} - -func (gw *Node) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipSetHeight(ctx, h, tsk); err != nil { - return nil, err - } - return gw.target.ChainGetTipSetByHeight(ctx, h, tsk) -} - -func (gw *Node) ChainGetTipSetAfterHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipSetHeight(ctx, h, tsk); err != nil { - return nil, err - } - return gw.target.ChainGetTipSetAfterHeight(ctx, h, tsk) -} - -func (gw *Node) checkTipSetHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) error { - var ts *types.TipSet - if tsk.IsEmpty() { - head, err := gw.target.ChainHead(ctx) - if err != nil { - return err - } - ts = head - } else { - gts, err := gw.target.ChainGetTipSet(ctx, tsk) - if err != nil { - return err - } - ts = gts - } - - // Check if the tipset key refers to gw tipset that's too far in the past - if err := gw.checkTipset(ts); err != nil { - return err - } - - // Check if the height is too far in the past - if err := gw.checkTipsetHeight(ts, h); err != nil { - return err - } - - return nil -} - -func (gw *Node) ChainGetNode(ctx context.Context, p string) (*api.IpldObject, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetNode(ctx, p) -} - -func (gw *Node) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainNotify(ctx) -} - -func (gw *Node) ChainGetPath(ctx context.Context, from, to types.TipSetKey) ([]*api.HeadChange, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, from); err != nil { - return nil, xerrors.Errorf("gateway: checking 'from' tipset: %w", err) - } - if err := gw.checkTipsetKey(ctx, to); err != nil { - return nil, xerrors.Errorf("gateway: checking 'to' tipset: %w", err) - } - return gw.target.ChainGetPath(ctx, from, to) -} - -func (gw *Node) ChainGetGenesis(ctx context.Context) (*types.TipSet, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainGetGenesis(ctx) -} - -func (gw *Node) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) { - if err := gw.limit(ctx, chainRateLimitTokens); err != nil { - return nil, err - } - return gw.target.ChainReadObj(ctx, c) -} - -func (gw *Node) ChainPutObj(context.Context, blocks.Block) error { - return xerrors.New("not supported") -} - -func (gw *Node) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.GasEstimateMessageGas(ctx, msg, spec, tsk) -} - -func (gw *Node) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return cid.Cid{}, err - } - // TODO: additional anti-spam checks - return gw.target.MpoolPushUntrusted(ctx, sm) -} - -func (gw *Node) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) { - if err := gw.limit(ctx, walletRateLimitTokens); err != nil { - return types.BigInt{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return types.NewInt(0), err - } - return gw.target.MsigGetAvailableBalance(ctx, addr, tsk) -} - -func (gw *Node) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) { - if err := gw.limit(ctx, walletRateLimitTokens); err != nil { - return types.BigInt{}, err - } - if err := gw.checkTipsetKey(ctx, start); err != nil { - return types.NewInt(0), err - } - if err := gw.checkTipsetKey(ctx, end); err != nil { - return types.NewInt(0), err - } - return gw.target.MsigGetVested(ctx, addr, start, end) -} - -func (gw *Node) MsigGetVestingSchedule(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MsigVesting, error) { - if err := gw.limit(ctx, walletRateLimitTokens); err != nil { - return api.MsigVesting{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return api.MsigVesting{}, err - } - return gw.target.MsigGetVestingSchedule(ctx, addr, tsk) -} - -func (gw *Node) MsigGetPending(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.MsigTransaction, error) { - if err := gw.limit(ctx, walletRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.MsigGetPending(ctx, addr, tsk) -} - -func (gw *Node) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return address.Address{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return address.Undef, err - } - return gw.target.StateAccountKey(ctx, addr, tsk) -} - -func (gw *Node) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return api.DealCollateralBounds{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return api.DealCollateralBounds{}, err - } - return gw.target.StateDealProviderCollateralBounds(ctx, size, verified, tsk) -} - -func (gw *Node) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateGetActor(ctx, actor, tsk) -} - -func (gw *Node) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateListMiners(ctx, tsk) -} - -func (gw *Node) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return address.Address{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return address.Undef, err - } - return gw.target.StateLookupID(ctx, addr, tsk) -} - -func (gw *Node) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return api.MarketBalance{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return api.MarketBalance{}, err - } - return gw.target.StateMarketBalance(ctx, addr, tsk) -} - -func (gw *Node) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateMarketStorageDeal(ctx, dealId, tsk) -} - -func (gw *Node) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return network.VersionMax, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return network.VersionMax, err - } - return gw.target.StateNetworkVersion(ctx, tsk) -} - -func (gw *Node) StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if limit == api.LookbackNoLimit { - limit = gw.stateWaitLookbackLimit - } - if gw.stateWaitLookbackLimit != api.LookbackNoLimit && limit > gw.stateWaitLookbackLimit { - limit = gw.stateWaitLookbackLimit - } - if err := gw.checkTipsetKey(ctx, from); err != nil { - return nil, err - } - return gw.target.StateSearchMsg(ctx, from, msg, limit, allowReplaced) -} - -func (gw *Node) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if limit == api.LookbackNoLimit { - limit = gw.stateWaitLookbackLimit - } - if gw.stateWaitLookbackLimit != api.LookbackNoLimit && limit > gw.stateWaitLookbackLimit { - limit = gw.stateWaitLookbackLimit - } - return gw.target.StateWaitMsg(ctx, msg, confidence, limit, allowReplaced) -} - -func (gw *Node) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateReadState(ctx, actor, tsk) -} - -func (gw *Node) StateMinerPower(ctx context.Context, m address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateMinerPower(ctx, m, tsk) -} - -func (gw *Node) StateMinerFaults(ctx context.Context, m address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return bitfield.BitField{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return bitfield.BitField{}, err - } - return gw.target.StateMinerFaults(ctx, m, tsk) -} - -func (gw *Node) StateMinerRecoveries(ctx context.Context, m address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return bitfield.BitField{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return bitfield.BitField{}, err - } - return gw.target.StateMinerRecoveries(ctx, m, tsk) -} - -func (gw *Node) StateMinerInfo(ctx context.Context, m address.Address, tsk types.TipSetKey) (api.MinerInfo, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return api.MinerInfo{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return api.MinerInfo{}, err - } - return gw.target.StateMinerInfo(ctx, m, tsk) -} - -func (gw *Node) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) ([]api.Deadline, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateMinerDeadlines(ctx, m, tsk) -} - -func (gw *Node) StateMinerAvailableBalance(ctx context.Context, m address.Address, tsk types.TipSetKey) (types.BigInt, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return types.BigInt{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return types.BigInt{}, err - } - return gw.target.StateMinerAvailableBalance(ctx, m, tsk) -} - -func (gw *Node) StateMinerProvingDeadline(ctx context.Context, m address.Address, tsk types.TipSetKey) (*dline.Info, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateMinerProvingDeadline(ctx, m, tsk) -} - -func (gw *Node) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (abi.TokenAmount, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return abi.TokenAmount{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return abi.TokenAmount{}, err - } - return gw.target.StateCirculatingSupply(ctx, tsk) -} - -func (gw *Node) StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateSectorGetInfo(ctx, maddr, n, tsk) -} - -func (gw *Node) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return nil, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return nil, err - } - return gw.target.StateVerifiedClientStatus(ctx, addr, tsk) -} - -func (gw *Node) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return api.CirculatingSupply{}, err - } - if err := gw.checkTipsetKey(ctx, tsk); err != nil { - return api.CirculatingSupply{}, err - } - return gw.target.StateVMCirculatingSupplyInternal(ctx, tsk) -} - -func (gw *Node) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *crypto.Signature) (bool, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return false, err - } - return sigs.Verify(sig, k, msg) == nil, nil -} - -func (gw *Node) WalletBalance(ctx context.Context, k address.Address) (types.BigInt, error) { - if err := gw.limit(ctx, stateRateLimitTokens); err != nil { - return types.BigInt{}, err - } - return gw.target.WalletBalance(ctx, k) -} diff --git a/gateway/proxy_eth.go b/gateway/proxy_eth.go new file mode 100644 index 000000000..fcad213d9 --- /dev/null +++ b/gateway/proxy_eth.go @@ -0,0 +1,481 @@ +package gateway + +import ( + "bytes" + "context" + "fmt" + "sync" + "time" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" +) + +func (gw *Node) EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) { + // gateway provides public API, so it can't hold user accounts + return []ethtypes.EthAddress{}, nil +} + +func (gw *Node) EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + return gw.target.EthBlockNumber(ctx) +} + +func (gw *Node) EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + head, err := gw.target.ChainHead(ctx) + if err != nil { + return 0, err + } + if err := gw.checkTipsetHeight(head, abi.ChainEpoch(blkNum)); err != nil { + return 0, err + } + + return gw.target.EthGetBlockTransactionCountByNumber(ctx, blkNum) +} + +func (gw *Node) tskByEthHash(ctx context.Context, blkHash ethtypes.EthHash) (types.TipSetKey, error) { + tskCid := blkHash.ToCid() + tskBlk, err := gw.target.ChainReadObj(ctx, tskCid) + if err != nil { + return types.EmptyTSK, err + } + tsk := new(types.TipSetKey) + if err := tsk.UnmarshalCBOR(bytes.NewReader(tskBlk)); err != nil { + return types.EmptyTSK, xerrors.Errorf("cannot unmarshal block into tipset key: %w", err) + } + + return *tsk, nil +} + +func (gw *Node) checkBlkHash(ctx context.Context, blkHash ethtypes.EthHash) error { + tsk, err := gw.tskByEthHash(ctx, blkHash) + if err != nil { + return err + } + + return gw.checkTipsetKey(ctx, tsk) +} + +func (gw *Node) checkBlkParam(ctx context.Context, blkParam string) error { + if blkParam == "earliest" { + // also not supported in node impl + return fmt.Errorf("block param \"earliest\" is not supported") + } + + switch blkParam { + case "pending", "latest": + // those will be recent enough, so we don't need to check + return nil + default: + var num ethtypes.EthUint64 + err := num.UnmarshalJSON([]byte(`"` + blkParam + `"`)) + if err != nil { + return fmt.Errorf("cannot parse block number: %v", err) + } + head, err := gw.target.ChainHead(ctx) + if err != nil { + return err + } + if err := gw.checkTipsetHeight(head, abi.ChainEpoch(num)); err != nil { + return err + } + } + + return nil +} + +func (gw *Node) EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + if err := gw.checkBlkHash(ctx, blkHash); err != nil { + return 0, err + } + + return gw.target.EthGetBlockTransactionCountByHash(ctx, blkHash) +} + +func (gw *Node) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthBlock{}, err + } + + if err := gw.checkBlkHash(ctx, blkHash); err != nil { + return ethtypes.EthBlock{}, err + } + + return gw.target.EthGetBlockByHash(ctx, blkHash, fullTxInfo) +} + +func (gw *Node) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthBlock{}, err + } + + if err := gw.checkBlkParam(ctx, blkNum); err != nil { + return ethtypes.EthBlock{}, err + } + + return gw.target.EthGetBlockByNumber(ctx, blkNum, fullTxInfo) +} + +func (gw *Node) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + return gw.target.EthGetTransactionByHash(ctx, txHash) +} + +func (gw *Node) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + if err := gw.checkBlkParam(ctx, blkOpt); err != nil { + return 0, err + } + + return gw.target.EthGetTransactionCount(ctx, sender, blkOpt) +} + +func (gw *Node) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + return gw.target.EthGetTransactionReceipt(ctx, txHash) +} + +func (gw *Node) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthTx{}, err + } + + if err := gw.checkBlkHash(ctx, blkHash); err != nil { + return ethtypes.EthTx{}, err + } + + return gw.target.EthGetTransactionByBlockHashAndIndex(ctx, blkHash, txIndex) +} + +func (gw *Node) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthTx{}, err + } + + head, err := gw.target.ChainHead(ctx) + if err != nil { + return ethtypes.EthTx{}, err + } + if err := gw.checkTipsetHeight(head, abi.ChainEpoch(blkNum)); err != nil { + return ethtypes.EthTx{}, err + } + + return gw.target.EthGetTransactionByBlockNumberAndIndex(ctx, blkNum, txIndex) +} + +func (gw *Node) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + if err := gw.checkBlkParam(ctx, blkOpt); err != nil { + return nil, err + } + + return gw.target.EthGetCode(ctx, address, blkOpt) +} + +func (gw *Node) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + if err := gw.checkBlkParam(ctx, blkParam); err != nil { + return nil, err + } + + return gw.target.EthGetStorageAt(ctx, address, position, blkParam) +} + +func (gw *Node) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthBigInt(big.Zero()), err + } + + if err := gw.checkBlkParam(ctx, blkParam); err != nil { + return ethtypes.EthBigInt(big.Zero()), err + } + + return gw.target.EthGetBalance(ctx, address, blkParam) +} + +func (gw *Node) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + return gw.target.EthChainId(ctx) +} + +func (gw *Node) NetVersion(ctx context.Context) (string, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return "", err + } + + return gw.target.NetVersion(ctx) +} + +func (gw *Node) NetListening(ctx context.Context) (bool, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return false, err + } + + return gw.target.NetListening(ctx) +} + +func (gw *Node) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + return gw.target.EthProtocolVersion(ctx) +} + +func (gw *Node) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthBigInt(big.Zero()), err + } + + return gw.target.EthGasPrice(ctx) +} + +var EthFeeHistoryMaxBlockCount = 128 // this seems to be expensive; todo: figure out what is a good number that works with everything + +func (gw *Node) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthFeeHistory{}, err + } + + if err := gw.checkBlkParam(ctx, newestBlk); err != nil { + return ethtypes.EthFeeHistory{}, err + } + + if blkCount > ethtypes.EthUint64(EthFeeHistoryMaxBlockCount) { + return ethtypes.EthFeeHistory{}, fmt.Errorf("block count too high") + } + + return gw.target.EthFeeHistory(ctx, blkCount, newestBlk, rewardPercentiles) +} + +func (gw *Node) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthBigInt(big.Zero()), err + } + + return gw.target.EthMaxPriorityFeePerGas(ctx) +} + +func (gw *Node) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return 0, err + } + + // todo limit gas? to what? + return gw.target.EthEstimateGas(ctx, tx) +} + +func (gw *Node) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + if err := gw.checkBlkParam(ctx, blkParam); err != nil { + return nil, err + } + + // todo limit gas? to what? + return gw.target.EthCall(ctx, tx, blkParam) +} + +func (gw *Node) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthHash{}, err + } + + return gw.target.EthSendRawTransaction(ctx, rawTx) +} + +func (gw *Node) EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + if filter.FromBlock != nil { + if err := gw.checkBlkParam(ctx, *filter.FromBlock); err != nil { + return nil, err + } + } + if filter.ToBlock != nil { + if err := gw.checkBlkParam(ctx, *filter.ToBlock); err != nil { + return nil, err + } + } + if filter.BlockHash != nil { + if err := gw.checkBlkHash(ctx, *filter.BlockHash); err != nil { + return nil, err + } + } + + return gw.target.EthGetLogs(ctx, filter) +} + +/* FILTERS: Those are stateful.. figure out how to properly either bind them to users, or time out? */ + +func (gw *Node) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + ft := filterTrackerFromContext(ctx) + ft.lk.Lock() + _, ok := ft.userFilters[id] + ft.lk.Unlock() + + if !ok { + return nil, nil + } + + return gw.target.EthGetFilterChanges(ctx, id) +} + +func (gw *Node) EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + + ft := filterTrackerFromContext(ctx) + ft.lk.Lock() + _, ok := ft.userFilters[id] + ft.lk.Unlock() + + if !ok { + return nil, nil + } + + return gw.target.EthGetFilterLogs(ctx, id) +} + +func (gw *Node) EthNewFilter(ctx context.Context, filter *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthFilterID{}, err + } + + return addUserFilterLimited(ctx, func() (ethtypes.EthFilterID, error) { + return gw.target.EthNewFilter(ctx, filter) + }) +} + +func (gw *Node) EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthFilterID{}, err + } + + return addUserFilterLimited(ctx, func() (ethtypes.EthFilterID, error) { + return gw.target.EthNewBlockFilter(ctx) + }) +} + +func (gw *Node) EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return ethtypes.EthFilterID{}, err + } + + return addUserFilterLimited(ctx, func() (ethtypes.EthFilterID, error) { + return gw.target.EthNewPendingTransactionFilter(ctx) + }) +} + +func (gw *Node) EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return false, err + } + + // check if the filter belongs to this connection + ft := filterTrackerFromContext(ctx) + ft.lk.Lock() + defer ft.lk.Unlock() + + if _, ok := ft.userFilters[id]; !ok { + return false, nil + } + + ok, err := gw.target.EthUninstallFilter(ctx, id) + if err != nil { + return false, err + } + + delete(ft.userFilters, id) + return ok, nil +} + +func (gw *Node) EthSubscribe(ctx context.Context, eventType string, params *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) { + return nil, xerrors.Errorf("not implemented") +} + +func (gw *Node) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) { + return false, xerrors.Errorf("not implemented") +} + +var EthMaxFiltersPerConn = 16 // todo make this configurable + +func addUserFilterLimited(ctx context.Context, cb func() (ethtypes.EthFilterID, error)) (ethtypes.EthFilterID, error) { + ft := filterTrackerFromContext(ctx) + ft.lk.Lock() + defer ft.lk.Unlock() + + if len(ft.userFilters) >= EthMaxFiltersPerConn { + return ethtypes.EthFilterID{}, fmt.Errorf("too many filters") + } + + id, err := cb() + if err != nil { + return id, err + } + + ft.userFilters[id] = time.Now() + + return id, nil +} + +func filterTrackerFromContext(ctx context.Context) *filterTracker { + return ctx.Value(filterTrackerKey).(*filterTracker) +} + +type filterTracker struct { + lk sync.Mutex + + userFilters map[ethtypes.EthFilterID]time.Time +} + +// called per request (ws connection) +func newFilterTracker() *filterTracker { + return &filterTracker{ + userFilters: make(map[ethtypes.EthFilterID]time.Time), + } +} diff --git a/gateway/proxy_fil.go b/gateway/proxy_fil.go new file mode 100644 index 000000000..0e53130fb --- /dev/null +++ b/gateway/proxy_fil.go @@ -0,0 +1,482 @@ +package gateway + +import ( + "context" + + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/network" + + "github.com/filecoin-project/lotus/api" + apitypes "github.com/filecoin-project/lotus/api/types" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/sigs" +) + +func (gw *Node) Discover(ctx context.Context) (apitypes.OpenRPCDocument, error) { + return build.OpenRPCDiscoverJSON_Gateway(), nil +} + +func (gw *Node) Version(ctx context.Context) (api.APIVersion, error) { + if err := gw.limit(ctx, basicRateLimitTokens); err != nil { + return api.APIVersion{}, err + } + return gw.target.Version(ctx) +} + +func (gw *Node) ChainGetParentMessages(ctx context.Context, c cid.Cid) ([]api.Message, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetParentMessages(ctx, c) +} + +func (gw *Node) ChainGetParentReceipts(ctx context.Context, c cid.Cid) ([]*types.MessageReceipt, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetParentReceipts(ctx, c) +} + +func (gw *Node) ChainGetBlockMessages(ctx context.Context, c cid.Cid) (*api.BlockMessages, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetBlockMessages(ctx, c) +} + +func (gw *Node) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return false, err + } + return gw.target.ChainHasObj(ctx, c) +} + +func (gw *Node) ChainHead(ctx context.Context) (*types.TipSet, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + + return gw.target.ChainHead(ctx) +} + +func (gw *Node) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetMessage(ctx, mc) +} + +func (gw *Node) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetTipSet(ctx, tsk) +} + +func (gw *Node) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipSetHeight(ctx, h, tsk); err != nil { + return nil, err + } + return gw.target.ChainGetTipSetByHeight(ctx, h, tsk) +} + +func (gw *Node) ChainGetTipSetAfterHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipSetHeight(ctx, h, tsk); err != nil { + return nil, err + } + return gw.target.ChainGetTipSetAfterHeight(ctx, h, tsk) +} + +func (gw *Node) checkTipSetHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) error { + var ts *types.TipSet + if tsk.IsEmpty() { + head, err := gw.target.ChainHead(ctx) + if err != nil { + return err + } + ts = head + } else { + gts, err := gw.target.ChainGetTipSet(ctx, tsk) + if err != nil { + return err + } + ts = gts + } + + // Check if the tipset key refers to gw tipset that's too far in the past + if err := gw.checkTipset(ts); err != nil { + return err + } + + // Check if the height is too far in the past + if err := gw.checkTipsetHeight(ts, h); err != nil { + return err + } + + return nil +} + +func (gw *Node) ChainGetNode(ctx context.Context, p string) (*api.IpldObject, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetNode(ctx, p) +} + +func (gw *Node) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainNotify(ctx) +} + +func (gw *Node) ChainGetPath(ctx context.Context, from, to types.TipSetKey) ([]*api.HeadChange, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, from); err != nil { + return nil, xerrors.Errorf("gateway: checking 'from' tipset: %w", err) + } + if err := gw.checkTipsetKey(ctx, to); err != nil { + return nil, xerrors.Errorf("gateway: checking 'to' tipset: %w", err) + } + return gw.target.ChainGetPath(ctx, from, to) +} + +func (gw *Node) ChainGetGenesis(ctx context.Context) (*types.TipSet, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainGetGenesis(ctx) +} + +func (gw *Node) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) { + if err := gw.limit(ctx, chainRateLimitTokens); err != nil { + return nil, err + } + return gw.target.ChainReadObj(ctx, c) +} + +func (gw *Node) ChainPutObj(context.Context, blocks.Block) error { + return xerrors.New("not supported") +} + +func (gw *Node) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.GasEstimateMessageGas(ctx, msg, spec, tsk) +} + +func (gw *Node) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return cid.Cid{}, err + } + // TODO: additional anti-spam checks + return gw.target.MpoolPushUntrusted(ctx, sm) +} + +func (gw *Node) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) { + if err := gw.limit(ctx, walletRateLimitTokens); err != nil { + return types.BigInt{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return types.NewInt(0), err + } + return gw.target.MsigGetAvailableBalance(ctx, addr, tsk) +} + +func (gw *Node) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) { + if err := gw.limit(ctx, walletRateLimitTokens); err != nil { + return types.BigInt{}, err + } + if err := gw.checkTipsetKey(ctx, start); err != nil { + return types.NewInt(0), err + } + if err := gw.checkTipsetKey(ctx, end); err != nil { + return types.NewInt(0), err + } + return gw.target.MsigGetVested(ctx, addr, start, end) +} + +func (gw *Node) MsigGetVestingSchedule(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MsigVesting, error) { + if err := gw.limit(ctx, walletRateLimitTokens); err != nil { + return api.MsigVesting{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return api.MsigVesting{}, err + } + return gw.target.MsigGetVestingSchedule(ctx, addr, tsk) +} + +func (gw *Node) MsigGetPending(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.MsigTransaction, error) { + if err := gw.limit(ctx, walletRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.MsigGetPending(ctx, addr, tsk) +} + +func (gw *Node) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return address.Address{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return address.Undef, err + } + return gw.target.StateAccountKey(ctx, addr, tsk) +} + +func (gw *Node) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return api.DealCollateralBounds{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return api.DealCollateralBounds{}, err + } + return gw.target.StateDealProviderCollateralBounds(ctx, size, verified, tsk) +} + +func (gw *Node) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateGetActor(ctx, actor, tsk) +} + +func (gw *Node) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateListMiners(ctx, tsk) +} + +func (gw *Node) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return address.Address{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return address.Undef, err + } + return gw.target.StateLookupID(ctx, addr, tsk) +} + +func (gw *Node) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return api.MarketBalance{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return api.MarketBalance{}, err + } + return gw.target.StateMarketBalance(ctx, addr, tsk) +} + +func (gw *Node) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateMarketStorageDeal(ctx, dealId, tsk) +} + +func (gw *Node) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return network.VersionMax, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return network.VersionMax, err + } + return gw.target.StateNetworkVersion(ctx, tsk) +} + +func (gw *Node) StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if limit == api.LookbackNoLimit { + limit = gw.stateWaitLookbackLimit + } + if gw.stateWaitLookbackLimit != api.LookbackNoLimit && limit > gw.stateWaitLookbackLimit { + limit = gw.stateWaitLookbackLimit + } + if err := gw.checkTipsetKey(ctx, from); err != nil { + return nil, err + } + return gw.target.StateSearchMsg(ctx, from, msg, limit, allowReplaced) +} + +func (gw *Node) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if limit == api.LookbackNoLimit { + limit = gw.stateWaitLookbackLimit + } + if gw.stateWaitLookbackLimit != api.LookbackNoLimit && limit > gw.stateWaitLookbackLimit { + limit = gw.stateWaitLookbackLimit + } + return gw.target.StateWaitMsg(ctx, msg, confidence, limit, allowReplaced) +} + +func (gw *Node) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateReadState(ctx, actor, tsk) +} + +func (gw *Node) StateMinerPower(ctx context.Context, m address.Address, tsk types.TipSetKey) (*api.MinerPower, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateMinerPower(ctx, m, tsk) +} + +func (gw *Node) StateMinerFaults(ctx context.Context, m address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return bitfield.BitField{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return bitfield.BitField{}, err + } + return gw.target.StateMinerFaults(ctx, m, tsk) +} + +func (gw *Node) StateMinerRecoveries(ctx context.Context, m address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return bitfield.BitField{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return bitfield.BitField{}, err + } + return gw.target.StateMinerRecoveries(ctx, m, tsk) +} + +func (gw *Node) StateMinerInfo(ctx context.Context, m address.Address, tsk types.TipSetKey) (api.MinerInfo, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return api.MinerInfo{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return api.MinerInfo{}, err + } + return gw.target.StateMinerInfo(ctx, m, tsk) +} + +func (gw *Node) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) ([]api.Deadline, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateMinerDeadlines(ctx, m, tsk) +} + +func (gw *Node) StateMinerAvailableBalance(ctx context.Context, m address.Address, tsk types.TipSetKey) (types.BigInt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return types.BigInt{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return types.BigInt{}, err + } + return gw.target.StateMinerAvailableBalance(ctx, m, tsk) +} + +func (gw *Node) StateMinerProvingDeadline(ctx context.Context, m address.Address, tsk types.TipSetKey) (*dline.Info, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateMinerProvingDeadline(ctx, m, tsk) +} + +func (gw *Node) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (abi.TokenAmount, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return abi.TokenAmount{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return abi.TokenAmount{}, err + } + return gw.target.StateCirculatingSupply(ctx, tsk) +} + +func (gw *Node) StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateSectorGetInfo(ctx, maddr, n, tsk) +} + +func (gw *Node) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return nil, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return nil, err + } + return gw.target.StateVerifiedClientStatus(ctx, addr, tsk) +} + +func (gw *Node) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return api.CirculatingSupply{}, err + } + if err := gw.checkTipsetKey(ctx, tsk); err != nil { + return api.CirculatingSupply{}, err + } + return gw.target.StateVMCirculatingSupplyInternal(ctx, tsk) +} + +func (gw *Node) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *crypto.Signature) (bool, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return false, err + } + return sigs.Verify(sig, k, msg) == nil, nil +} + +func (gw *Node) WalletBalance(ctx context.Context, k address.Address) (types.BigInt, error) { + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { + return types.BigInt{}, err + } + return gw.target.WalletBalance(ctx, k) +} diff --git a/node/builder_chain.go b/node/builder_chain.go index 584cf3a60..541b451b7 100644 --- a/node/builder_chain.go +++ b/node/builder_chain.go @@ -152,8 +152,8 @@ var ChainNode = Options( Override(new(full.MpoolModuleAPI), From(new(api.Gateway))), Override(new(full.StateModuleAPI), From(new(api.Gateway))), Override(new(stmgr.StateManagerAPI), rpcstmgr.NewRPCStateManager), - // this to make tests pass, but we should consider actually implementing it in the gateway - Override(new(full.EthModuleAPI), new(full.EthModuleDummy)), + Override(new(full.EthModuleAPI), From(new(api.Gateway))), + Override(new(full.EthEventAPI), From(new(api.Gateway))), ), // Full node API / service startup @@ -259,7 +259,8 @@ func ConfigFullNode(c interface{}) Option { // Actor event filtering support Override(new(events.EventAPI), From(new(modules.EventAPI))), - Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.ActorEvent)), + // in lite-mode Eth event api is provided by gateway + ApplyIf(isFullNode, Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.ActorEvent))), ) } diff --git a/node/rpc.go b/node/rpc.go index c454e39be..a96e6e3ac 100644 --- a/node/rpc.go +++ b/node/rpc.go @@ -79,44 +79,7 @@ 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_feeHistory", "Filecoin.EthFeeHistory") - 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("eth_getLogs", "Filecoin.EthGetLogs") - rpcServer.AliasMethod("eth_getFilterChanges", "Filecoin.EthGetFilterChanges") - rpcServer.AliasMethod("eth_getFilterLogs", "Filecoin.EthGetFilterLogs") - rpcServer.AliasMethod("eth_newFilter", "Filecoin.EthNewFilter") - rpcServer.AliasMethod("eth_newBlockFilter", "Filecoin.EthNewBlockFilter") - rpcServer.AliasMethod("eth_newPendingTransactionFilter", "Filecoin.EthNewPendingTransactionFilter") - rpcServer.AliasMethod("eth_uninstallFilter", "Filecoin.EthUninstallFilter") - rpcServer.AliasMethod("eth_subscribe", "Filecoin.EthSubscribe") - rpcServer.AliasMethod("eth_unsubscribe", "Filecoin.EthUnsubscribe") - - rpcServer.AliasMethod("net_version", "Filecoin.NetVersion") - rpcServer.AliasMethod("net_listening", "Filecoin.NetListening") + api.CreateEthRPCAliases(rpcServer) var handler http.Handler = rpcServer if permissioned { @@ -144,7 +107,6 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server Next: handleImportFunc, } m.Handle("/rest/v0/import", importAH) - exportAH := &auth.Handler{ Verify: a.AuthVerify, Next: handleExportFunc,