-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add EIP-1898 support needed for The Graph compatibility #10815
Conversation
32c4244
to
8a64b50
Compare
9e18cbf
to
c9a6734
Compare
@@ -479,6 +479,9 @@ func ExampleValue(method string, t, parent reflect.Type) interface{} { | |||
es := exampleStruct(method, t.Elem(), t) | |||
ExampleValues[t] = es | |||
return es | |||
} else if t.Elem().Kind() == reflect.String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably be a switch statement now.
chain/types/ethtypes/eth_types.go
Outdated
PredefinedBlock *string | ||
Number *EthUint64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Why do we have two block number fields?
- These should both be ignored by json (
`json:"-"`
). Or private.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Stebalien I looked better into merging the Number
/BlockNumber
into one and I think it may not be such a great idea.
For context, the issue is that currently the blkParam
can be one of "latest", "earliest", "pending", or a block number (decimal or hex) but with this PR we additionally need to support that blkParam
to be able to be a json hash witch a certain named fields (blockNumber,blockHash,requireCanonical). To implement this, I introduced this EthBlockParamByNumberOrHash
struct which has fields for both cases (normal as before + support for json hashes) and handles the al the construction/json deserialization.
It would be possible to merge the Number
and BlockNumber
in EthBlockParamByNumberOrHash
into one, but I would think that makes the code less readable since right now its easy to see from reading the code whether we are talking about a normal block number or a one we need to support for the EIP-1891. Also, it would make error handling cumbersome (like here).
chain/types/ethtypes/eth_types.go
Outdated
@@ -815,3 +815,82 @@ func (e EthFeeHistoryParams) MarshalJSON() ([]byte, error) { | |||
} | |||
return json.Marshal([]interface{}{e.BlkCount, e.NewestBlkNum}) | |||
} | |||
|
|||
type EthBlockParamByNumberOrHash struct { | |||
PredefinedBlock *string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd consider using negative constants to represent "latest", etc. Storing them in the BlockNumber
field. I.e., we'd have three fields only:
const (
EthBlockLatest EthUint64 = -iota
EthBlockPending
EthBlockEarliest
// ...
)
type EthBlockParam struct {
BlockNumber *EthUint64
BlockHash *EthHash
RequireCanonical bool
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Stebalien I do recall considering that but EthUint64 is an unsigned type, do you think this would warrant a new type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would love feedback from @filecoin-project/lotus-maintainers team on Stebs comment here.
Fixes: #10814 This PR updates the following RPC methods according to EIP-1898 specs. The following RPC methods are affected: - eth_getBalance - eth_getStorageAt - eth_getTransactionCount - eth_getCode - eth_call Note that eth_getBlockByNumber was not included in this list in the spec although it seems it should be affected also? Currently these methods all accept a blkParam string which can be one of "latest", "earliest", "pending", or a block number (decimal or hex). The spec enables caller to additionally specify a json hash which can include the following fields: - blockNumber EthUint64: A block number (decimal or hex) which is similar to the original use of the blkParam string - blockHash EthHash: The block hash - requireCanonical bool) If true we should make sure the block is in the canonical chain Since the blkParam needs to support both being a number/string and a json hash then this to properly work we need to introduce a new struct with pointer fields to check if they exist. This is done in the EthBlockParamByNumberOrHash struct which first tries to unmarshal as a json hash (according to eip-1898) and then fallback to unmarshal as string/number.
c852491
to
f358160
Compare
189e09e
to
eed38a3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two small changes but otherwise lgtm.
chain/types/ethtypes/eth_types.go
Outdated
@@ -839,3 +839,80 @@ func (e EthFeeHistoryParams) MarshalJSON() ([]byte, error) { | |||
} | |||
return json.Marshal([]interface{}{e.BlkCount, e.NewestBlkNum}) | |||
} | |||
|
|||
type EthBlockNumberOrHash struct { | |||
PredefinedBlock *string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field shouldn't be serialized to json.
node/impl/full/eth.go
Outdated
// walk back the current chain (our head) until we reach targetHeight and validate the block hash | ||
currTs := head | ||
for { | ||
if currTs.Equals(ts) { | ||
return ts, nil | ||
} else if currTs.Height() < ts.Height() { | ||
return nil, fmt.Errorf("could not find block hash %s in canonical chain", blkParam.BlockHash.ToCid()) | ||
} | ||
|
||
currTs, err = a.Chain.LoadTipSet(ctx, currTs.Parents()) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to load tipset: %v", err) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call ChainGetTipSetByHeight
and let that walk for you. That'll use the index/skip-list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then, when you have the tipset at the target height:
- Make sure it's actually at the target height (nulls, etc.). Just in case.
- Make sure it equals the expected tipset.
f6136e0
to
07ac21c
Compare
|
||
predefined := blkParam.PredefinedBlock | ||
if predefined != nil { | ||
if *predefined == "earliest" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be a switch, but it's not critical.
Looks like the final issue is the linter not being happy about some error formatting. |
07ac21c
to
862f623
Compare
I need to look better into it tomorrow, but I think its because of the change of ignoring |
Well, the linter is mad about an |
df2037e
to
b7d7d4a
Compare
@Stebalien There were several failed tests that were due to the itest/testkit creating a client and setting the To address this we can either:
I updated the PR with 1) in mind, but let me know if you would prefer other options |
I believe the correct thing to do is to marshal it into the |
Well, it's unclear. That's what go-ethereum would do, but it's probably not correct. IMO, the "most correct" thing to do would be to implement
|
My concern with the current approach is that we're now exposing |
That should work, just create a tmp struct like in Unmarshal, let me do that! |
b7d7d4a
to
dda2d7e
Compare
Fixes: #10814
See also: https://github.com/filecoin-project/fvm-pm/issues/389
This PR updates the following RPC methods according to EIP-1898 specs.
The following RPC methods are affected:
eth_getBalance
eth_getStorageAt
eth_getTransactionCount
eth_getCode
eth_call
Note that
eth_getBlockByNumber
was not included in this list in the spec although it seems it should be affected also?Currently these methods all accept a
blkParam
string which can be one of "latest", "earliest", "pending", or a block number (decimal or hex). The spec enables caller to additionally specify a json hash which can include the following fields:blockNumber EthUint64
: A block number (decimal or hex) which is similar to the original use of theblkParam
stringblockHash EthHash
: The block hashrequireCanonical bool
) If true we should make sure the block is in the canonical chainSince the
blkParam
needs to support both being a number/string and a json hash then this to properly work we need to introduce a new struct with pointer fields to check if they exist. This is done in theEthBlockParamByNumberOrHash
struct which first tries to unmarshal as a json hash (according to eip-1898) and then fallback to unmarshal as string/number.Test plan
Check that specifying by predefined blocks works:
Check that specifying by number works:
Check that specifying by blockNumber works:
Check that specifying by blockHash works:
Check that specifying by blockHash works and when requireCanonical is set:
Check that specifying both blockNumber and blochHash should fail:
Check specifying by blockHash with requireCanonical is set where blockHash is not in the canonical chain: