Merge branch 'release/v1.20.0' into asr/merge-release-into-master

This commit is contained in:
Aayush
2023-02-17 16:08:22 -05:00
51 changed files with 608 additions and 154 deletions
+5
View File
@@ -6,6 +6,7 @@ import (
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/lotus/api"
@@ -16,6 +17,10 @@ var ErrModuleDisabled = errors.New("module disabled, enable with Fevm.EnableEthR
type EthModuleDummy struct{}
func (e *EthModuleDummy) EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) {
return address.Undef, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) {
return nil, ErrModuleDisabled
}
+154 -10
View File
@@ -31,6 +31,7 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin"
builtinevm "github.com/filecoin-project/lotus/chain/actors/builtin/evm"
"github.com/filecoin-project/lotus/chain/ethhashlookup"
"github.com/filecoin-project/lotus/chain/events/filter"
"github.com/filecoin-project/lotus/chain/messagepool"
@@ -181,6 +182,10 @@ func (a *EthModule) EthAccounts(context.Context) ([]ethtypes.EthAddress, error)
return []ethtypes.EthAddress{}, nil
}
func (a *EthAPI) EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) {
return ethAddress.ToFilecoinAddress()
}
func (a *EthModule) countTipsetMsgs(ctx context.Context, ts *types.TipSet) (int, error) {
blkMsgs, err := a.Chain.BlockMsgsForTipset(ctx, ts)
if err != nil {
@@ -363,6 +368,26 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.
return ethtypes.EthUint64(0), xerrors.Errorf("cannot parse block param: %s", blkParam)
}
// First, handle the case where the "sender" is an EVM actor.
if actor, err := a.StateManager.LoadActor(ctx, addr, ts); err != nil {
if xerrors.Is(err, types.ErrActorNotFound) {
return 0, nil
}
return 0, xerrors.Errorf("failed to lookup contract %s: %w", sender, err)
} else if builtinactors.IsEvmActor(actor.Code) {
evmState, err := builtinevm.Load(a.Chain.ActorStore(ctx), actor)
if err != nil {
return 0, xerrors.Errorf("failed to load evm state: %w", err)
}
if alive, err := evmState.IsAlive(); err != nil {
return 0, err
} else if !alive {
return 0, nil
}
nonce, err := evmState.Nonce()
return ethtypes.EthUint64(nonce), err
}
nonce, err := a.Mpool.GetNonce(ctx, addr, ts.Key())
if err != nil {
return ethtypes.EthUint64(0), nil
@@ -506,13 +531,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 {
@@ -525,6 +555,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),
})
@@ -543,8 +585,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 {
@@ -563,10 +603,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) {
@@ -840,7 +892,8 @@ func (a *EthModule) applyMessage(ctx context.Context, msg *types.Message, tsk ty
return nil, xerrors.Errorf("CallWithGas failed: %w", err)
}
if res.MsgRct.ExitCode.IsError() {
return nil, xerrors.Errorf("message execution failed: exit %s, msg receipt: %s, reason: %s", res.MsgRct.ExitCode, res.MsgRct.Return, res.Error)
reason := parseEthRevert(res.MsgRct.Return)
return nil, xerrors.Errorf("message execution failed: exit %s, revert reason: %s, vm error: %s", res.MsgRct.ExitCode, reason, res.Error)
}
return res, nil
}
@@ -856,14 +909,24 @@ func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (et
msg.GasLimit = 0
ts := a.Chain.GetHeaviestTipSet()
msg, err = a.GasAPI.GasEstimateMessageGas(ctx, msg, nil, ts.Key())
gassedMsg, err := a.GasAPI.GasEstimateMessageGas(ctx, msg, nil, ts.Key())
if err != nil {
// On failure, GasEstimateMessageGas doesn't actually return the invocation result,
// it just returns an error. That means we can't get the revert reason.
//
// So we re-execute the message with EthCall (well, applyMessage which contains the
// guts of EthCall). This will give us an ethereum specific error with revert
// information.
msg.GasLimit = build.BlockGasLimit
if _, err2 := a.applyMessage(ctx, msg, ts.Key()); err2 != nil {
err = err2
}
return ethtypes.EthUint64(0), xerrors.Errorf("failed to estimate gas: %w", err)
}
expectedGas, err := ethGasSearch(ctx, a.Chain, a.Stmgr, a.Mpool, msg, ts)
expectedGas, err := ethGasSearch(ctx, a.Chain, a.Stmgr, a.Mpool, gassedMsg, ts)
if err != nil {
log.Errorw("expected gas", "err", err)
return 0, xerrors.Errorf("gas search failed: %w", err)
}
return ethtypes.EthUint64(expectedGas), nil
@@ -1001,7 +1064,7 @@ func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam s
invokeResult, err := a.applyMessage(ctx, msg, ts.Key())
if err != nil {
return nil, xerrors.Errorf("failed to apply message: %w", err)
return nil, err
}
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
@@ -2125,11 +2188,13 @@ func (m *EthTxHashManager) ProcessSignedMessage(ctx context.Context, msg *types.
ethTx, err := newEthTxFromSignedMessage(ctx, msg, m.StateAPI)
if err != nil {
log.Errorf("error converting filecoin message to eth tx: %s", err)
return
}
err = m.TransactionHashLookup.UpsertHash(ethTx.Hash, msg.Cid())
if err != nil {
log.Errorf("error inserting tx mapping to db: %s", err)
return
}
}
@@ -2180,6 +2245,85 @@ func parseEthTopics(topics ethtypes.EthTopicSpec) (map[string][][]byte, error) {
return keys, nil
}
const errorFunctionSelector = "\x08\xc3\x79\xa0" // Error(string)
const panicFunctionSelector = "\x4e\x48\x7b\x71" // Panic(uint256)
// Eth ABI (solidity) panic codes.
var panicErrorCodes map[uint64]string = map[uint64]string{
0x00: "Panic()",
0x01: "Assert()",
0x11: "ArithmeticOverflow()",
0x12: "DivideByZero()",
0x21: "InvalidEnumVariant()",
0x22: "InvalidStorageArray()",
0x31: "PopEmptyArray()",
0x32: "ArrayIndexOutOfBounds()",
0x41: "OutOfMemory()",
0x51: "CalledUninitializedFunction()",
}
// Parse an ABI encoded revert reason. This reason should be encoded as if it were the parameters to
// an `Error(string)` function call.
//
// See https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require
func parseEthRevert(ret []byte) string {
if len(ret) == 0 {
return "none"
}
var cbytes abi.CborBytes
if err := cbytes.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
return "ERROR: revert reason is not cbor encoded bytes"
}
if len(cbytes) == 0 {
return "none"
}
// If it's not long enough to contain an ABI encoded response, return immediately.
if len(cbytes) < 4+32 {
return ethtypes.EthBytes(cbytes).String()
}
switch string(cbytes[:4]) {
case panicFunctionSelector:
cbytes := cbytes[4 : 4+32]
// Read the and check the code.
code, err := ethtypes.EthUint64FromBytes(cbytes)
if err != nil {
// If it's too big, just return the raw value.
codeInt := big.PositiveFromUnsignedBytes(cbytes)
return fmt.Sprintf("Panic(%s)", ethtypes.EthBigInt(codeInt).String())
}
if s, ok := panicErrorCodes[uint64(code)]; ok {
return s
}
return fmt.Sprintf("Panic(0x%x)", code)
case errorFunctionSelector:
cbytes := cbytes[4:]
cbytesLen := ethtypes.EthUint64(len(cbytes))
// Read the and check the offset.
offset, err := ethtypes.EthUint64FromBytes(cbytes[:32])
if err != nil {
break
}
if cbytesLen < offset {
break
}
// Read and check the length.
if cbytesLen-offset < 32 {
break
}
start := offset + 32
length, err := ethtypes.EthUint64FromBytes(cbytes[offset : offset+32])
if err != nil {
break
}
if cbytesLen-start < length {
break
}
// Slice the error message.
return fmt.Sprintf("Error(%s)", cbytes[start:start+length])
}
return ethtypes.EthBytes(cbytes).String()
}
func calculateRewardsAndGasUsed(rewardPercentiles []float64, txGasRewards gasRewardSorter) ([]ethtypes.EthBigInt, uint64) {
var totalGasUsed uint64
for _, tx := range txGasRewards {