Skip to content

Commit 1e53dd4

Browse files
committed
fixup! feat(eth)!: add Eth APIs to /v2 + minor improvements & fixes
1 parent 5ef2fe8 commit 1e53dd4

15 files changed

+281
-129
lines changed

CHANGELOG.md

+16-12
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,22 @@
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**:<br>
15-
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 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)), ([filecoin-project/lotus#13034](https://github.com/filecoin-project/lotus/pull/13034))
16-
- feat: add **Ethereum APIs to v2 with F3 awareness** and minor improvements to v1 Ethereum APIs:<br>
17-
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>
18-
Additional changes to the Ethereum APIs (both V1 and V2) introduced in this release include:
19-
- `eth_getBlockTransactionCountByNumber` now takes the standard Ethereum block number specifier: hex encoded integers _or_ labels including `"latest"`, `"safe"` and `"finalized"`.
20-
- 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`.
21-
- `EthGetTransactionByHashLimited`, `EthGetTransactionReceiptLimited` and `EthGetBlockReceiptsLimited` are no longer supported via the gateway, they are an unnecessary implementation detail.
22-
- 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.
23-
- The `"safe"` label has divergent behaviour between V1 and V2 APIs worth noting:
24-
- `/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.
25-
- `/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.
14+
- feat: Add **Lotus v2 experimental APIs with F3 awareness** ([filecoin-project/lotus#13003](https://github.com/filecoin-project/lotus/pull/13003)), ([filecoin-project/lotus#13027](https://github.com/filecoin-project/lotus/pull/13027)), ([filecoin-project/lotus#13034](https://github.com/filecoin-project/lotus/pull/13034))<br>
15+
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 in-depth overview.
16+
- feat: Introduce F3-aware Ethereum APIs via `/v2` endpoint and improve existing `/v1` APIs ([filecoin-project/lotus#13026](https://github.com/filecoin-project/lotus/pull/13026))<br>
17+
Lotus now offers two versions of its Ethereum-compatible APIs (`eth_`, `trace_`, etc.) with different finality handling to make use of the upcoming F3 activation:
18+
* **`/v2` APIs (New & Recommended):** These APIs fully leverage F3 finality, significantly reducing confirmation times compared to the previous fixed delays.
19+
* `"finalized"` tag maps directly to the F3 finalized epoch (much closer to the chain head).
20+
* `"safe"` tag maps to the F3 finalized epoch or 200 epochs behind head, whichever is more recent.
21+
* **`/v1` APIs (Existing):** These maintain behavior closer to pre-F3 Lotus for compatibility.
22+
* `"finalized"` tag continues to use a fixed 900-epoch delay from the head.
23+
* `"safe"` tag uses a 30-epoch delay *or* the F3 finalized epoch (whichever is more recent). *After* F3 is fully active on the network, the behavior of `"safe"` on `/v1` will align with `/v2`'s `"safe"`.
24+
* **Note:** Previously, `"finalized"` and `"safe"` tags referred to epochs `N-1`. This `-1` offset has been removed in both V1 and V2.
25+
* Additional improvements affecting **both `/v1` and `/v2`** Ethereum APIs:
26+
* `eth_getBlockTransactionCountByNumber` now accepts standard Ethereum block specifiers (hex numbers _or_ labels like `"latest"`, `"safe"`, `"finalized"`).
27+
* Methods accepting `BlockNumberOrHash` now support all standard labels (`"pending"`, `"latest"`, `"safe"`, `"finalized"`). This includes `eth_estimateGas`, `eth_call`, `eth_getCode`, `eth_getStorageAt`, `eth_getBalance`, `eth_getTransactionCount`, and `eth_getBlockReceipts`.
28+
* Removed internal `Eth*Limited` methods (e.g., `EthGetTransactionByHashLimited`) from the supported gateway API surface.
29+
* Improved error handling: block selection endpoints now consistently return `ErrNullRound` (and corresponding JSONRPC errors) for null tipsets.
2630

2731
# Node and Miner v1.32.2 / 2025-04-04
2832

chain/types/ethtypes/eth_types.go

+23-2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ var ErrInvalidAddress = errors.New("invalid Filecoin Eth address")
4545
// See https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0089.md
4646
const SafeEpochDelay = abi.ChainEpoch(30)
4747

48+
const (
49+
BlockTagEarliest = "earliest"
50+
BlockTagPending = "pending"
51+
BlockTagLatest = "latest"
52+
BlockTagFinalized = "finalized"
53+
BlockTagSafe = "safe"
54+
)
55+
4856
type EthUint64 uint64
4957

5058
func (e EthUint64) MarshalJSON() ([]byte, error) {
@@ -61,8 +69,9 @@ func (e *EthUint64) UnmarshalJSON(b []byte) error {
6169
base := 10
6270
if strings.HasPrefix(s, "0x") {
6371
base = 16
72+
s = s[2:]
6473
}
65-
parsedInt, err := strconv.ParseUint(strings.Replace(s, "0x", "", -1), base, 64)
74+
parsedInt, err := strconv.ParseUint(s, base, 64)
6675
if err != nil {
6776
return err
6877
}
@@ -84,6 +93,16 @@ func EthUint64FromHex(s string) (EthUint64, error) {
8493
return EthUint64(parsedInt), nil
8594
}
8695

96+
// EthUint64FromString parses a uint64 from a string. It accepts both decimal and hex strings.
97+
func EthUint64FromString(s string) (EthUint64, error) {
98+
var parsedInt EthUint64
99+
err := parsedInt.UnmarshalJSON([]byte(`"` + s + `"`))
100+
if err != nil {
101+
return 0, err
102+
}
103+
return parsedInt, nil
104+
}
105+
87106
// EthUint64FromBytes parses a uint64 from big-endian encoded bytes.
88107
func EthUint64FromBytes(b []byte) (EthUint64, error) {
89108
if len(b) != 32 {
@@ -1101,7 +1120,9 @@ func (e *EthBlockNumberOrHash) UnmarshalJSON(b []byte) error {
11011120
if err != nil {
11021121
return err
11031122
}
1104-
if str == "earliest" || str == "pending" || str == "latest" || str == "finalized" || str == "safe" {
1123+
1124+
switch str {
1125+
case BlockTagEarliest, BlockTagPending, BlockTagLatest, BlockTagFinalized, BlockTagSafe:
11051126
e.PredefinedBlock = &str
11061127
return nil
11071128
}

chain/types/ethtypes/eth_types_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ func TestEthIntUnmarshalJSON(t *testing.T) {
5252
err := i.UnmarshalJSON(tc.Input.([]byte))
5353
require.Nil(t, err)
5454
require.Equal(t, tc.Output, i)
55+
56+
i, err = EthUint64FromString(strings.Replace(string(tc.Input.([]byte)), `"`, "", -1))
57+
require.Nil(t, err)
58+
require.Equal(t, tc.Output, i)
5559
}
5660
}
5761

itests/api_v2_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
125125
name: "finalized tag is ok",
126126
when: func(t *testing.T) {
127127
mockF3.Running = true
128+
mockF3.Finalizing = true
128129
mockF3.LatestCertErr = nil
129130
mockF3.LatestCert = plausibleCertAt(t, f3FinalizedEpoch)
130131
},
@@ -136,6 +137,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
136137
name: "safe tag is ec safe distance when more recent than f3 finalized",
137138
when: func(t *testing.T) {
138139
mockF3.Running = true
140+
mockF3.Finalizing = true
139141
mockF3.LatestCertErr = nil
140142
mockF3.LatestCert = plausibleCertAt(t, f3FinalizedEpoch)
141143
},
@@ -147,6 +149,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
147149
name: "safe tag is f3 finalized when ec minus safe distance is too old",
148150
when: func(t *testing.T) {
149151
mockF3.Running = true
152+
mockF3.Finalizing = true
150153
mockF3.LatestCertErr = nil
151154
mockF3.LatestCert = plausibleCertAt(t, 890)
152155
},
@@ -158,6 +161,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
158161
name: "finalized tag when f3 not ready falls back to ec",
159162
when: func(t *testing.T) {
160163
mockF3.Running = true
164+
mockF3.Finalizing = true
161165
mockF3.LatestCert = nil
162166
mockF3.LatestCertErr = api.ErrF3NotReady
163167
},
@@ -169,6 +173,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
169173
name: "finalized tag when f3 fails is error",
170174
when: func(t *testing.T) {
171175
mockF3.Running = true
176+
mockF3.Finalizing = true
172177
mockF3.LatestCert = nil
173178
mockF3.LatestCertErr = internalF3Error
174179
},
@@ -180,6 +185,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
180185
name: "latest tag when f3 fails is ok",
181186
when: func(t *testing.T) {
182187
mockF3.Running = true
188+
mockF3.Finalizing = true
183189
mockF3.LatestCert = nil
184190
mockF3.LatestCertErr = internalF3Error
185191
},
@@ -191,6 +197,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
191197
name: "finalized tag when f3 is broken",
192198
when: func(t *testing.T) {
193199
mockF3.Running = true
200+
mockF3.Finalizing = true
194201
mockF3.LatestCert = implausibleCert
195202
mockF3.LatestCertErr = nil
196203
},
@@ -222,6 +229,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
222229
name: "height with no anchor before finalized epoch is ok",
223230
when: func(t *testing.T) {
224231
mockF3.Running = true
232+
mockF3.Finalizing = true
225233
mockF3.LatestCert = plausibleCertAt(t, f3FinalizedEpoch)
226234
mockF3.LatestCertErr = nil
227235
},
@@ -233,6 +241,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
233241
name: "height with no anchor after finalized epoch is error",
234242
when: func(t *testing.T) {
235243
mockF3.Running = true
244+
mockF3.Finalizing = true
236245
mockF3.LatestCert = plausibleCertAt(t, f3FinalizedEpoch)
237246
mockF3.LatestCertErr = nil
238247
},
@@ -244,6 +253,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
244253
name: "height with no anchor when f3 fails is error",
245254
when: func(t *testing.T) {
246255
mockF3.Running = true
256+
mockF3.Finalizing = true
247257
mockF3.LatestCert = nil
248258
mockF3.LatestCertErr = internalF3Error
249259
},
@@ -255,6 +265,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
255265
name: "height with no anchor and nil f3 cert falling back to ec fails",
256266
when: func(t *testing.T) {
257267
mockF3.Running = true
268+
mockF3.Finalizing = true
258269
mockF3.LatestCert = nil
259270
mockF3.LatestCertErr = nil
260271
},
@@ -266,6 +277,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
266277
name: "height with anchor to latest",
267278
when: func(t *testing.T) {
268279
mockF3.Running = true
280+
mockF3.Finalizing = true
269281
mockF3.LatestCert = plausibleCertAt(t, f3FinalizedEpoch)
270282
mockF3.LatestCertErr = nil
271283
},
@@ -340,6 +352,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
340352
name: "finalized tag is ok",
341353
when: func(t *testing.T) {
342354
mockF3.Running = true
355+
mockF3.Finalizing = true
343356
mockF3.LatestCertErr = nil
344357
mockF3.LatestCert = plausibleCertAt(t, f3FinalizedEpoch)
345358
},
@@ -351,6 +364,7 @@ func TestAPIV2_ThroughRPC(t *testing.T) {
351364
name: "height with anchor to latest",
352365
when: func(t *testing.T) {
353366
mockF3.Running = true
367+
mockF3.Finalizing = true
354368
mockF3.LatestCert = plausibleCertAt(t, f3FinalizedEpoch)
355369
mockF3.LatestCertErr = nil
356370
},

0 commit comments

Comments
 (0)