Skip to content

Commit bde20c3

Browse files
committed
feat(eth)!: add Eth APIs to /v2 + minor improvements & fixes
1 parent a8999cb commit bde20c3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+11242
-2966
lines changed

CHANGELOG.md

+12-5
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,19 @@
1111

1212
- fix(eth): always return nil for eth transactions not found ([filecoin-project/lotus#12999](https://github.com/filecoin-project/lotus/pull/12999))
1313
- feat: add gas to application metric reporting `vm/applyblocks_early_gas`, `vm/applyblocks_messages_gas`, `vm/applyblocks_cron_gas` ([filecoin-project/lotus#13030](https://github.com/filecoin-project/lotus/pull/13030))
14-
- feat: add Lotus v2 experimental APIs with F3 awareness
14+
- feat: add **Lotus v2 experimental APIs with F3 awareness**:<br>
1515
The Lotus V2 APIs introduce a powerful new TipSet selection mechanism that significantly enhances how applications interact with the Filecoin blockchain. The design reduces API footprint, seamlessly handles both traditional Expected Consensus and the new F3 protocol, and provides graceful fallbacks. See [Filecoin v2 APIs](https://filoznotebook.notion.site/Filecoin-V2-APIs-1d0dc41950c1808b914de5966d501658) for an
16-
in-depth overview.
17-
Pull requests:
18-
- https://github.com/filecoin-project/lotus/pull/13003
19-
- https://github.com/filecoin-project/lotus/pull/13027
16+
in-depth overview. ([filecoin-project/lotus#13003](https://github.com/filecoin-project/lotus/pull/13003)), ([filecoin-project/lotus#13027](https://github.com/filecoin-project/lotus/pull/13027))
17+
- feat: add **Ethereum APIs to v2 with F3 awareness** and minor improvements to v1 Ethereum APIs:<br>
18+
The full suite of Ethereum APIs supported by Lotus (aliased by `eth_`, `trace_` etc. for compatibility) are now also exposed on the new V2 API endpoint. Functionality of the APIs remains identical, however the mapping of `"finalized"` and `"safe"` will defer to F3 rather than using fixed epochs. When F3 is operating normally, both of these labels will choose the parent of the F3 finalized epoch rather than their EC fixed values as used in V1 APIs. Use the `/v2` API endpoint to be able to use `"finalized"` and be closer to the chain head when F3 is active. ([filecoin-project/lotus#13026](https://github.com/filecoin-project/lotus/pull/13026))<br>
19+
Additional changes to the Ethereum APIs (both V1 and V2) introduced in this release include:
20+
- `eth_getBlockTransactionCountByNumber` now takes the standard Ethereum block number specifier: hex encoded integers _or_ labels including `"latest"`, `"safe"` and `"finalized"`.
21+
- All APIs that take a `BlockNumberOrHash` now handle the full range of labels: `"pending"`, `"latest"`, `"safe"`, `"finalized"` (previously only the first two were supported). These include: `eth_estimateGas`, `eth_call`, `eth_getCode`, `eth_getStorageAt`, `eth_getBalance`, `eth_getTransactionCount` and `eth_getBlockReceipts`.
22+
- `EthGetTransactionByHashLimited`, `EthGetTransactionReceiptLimited` and `EthGetBlockReceiptsLimited` are no longer supported via the gateway, they are an unnecessary implementation detail.
23+
- All endpoints that select by block hash or number now properly return `ErrNullRound` error types via the go-jsonrpc API and present a consistent error message via raw JSONRPC.
24+
- The `"safe"` label has divergent behaviour between V1 and V2 APIs worth noting:
25+
- `/v1` APIs will interpret `"safe"` as a fixed distance of 30 epochs behind `"latest"`, this is unchanged and is based on research into the stability of the chain under normal conditions.
26+
- `/v2` APIs will interpret `"safe"` to be the same as `"finalized"` as long as F3 is enabled and properly functioning. In the case of F3 being inactive or otherwise not operational, it will be interpreted as a (*very* pessimistic) fixed distance of 200 epochs behind `"latest"`. This may be revised in a future update.
2027

2128
# Node and Miner v1.32.2 / 2025-04-04
2229

api/api_full.go

+15-31
Original file line numberDiff line numberDiff line change
@@ -837,23 +837,23 @@ type FullNode interface {
837837
// EthBlockNumber returns the height of the latest (heaviest) TipSet
838838
EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) //perm:read
839839
// EthGetBlockTransactionCountByNumber returns the number of messages in the TipSet
840-
EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) //perm:read
840+
EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum string) (ethtypes.EthUint64, error) //perm:read
841841
// EthGetBlockTransactionCountByHash returns the number of messages in the TipSet
842842
EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) //perm:read
843843

844-
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
845-
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
846-
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read
847-
EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) //perm:read
848-
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) //perm:read
849-
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) //perm:read
850-
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) //perm:read
851-
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read
852-
EthGetBlockReceipts(ctx context.Context, blkParam ethtypes.EthBlockNumberOrHash) ([]*EthTxReceipt, error) //perm:read
853-
EthGetBlockReceiptsLimited(ctx context.Context, blkParam ethtypes.EthBlockNumberOrHash, limit abi.ChainEpoch) ([]*EthTxReceipt, error) //perm:read
854-
EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*EthTxReceipt, error) //perm:read
855-
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (*ethtypes.EthTx, error) //perm:read
856-
EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum string, txIndex ethtypes.EthUint64) (*ethtypes.EthTx, error) //perm:read
844+
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
845+
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
846+
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read
847+
EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) //perm:read
848+
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) //perm:read
849+
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) //perm:read
850+
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) //perm:read
851+
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*ethtypes.EthTxReceipt, error) //perm:read
852+
EthGetBlockReceipts(ctx context.Context, blkParam ethtypes.EthBlockNumberOrHash) ([]*ethtypes.EthTxReceipt, error) //perm:read
853+
EthGetBlockReceiptsLimited(ctx context.Context, blkParam ethtypes.EthBlockNumberOrHash, limit abi.ChainEpoch) ([]*ethtypes.EthTxReceipt, error) //perm:read
854+
EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTxReceipt, error) //perm:read
855+
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (*ethtypes.EthTx, error) //perm:read
856+
EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum string, txIndex ethtypes.EthUint64) (*ethtypes.EthTx, error) //perm:read
857857

858858
EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) //perm:read
859859
EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) //perm:read
@@ -1452,20 +1452,4 @@ type HotGCOpts struct {
14521452
Moving bool
14531453
}
14541454

1455-
type EthTxReceipt struct {
1456-
TransactionHash ethtypes.EthHash `json:"transactionHash"`
1457-
TransactionIndex ethtypes.EthUint64 `json:"transactionIndex"`
1458-
BlockHash ethtypes.EthHash `json:"blockHash"`
1459-
BlockNumber ethtypes.EthUint64 `json:"blockNumber"`
1460-
From ethtypes.EthAddress `json:"from"`
1461-
To *ethtypes.EthAddress `json:"to"`
1462-
StateRoot ethtypes.EthHash `json:"root"`
1463-
Status ethtypes.EthUint64 `json:"status"`
1464-
ContractAddress *ethtypes.EthAddress `json:"contractAddress"`
1465-
CumulativeGasUsed ethtypes.EthUint64 `json:"cumulativeGasUsed"`
1466-
GasUsed ethtypes.EthUint64 `json:"gasUsed"`
1467-
EffectiveGasPrice ethtypes.EthBigInt `json:"effectiveGasPrice"`
1468-
LogsBloom ethtypes.EthBytes `json:"logsBloom"`
1469-
Logs []ethtypes.EthLog `json:"logs"`
1470-
Type ethtypes.EthUint64 `json:"type"`
1471-
}
1455+
type EthTxReceipt = ethtypes.EthTxReceipt // Deprecated: use ethtypes.EthTxReceipt instead

api/api_gateway.go

+18-14
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,11 @@ import (
3535
// * Generate openrpc blobs
3636

3737
type Gateway interface {
38-
MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error)
3938
ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error)
40-
MinerGetBaseInfo(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*MiningBaseInfo, error)
41-
StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error)
42-
GasEstimateGasPremium(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error)
43-
StateReplay(context.Context, types.TipSetKey, cid.Cid) (*InvocResult, error)
4439
ChainHasObj(context.Context, cid.Cid) (bool, error)
4540
ChainPutObj(context.Context, blocks.Block) error
4641
ChainHead(ctx context.Context) (*types.TipSet, error)
42+
ChainGetEvents(context.Context, cid.Cid) ([]types.Event, error)
4743
ChainGetParentMessages(context.Context, cid.Cid) ([]Message, error)
4844
ChainGetParentReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error)
4945
ChainGetMessagesInTipset(context.Context, types.TipSetKey) ([]Message, error)
@@ -56,15 +52,22 @@ type Gateway interface {
5652
ChainNotify(context.Context) (<-chan []*HeadChange, error)
5753
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
5854
ChainGetGenesis(context.Context) (*types.TipSet, error)
55+
56+
GasEstimateGasPremium(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error)
5957
GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
58+
6059
MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error)
60+
MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error)
6161
MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
62+
6263
MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error)
6364
MsigGetPending(context.Context, address.Address, types.TipSetKey) ([]*MsigTransaction, error)
6465
MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
6566
MsigGetVestingSchedule(ctx context.Context, addr address.Address, tsk types.TipSetKey) (MsigVesting, error)
67+
6668
StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
6769
StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*InvocResult, error)
70+
StateReplay(context.Context, types.TipSetKey, cid.Cid) (*InvocResult, error)
6871
StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (DealCollateralBounds, error)
6972
StateDecodeParams(ctx context.Context, toAddr address.Address, method abi.MethodNum, params []byte, tsk types.TipSetKey) (interface{}, error)
7073
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
@@ -83,34 +86,33 @@ type Gateway interface {
8386
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) ([]Deadline, error)
8487
StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error)
8588
StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error)
89+
StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error)
8690
StateNetworkName(context.Context) (dtypes.NetworkName, error)
8791
StateNetworkVersion(context.Context, types.TipSetKey) (apitypes.NetworkVersion, error)
8892
StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error)
8993
StateVerifierStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error)
9094
StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error)
9195
StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*MsgLookup, error)
9296
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64, limit abi.ChainEpoch, allowReplaced bool) (*MsgLookup, error)
97+
98+
MinerGetBaseInfo(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*MiningBaseInfo, error)
99+
93100
WalletBalance(context.Context, address.Address) (types.BigInt, error)
94-
Version(context.Context) (APIVersion, error)
95-
Discover(context.Context) (apitypes.OpenRPCDocument, error)
96101

97102
EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error)
98103
FilecoinAddressToEthAddress(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthAddress, error)
99104
EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error)
100105
EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error)
101-
EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error)
106+
EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum string) (ethtypes.EthUint64, error)
102107
EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error)
103108
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error)
104109
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error)
105110
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error)
106-
EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error)
107111
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error)
108112
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error)
109113
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error)
110-
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error)
111-
EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*EthTxReceipt, error)
112-
EthGetBlockReceipts(ctx context.Context, blkParam ethtypes.EthBlockNumberOrHash) ([]*EthTxReceipt, error)
113-
EthGetBlockReceiptsLimited(ctx context.Context, blkParam ethtypes.EthBlockNumberOrHash, limit abi.ChainEpoch) ([]*EthTxReceipt, error)
114+
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*ethtypes.EthTxReceipt, error)
115+
EthGetBlockReceipts(ctx context.Context, blkParam ethtypes.EthBlockNumberOrHash) ([]*ethtypes.EthTxReceipt, error)
114116
EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error)
115117
EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error)
116118
EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error)
@@ -143,8 +145,10 @@ type Gateway interface {
143145
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, index ethtypes.EthUint64) (*ethtypes.EthTx, error)
144146
GetActorEventsRaw(ctx context.Context, filter *types.ActorEventFilter) ([]*types.ActorEvent, error)
145147
SubscribeActorEventsRaw(ctx context.Context, filter *types.ActorEventFilter) (<-chan *types.ActorEvent, error)
146-
ChainGetEvents(context.Context, cid.Cid) ([]types.Event, error)
147148

148149
F3GetCertificate(ctx context.Context, instance uint64) (*certs.FinalityCertificate, error)
149150
F3GetLatestCertificate(ctx context.Context) (*certs.FinalityCertificate, error)
151+
152+
Version(context.Context) (APIVersion, error)
153+
Discover(context.Context) (apitypes.OpenRPCDocument, error)
150154
}

api/client/client.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/filecoin-project/lotus/api"
1313
"github.com/filecoin-project/lotus/api/v0api"
1414
"github.com/filecoin-project/lotus/api/v1api"
15+
"github.com/filecoin-project/lotus/api/v2api"
1516
"github.com/filecoin-project/lotus/lib/rpcenc"
1617
)
1718

@@ -24,7 +25,7 @@ func NewCommonRPCV0(ctx context.Context, addr string, requestHeader http.Header)
2425
return &res, closer, err
2526
}
2627

27-
// NewFullNodeRPCV0 creates a new http jsonrpc client.
28+
// NewFullNodeRPCV0 creates a new http jsonrpc client for the /v0 API.
2829
func NewFullNodeRPCV0(ctx context.Context, addr string, requestHeader http.Header) (v0api.FullNode, jsonrpc.ClientCloser, error) {
2930
var res v0api.FullNodeStruct
3031

@@ -34,7 +35,7 @@ func NewFullNodeRPCV0(ctx context.Context, addr string, requestHeader http.Heade
3435
return &res, closer, err
3536
}
3637

37-
// NewFullNodeRPCV1 creates a new http jsonrpc client.
38+
// NewFullNodeRPCV1 creates a new http jsonrpc client for the /v1 API.
3839
func NewFullNodeRPCV1(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (api.FullNode, jsonrpc.ClientCloser, error) {
3940
var res v1api.FullNodeStruct
4041
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
@@ -43,6 +44,15 @@ func NewFullNodeRPCV1(ctx context.Context, addr string, requestHeader http.Heade
4344
return &res, closer, err
4445
}
4546

47+
// NewFullNodeRPCV2 creates a new http jsonrpc client for the /v2 API.
48+
func NewFullNodeRPCV2(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (v2api.FullNode, jsonrpc.ClientCloser, error) {
49+
var res v2api.FullNodeStruct
50+
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
51+
api.GetInternalStructs(&res), requestHeader, append([]jsonrpc.Option{jsonrpc.WithErrors(api.RPCErrors)}, opts...)...)
52+
53+
return &res, closer, err
54+
}
55+
4656
func getPushUrl(addr string) (string, error) {
4757
pushUrl, err := url.Parse(addr)
4858
if err != nil {

0 commit comments

Comments
 (0)