fix: eth: correctly decode EthGetStorageAt output (#10284)

* fix: eth: correctly decode EthGetStorageAt output

We cbor-encode it. Also:

1. Actually use the passed block param.
2. Check if the target actor is an EVM actor to avoid nonsense outputs.

fixes https://github.com/filecoin-project/ref-fvm/issues/1621
This commit is contained in:
Steven Allen 2023-02-16 16:36:52 -08:00 committed by GitHub
parent a2b996e054
commit 5854d72784
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 5 deletions

View File

@ -265,6 +265,20 @@ func TestFEVMDelegateCall(t *testing.T) {
expectedResultActor, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
require.NoError(t, err)
require.Equal(t, result, expectedResultActor)
// The implementation's storage should not have been updated.
actorAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(actorAddr)
require.NoError(t, err)
value, err := client.EVM().EthGetStorageAt(ctx, actorAddrEth, nil, "latest")
require.NoError(t, err)
require.Equal(t, ethtypes.EthBytes(make([]byte, 32)), value)
// The storage actor's storage _should_ have been updated
storageAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(storageAddr)
require.NoError(t, err)
value, err = client.EVM().EthGetStorageAt(ctx, storageAddrEth, nil, "latest")
require.NoError(t, err)
require.Equal(t, ethtypes.EthBytes(expectedResult), value)
}
// TestFEVMDelegateCallRevert makes a delegatecall action and then calls revert.

View File

@ -510,13 +510,18 @@ func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress,
}
func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) {
ts, err := a.parseBlkParam(ctx, blkParam)
if err != nil {
return nil, xerrors.Errorf("cannot parse block param: %s", blkParam)
}
l := len(position)
if l > 32 {
return nil, fmt.Errorf("supplied storage key is too long")
}
// pad with zero bytes if smaller than 32 bytes
position = append(make([]byte, 32-l, 32-l), position...)
position = append(make([]byte, 32-l, 32), position...)
to, err := ethAddr.ToFilecoinAddress()
if err != nil {
@ -529,6 +534,18 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd
return nil, fmt.Errorf("failed to construct system sender address: %w", err)
}
actor, err := a.StateManager.LoadActor(ctx, to, ts)
if err != nil {
if xerrors.Is(err, types.ErrActorNotFound) {
return ethtypes.EthBytes(make([]byte, 32)), nil
}
return nil, xerrors.Errorf("failed to lookup contract %s: %w", ethAddr, err)
}
if !builtinactors.IsEvmActor(actor.Code) {
return ethtypes.EthBytes(make([]byte, 32)), nil
}
params, err := actors.SerializeParams(&evm.GetStorageAtParams{
StorageKey: *(*[32]byte)(position),
})
@ -547,8 +564,6 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd
GasPremium: big.Zero(),
}
ts := a.Chain.GetHeaviestTipSet()
// Try calling until we find a height with no migration.
var res *api.InvocResult
for {
@ -567,10 +582,22 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd
}
if res.MsgRct == nil {
return nil, fmt.Errorf("no message receipt")
return nil, xerrors.Errorf("no message receipt")
}
return res.MsgRct.Return, nil
if res.MsgRct.ExitCode.IsError() {
return nil, xerrors.Errorf("failed to lookup storage slot: %s", res.Error)
}
var ret abi.CborBytes
if err := ret.UnmarshalCBOR(bytes.NewReader(res.MsgRct.Return)); err != nil {
return nil, xerrors.Errorf("failed to unmarshal storage slot: %w", err)
}
// pad with zero bytes if smaller than 32 bytes
ret = append(make([]byte, 32-len(ret), 32), ret...)
return ethtypes.EthBytes(ret), nil
}
func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) {