Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/schemas/block.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,28 @@ BlockNumberOrTagOrHash:
$ref: '#/components/schemas/BlockTag'
- title: Block hash
$ref: '#/components/schemas/hash32'
- title: EIP-1898 block number object

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this have to be a separate object? ideally it would be an optional value on "Block Number" and "Block hash" object?

@MysticRyuujin MysticRyuujin Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate on this question?

The options are basically:

"0x1234" - a Block Number
"0x..." - a Block Hash

or and object {} that object can be one of:

{"blockNumber":"0x1234"...}
{"blockHash":"0x...","requireCanonical":true|false,...}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lightclient can you comment or elaborate so we can close this one out?

type: object
additionalProperties: false
required:
- blockNumber
properties:
blockNumber:
title: Block number
$ref: '#/components/schemas/uint'
- title: EIP-1898 block hash object
type: object
additionalProperties: false
required:
- blockHash
properties:
blockHash:
title: Block hash
$ref: '#/components/schemas/hash32'
requireCanonical:
title: Require canonical
description: 'Whether the block hash must belong to a canonical block, defaulting to `false`. When `true` and the referenced block is not canonical, EIP-1898 recommends `-32000: Invalid input`. A block that cannot be found takes precedence and is reported as `-32001: Resource not found`.'
type: boolean
BadBlock:
title: Bad block
type: object
Expand Down
5 changes: 5 additions & 0 deletions tests/eth_call/call-block-hash-object.io
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Performs a call at a block hash given as an EIP-1898 object.
// Calls the callenv contract, whose echoed block number makes the result differ per
// block, so a client that ignored the block parameter would not match.
>> {"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":"0x9344b07175800259691961298ca11c824e65032d"},{"blockHash":"0xa38f2a6f7d276298d8e7a9bfa28625e4dc8948021f5a7369d0a04571879e98d2"}]}
<< {"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000c72dd9d5e883e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// retrieves an account balance at a canonical block hash with requireCanonical set
>> {"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["0x7dcd17433742f4c0ca53122ab541d0ba67fc27df",{"blockHash":"0xa38f2a6f7d276298d8e7a9bfa28625e4dc8948021f5a7369d0a04571879e98d2","requireCanonical":true}]}
<< {"jsonrpc":"2.0","id":1,"result":"0x56"}
3 changes: 3 additions & 0 deletions tests/eth_getBalance/get-balance-block-hash-object.io
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// retrieves an account balance at a block hash given as an EIP-1898 object
>> {"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["0x7dcd17433742f4c0ca53122ab541d0ba67fc27df",{"blockHash":"0xa38f2a6f7d276298d8e7a9bfa28625e4dc8948021f5a7369d0a04571879e98d2"}]}
<< {"jsonrpc":"2.0","id":1,"result":"0x56"}
3 changes: 3 additions & 0 deletions tests/eth_getBalance/get-balance-block-number-object.io
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// retrieves an account balance at a block number given as an EIP-1898 object
>> {"jsonrpc":"2.0","id":1,"method":"eth_getBalance","params":["0x7dcd17433742f4c0ca53122ab541d0ba67fc27df",{"blockNumber":"0x2c"}]}
<< {"jsonrpc":"2.0","id":1,"result":"0x56"}
6 changes: 6 additions & 0 deletions tests/eth_getProof/get-account-proof-block-hash-object.io
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Gets proof at a block hash given as an EIP-1898 object.
// Targets the head block rather than a historical one: this case covers the object
// form in the third parameter position, and clients legitimately bound how far back
// they serve proofs.
>> {"jsonrpc":"2.0","id":1,"method":"eth_getProof","params":["0x7dcd17433742f4c0ca53122ab541d0ba67fc27df",[],{"blockHash":"0xd226371d0b1551adb03fb52b71f08e3e11247fe9b1af994768af8cdaa8e7dcd7"}]}
<< {"jsonrpc":"2.0","id":1,"result":{"address":"0x7dcd17433742f4c0ca53122ab541d0ba67fc27df","accountProof":["0xf90211a03e7affd7171fd5da97f3c822aedb5a54883069214df918f0f8c19a3477835340a096ab2c852d4cf3883217a55ccc80525d4191990eec2a7e6c069d4402929b3a9ea0ec5d4f6a260e3066f809708adc8bb079b2a51f72d698cc5d59707a02260b22a4a0ea8a8eba999e8888fd9e04176c371fe261cf901831c42abf7782271b9aa149a5a04ea9cc0c744d4b9efb81b1b8244e120fac0fcae34815b454b4f5ae3ade317ddea0a4e18a1f895dcd084e0c9747152e63be09b0b13b75e04cc93f280f2731cbb4c9a0524c77b37063f3ea1614debae488bf0537a3870fe184feab728a92fd2762388da02a201e0a5a7baedcabc648b937bbaf714c9d8c8a5a5161a79f65546b77f2624da009b3f8bf6205057d39697ed8349764e5b752b2c489dfef617bc402689e7168fba07f2d0ced929198203a9e9538b59e9b4f812b53857ca8ebf615e7eb1f24a18d05a08252dd59527bb707c561bdc1e2e05b8a4781226f01dc96b64c61f84f68211904a055731299838a729727b2724d74b8bc1d62ed1d529303103a061096d99a6e18f0a0f76e4f5959b1ba750b2e790069ba7b9bb4d6877edce199fa0b3f51e41c81ff4ca06c59b04cf791ef6b43d8ec4a423368f9eea6606592e1ba8d1b92ccbc547fafc1a0ffce7fd1f8bfb6316ec4f22ec71e15b10ed816166203bd6f555b3569cf6397f0a04d6ca92bb6fece12d77e5638272515099bde6149f50adaf388eca40abe70243e80","0xf89180a02a2f71808bd7e7f11066619d43d6568a312e3de9666dd037b160a0fab523499080a0591c1f461f4c61296b7600d08e4594131e039114babe6464cd8b6702abc975d480808080808080a003519723dae2cc55588428c710ee5421f4c1e38e52e53deb94c7649f08d00bc7808080a0d3fbc6ec6915f0be27282666096502f621817e90fece0de4ddb015e2a83559e680","0xf869a0201f52c702c40589735c4b038bd94e04268a58c35afad63bb16c071d62d2e23db846f8448076a07917ac1f1d6cd87c54aea239c6efbe5c8865659f0761c74e67f1c1eb837923bba0a3216dd3ef46a63d518ef54e482cecac68a077f70fca0e5fb900be63f41d54a2"],"balance":"0x76","codeHash":"0xa3216dd3ef46a63d518ef54e482cecac68a077f70fca0e5fb900be63f41d54a2","nonce":"0x0","storageHash":"0x7917ac1f1d6cd87c54aea239c6efbe5c8865659f0761c74e67f1c1eb837923bb","storageProof":[]}}
89 changes: 89 additions & 0 deletions tools/testgen/generators.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,54 @@ var EthGetBalance = MethodTests{
return nil
},
},
{
Name: "get-balance-block-number-object",
About: "retrieves an account balance at a block number given as an EIP-1898 object",
Run: func(ctx context.Context, t *T) error {
block := t.chain.GetBlock(int(t.chain.Head().NumberU64()) - 10)
var got hexutil.Big
ref := map[string]any{"blockNumber": hexutil.Uint64(block.NumberU64())}
if err := t.rpc.CallContext(ctx, &got, "eth_getBalance", emitContract, ref); err != nil {
return err
}
if got.ToInt().Sign() <= 0 {
return errors.New("invalid historical balance, should be > zero")
}
return nil
},
},
{
Name: "get-balance-block-hash-object",
About: "retrieves an account balance at a block hash given as an EIP-1898 object",
Run: func(ctx context.Context, t *T) error {
block := t.chain.GetBlock(int(t.chain.Head().NumberU64()) - 10)
var got hexutil.Big
ref := map[string]any{"blockHash": block.Hash()}
if err := t.rpc.CallContext(ctx, &got, "eth_getBalance", emitContract, ref); err != nil {
return err
}
if got.ToInt().Sign() <= 0 {
return errors.New("invalid historical balance, should be > zero")
}
return nil
},
},
{
Name: "get-balance-block-hash-object-require-canonical",
About: "retrieves an account balance at a canonical block hash with requireCanonical set",
Run: func(ctx context.Context, t *T) error {
block := t.chain.GetBlock(int(t.chain.Head().NumberU64()) - 10)
var got hexutil.Big
ref := map[string]any{"blockHash": block.Hash(), "requireCanonical": true}
if err := t.rpc.CallContext(ctx, &got, "eth_getBalance", emitContract, ref); err != nil {
return err
}
if got.ToInt().Sign() <= 0 {
return errors.New("invalid historical balance, should be > zero")
}
return nil
},
},
{
Name: "get-balance-default-block",
About: "retrieves an account balance with the block parameter omitted, which defaults to latest",
Expand Down Expand Up @@ -738,6 +786,25 @@ var EthCall = MethodTests{
return nil
},
},
{
Name: "call-block-hash-object",
About: `Performs a call at a block hash given as an EIP-1898 object.
Calls the callenv contract, whose echoed block number makes the result differ per
block, so a client that ignored the block parameter would not match.`,
Run: func(ctx context.Context, t *T) error {
block := t.chain.GetBlock(int(t.chain.Head().NumberU64()) - 10)
msg := map[string]any{"to": t.chain.txinfo.CallEnvContract.Addr}
var result hexutil.Bytes
ref := map[string]any{"blockHash": block.Hash()}
if err := t.rpc.CallContext(ctx, &result, "eth_call", msg, ref); err != nil {
return err
}
if len(result) == 0 {
return fmt.Errorf("empty call result")
}
return nil
},
},
{
Name: "call-callenv",
About: `Performs a call to the callenv contract, which echoes the EVM transaction environment.
Expand Down Expand Up @@ -2152,6 +2219,28 @@ var EthGetProof = MethodTests{
return nil
},
},
{
Name: "get-account-proof-block-hash-object",
About: `Gets proof at a block hash given as an EIP-1898 object.
Targets the head block rather than a historical one: this case covers the object
form in the third parameter position, and clients legitimately bound how far back
they serve proofs.`,
Run: func(ctx context.Context, t *T) error {
type accountResult struct {
Balance *hexutil.Big `json:"balance"`
}
var result accountResult
ref := map[string]any{"blockHash": t.chain.Head().Hash()}
if err := t.rpc.CallContext(ctx, &result, "eth_getProof", emitContract, []string{}, ref); err != nil {
return err
}
balance := t.chain.Balance(emitContract)
if result.Balance.ToInt().Cmp(balance) != 0 {
return fmt.Errorf("unexpected balance (got: %s, want: %s)", result.Balance, balance)
}
return nil
},
},
{
Name: "get-account-proof-with-storage",
About: "gets proof for a certain account",
Expand Down
Loading