Add EIP-1898 support needed for The Graph compatibility
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.
This commit is contained in:
@@ -62,7 +62,7 @@ func (e *EthModuleDummy) EthGetTransactionByHashLimited(ctx context.Context, txH
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) {
|
||||
func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrModuleDisabled
|
||||
}
|
||||
|
||||
@@ -82,15 +82,15 @@ func (e *EthModuleDummy) EthGetTransactionByBlockNumberAndIndex(ctx context.Cont
|
||||
return ethtypes.EthTx{}, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) {
|
||||
func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) {
|
||||
func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) {
|
||||
func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) {
|
||||
return ethtypes.EthBigIntZero, ErrModuleDisabled
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall
|
||||
return 0, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) {
|
||||
func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) {
|
||||
return nil, ErrModuleDisabled
|
||||
}
|
||||
|
||||
|
||||
+85
-16
@@ -59,12 +59,12 @@ type EthModuleAPI interface {
|
||||
EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error)
|
||||
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error)
|
||||
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error)
|
||||
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error)
|
||||
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error)
|
||||
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error)
|
||||
EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*api.EthTxReceipt, error)
|
||||
EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error)
|
||||
EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error)
|
||||
EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error)
|
||||
EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error)
|
||||
EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error)
|
||||
EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error)
|
||||
EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error)
|
||||
EthChainId(ctx context.Context) (ethtypes.EthUint64, error)
|
||||
EthSyncing(ctx context.Context) (ethtypes.EthSyncingResult, error)
|
||||
@@ -73,7 +73,7 @@ type EthModuleAPI interface {
|
||||
EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error)
|
||||
EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error)
|
||||
EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error)
|
||||
EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error)
|
||||
EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error)
|
||||
EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error)
|
||||
EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error)
|
||||
Web3ClientVersion(ctx context.Context) (string, error)
|
||||
@@ -241,7 +241,76 @@ func (a *EthModule) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthH
|
||||
return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.StateAPI)
|
||||
}
|
||||
|
||||
func (a *EthModule) parseBlkParam(ctx context.Context, blkParam string, strict bool) (tipset *types.TipSet, err error) {
|
||||
func (a *EthModule) getTipsetByEthBlockNumberOrHash(ctx context.Context, blkParam ethtypes.EthBlockParamByNumberOrHash) (*types.TipSet, error) {
|
||||
head := a.Chain.GetHeaviestTipSet()
|
||||
|
||||
predefined := blkParam.PredefinedBlock
|
||||
if predefined != nil {
|
||||
if *predefined == "earliest" {
|
||||
return nil, fmt.Errorf("block param \"earliest\" is not supported")
|
||||
} else if *predefined == "pending" {
|
||||
return head, nil
|
||||
} else if *predefined == "latest" {
|
||||
parent, err := a.Chain.GetTipSetFromKey(ctx, head.Parents())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get parent tipset")
|
||||
}
|
||||
return parent, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("unknown predefined block %s", *predefined)
|
||||
}
|
||||
}
|
||||
|
||||
// utility function to validate a tipset by height and return it
|
||||
returnAndValidateTipsetFunc := func(height abi.ChainEpoch) (*types.TipSet, error) {
|
||||
if height > head.Height()-1 {
|
||||
return nil, fmt.Errorf("requested a future epoch (beyond 'latest')")
|
||||
}
|
||||
ts, err := a.ChainAPI.ChainGetTipSetByHeight(ctx, height, head.Key())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get tipset at height: %v", height)
|
||||
}
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
if blkParam.Number != nil {
|
||||
return returnAndValidateTipsetFunc(abi.ChainEpoch(*blkParam.Number))
|
||||
}
|
||||
|
||||
if blkParam.BlockNumber != nil {
|
||||
return returnAndValidateTipsetFunc(abi.ChainEpoch(*blkParam.BlockNumber))
|
||||
}
|
||||
|
||||
if blkParam.BlockHash != nil {
|
||||
ts, err := a.Chain.GetTipSetByCid(ctx, blkParam.BlockHash.ToCid())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get tipset by hash: %v", err)
|
||||
}
|
||||
|
||||
if blkParam.RequireCanonical {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("invalid block param")
|
||||
}
|
||||
|
||||
func (a *EthModule) parseBlkParam(ctx context.Context, blkParam string, strict bool) (*types.TipSet, error) {
|
||||
if blkParam == "earliest" {
|
||||
return nil, fmt.Errorf("block param \"earliest\" is not supported")
|
||||
}
|
||||
@@ -382,13 +451,13 @@ func (a *EthModule) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid)
|
||||
return &hash, err
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam string) (ethtypes.EthUint64, error) {
|
||||
func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) {
|
||||
addr, err := sender.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return ethtypes.EthUint64(0), nil
|
||||
}
|
||||
|
||||
ts, err := a.parseBlkParam(ctx, blkParam, false)
|
||||
ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam)
|
||||
if err != nil {
|
||||
return ethtypes.EthUint64(0), xerrors.Errorf("failed to process block param: %s; %w", blkParam, err)
|
||||
}
|
||||
@@ -470,13 +539,13 @@ func (a *EthAPI) EthGetTransactionByBlockNumberAndIndex(context.Context, ethtype
|
||||
}
|
||||
|
||||
// EthGetCode returns string value of the compiled bytecode
|
||||
func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, blkParam string) (ethtypes.EthBytes, error) {
|
||||
func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) {
|
||||
to, err := ethAddr.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("cannot get Filecoin address: %w", err)
|
||||
}
|
||||
|
||||
ts, err := a.parseBlkParam(ctx, blkParam, false)
|
||||
ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err)
|
||||
}
|
||||
@@ -554,8 +623,8 @@ func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress,
|
||||
return blk.RawData(), nil
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) {
|
||||
ts, err := a.parseBlkParam(ctx, blkParam, false)
|
||||
func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) {
|
||||
ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err)
|
||||
}
|
||||
@@ -645,13 +714,13 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd
|
||||
return ethtypes.EthBytes(ret), nil
|
||||
}
|
||||
|
||||
func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) {
|
||||
func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) {
|
||||
filAddr, err := address.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return ethtypes.EthBigInt{}, err
|
||||
}
|
||||
|
||||
ts, err := a.parseBlkParam(ctx, blkParam, false)
|
||||
ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam)
|
||||
if err != nil {
|
||||
return ethtypes.EthBigInt{}, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err)
|
||||
}
|
||||
@@ -1112,13 +1181,13 @@ func ethGasSearch(
|
||||
return -1, xerrors.Errorf("message execution failed: exit %s, reason: %s", res.MsgRct.ExitCode, res.Error)
|
||||
}
|
||||
|
||||
func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) {
|
||||
func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) {
|
||||
msg, err := a.ethCallToFilecoinMessage(ctx, tx)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to convert ethcall to filecoin message: %w", err)
|
||||
}
|
||||
|
||||
ts, err := a.parseBlkParam(ctx, blkParam, false)
|
||||
ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user