diff --git a/itests/fevm_test.go b/itests/fevm_test.go index 3018bf63ddd..cf70faba280 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -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. diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index e30fe4da1e8..3fc6c6940d4 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -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") + } + + 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) } - return res.MsgRct.Return, nil + // 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) {