Skip to content

Commit 883ff23

Browse files
Stebalienraulk
andcommitted
fix: Eth API: accept input data in call arguments under field 'input'
The correct name for this field is 'input' according to the Ethereum specs [0]. However, for the longest time, clients have been using 'data' and servers have been lenient to accept both, preferring 'input' over 'data' when both appear. Our lack of support for 'input' had gone unnoticed until go-ethereum decided to adjust their ethclient implementation to issue eth_call and eth_estimateGas requests with the 'input' field instead of 'data' [1]. This suddenly broke apps using this client against Lotus' Eth API. [0]: https://github.com/ethereum/execution-apis/blob/main/src/schemas/transaction.yaml#L33-L35 [1]: ethereum/go-ethereum#28078 Co-authored-by: raulk <raul.kripalani@gmail.com>
1 parent cf8fed9 commit 883ff23

File tree

2 files changed

+45
-4
lines changed

2 files changed

+45
-4
lines changed

chain/types/ethtypes/eth_types.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,13 +229,25 @@ type EthCall struct {
229229
}
230230

231231
func (c *EthCall) UnmarshalJSON(b []byte) error {
232-
type TempEthCall EthCall
233-
var params TempEthCall
232+
type EthCallRaw EthCall // Avoid a recursive call.
233+
type EthCallDecode struct {
234+
// The field should be "input" by spec, but many clients use "data" so we support
235+
// both, but prefer "input".
236+
Input *EthBytes `json:"input"`
237+
EthCallRaw
238+
}
234239

240+
var params EthCallDecode
235241
if err := json.Unmarshal(b, &params); err != nil {
236242
return err
237243
}
238-
*c = EthCall(params)
244+
245+
// If input is specified, prefer it.
246+
if params.Input != nil {
247+
params.Data = *params.Input
248+
}
249+
250+
*c = EthCall(params.EthCallRaw)
239251
return nil
240252
}
241253

chain/types/ethtypes/eth_types_test.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,40 @@ func TestMaskedIDInF4(t *testing.T) {
194194
}
195195

196196
func TestUnmarshalEthCall(t *testing.T) {
197-
data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","data":""}`
197+
data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","data":"0xFF"}`
198198

199199
var c EthCall
200200
err := c.UnmarshalJSON([]byte(data))
201201
require.Nil(t, err)
202+
require.EqualValues(t, []byte{0xff}, c.Data)
203+
}
204+
205+
func TestUnmarshalEthCallInput(t *testing.T) {
206+
data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","input":"0xFF"}`
207+
208+
var c EthCall
209+
err := c.UnmarshalJSON([]byte(data))
210+
require.Nil(t, err)
211+
require.EqualValues(t, []byte{0xff}, c.Data)
212+
}
213+
214+
func TestUnmarshalEthCallInputAndData(t *testing.T) {
215+
data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","data":"0xFE","input":"0xFF"}`
216+
217+
var c EthCall
218+
err := c.UnmarshalJSON([]byte(data))
219+
require.Nil(t, err)
220+
require.EqualValues(t, []byte{0xff}, c.Data)
221+
}
222+
223+
func TestUnmarshalEthCallInputAndDataEmpty(t *testing.T) {
224+
// Even if the input is empty, it should be used when specified.
225+
data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","data":"0xFE","input":""}`
226+
227+
var c EthCall
228+
err := c.UnmarshalJSON([]byte(data))
229+
require.Nil(t, err)
230+
require.EqualValues(t, []byte{}, c.Data)
202231
}
203232

204233
func TestUnmarshalEthBytes(t *testing.T) {

0 commit comments

Comments
 (0)