Merge pull request #10300 from filecoin-project/steb/fix-eth-nonce

fix: eth: return the correct nonce from EthGetTransactionCount
This commit is contained in:
Aayush Rajasekaran 2023-02-17 14:45:45 -05:00 committed by GitHub
commit efcdec6517
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 3 deletions

View File

@ -48,6 +48,7 @@ type State interface {
cbor.Marshaler cbor.Marshaler
Nonce() (uint64, error) Nonce() (uint64, error)
IsAlive() (bool, error)
GetState() interface{} GetState() interface{}
GetBytecode() ([]byte, error) GetBytecode() ([]byte, error)

View File

@ -48,6 +48,7 @@ type State interface {
cbor.Marshaler cbor.Marshaler
Nonce() (uint64, error) Nonce() (uint64, error)
IsAlive() (bool, error)
GetState() interface{} GetState() interface{}
GetBytecode() ([]byte, error) GetBytecode() ([]byte, error)

View File

@ -4,6 +4,8 @@ import (
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/go-state-types/abi"
evm{{.v}} "github.com/filecoin-project/go-state-types/builtin{{.import}}evm" evm{{.v}} "github.com/filecoin-project/go-state-types/builtin{{.import}}evm"
) )
@ -40,6 +42,10 @@ func (s *state{{.v}}) Nonce() (uint64, error) {
return s.State.Nonce, nil return s.State.Nonce, nil
} }
func (s *state{{.v}}) IsAlive() (bool, error) {
return s.State.Tombstone == nil, nil
}
func (s *state{{.v}}) GetState() interface{} { func (s *state{{.v}}) GetState() interface{} {
return &s.State return &s.State
} }

View File

@ -41,6 +41,10 @@ func (s *state10) Nonce() (uint64, error) {
return s.State.Nonce, nil return s.State.Nonce, nil
} }
func (s *state10) IsAlive() (bool, error) {
return s.State.Tombstone == nil, nil
}
func (s *state10) GetState() interface{} { func (s *state10) GetState() interface{} {
return &s.State return &s.State
} }

View File

@ -10,15 +10,16 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/itests/kit"
) )
// TestGetCode ensures that GetCode returns the correct results for: // TestGetCodeAndNonce ensures that GetCode and GetTransactionCount return the correct results for:
// 1. Placeholders. // 1. Placeholders.
// 2. Non-existent actors. // 2. Non-existent actors.
// 3. Normal EVM actors. // 3. Normal EVM actors.
// 4. Self-destructed EVM actors. // 4. Self-destructed EVM actors.
func TestGetCode(t *testing.T) { func TestGetCodeAndNonce(t *testing.T) {
kit.QuietMiningLogs() kit.QuietMiningLogs()
blockTime := 100 * time.Millisecond blockTime := 100 * time.Millisecond
@ -28,7 +29,7 @@ func TestGetCode(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel() defer cancel()
// Accounts should have empty code. // Accounts should have empty code, empty nonce.
{ {
// A random eth address should have no code. // A random eth address should have no code.
_, ethAddr, filAddr := client.EVM().NewAccount() _, ethAddr, filAddr := client.EVM().NewAccount()
@ -36,6 +37,11 @@ func TestGetCode(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, bytecode) require.Empty(t, bytecode)
// Nonce should also be zero
nonce, err := client.EVM().EthGetTransactionCount(ctx, ethAddr, "latest")
require.NoError(t, err)
require.Zero(t, nonce)
// send some funds to the account. // send some funds to the account.
kit.SendFunds(ctx, t, client, filAddr, types.FromFil(10)) kit.SendFunds(ctx, t, client, filAddr, types.FromFil(10))
@ -43,6 +49,11 @@ func TestGetCode(t *testing.T) {
bytecode, err = client.EVM().EthGetCode(ctx, ethAddr, "latest") bytecode, err = client.EVM().EthGetCode(ctx, ethAddr, "latest")
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, bytecode) require.Empty(t, bytecode)
// Nonce should still be zero.
nonce, err = client.EVM().EthGetTransactionCount(ctx, ethAddr, "latest")
require.NoError(t, err)
require.Zero(t, nonce)
} }
// Check contract code. // Check contract code.
@ -61,6 +72,11 @@ func TestGetCode(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, bytecode) require.NotEmpty(t, bytecode)
// Nonce should be one.
nonce, err := client.EVM().EthGetTransactionCount(ctx, contractAddr, "latest")
require.NoError(t, err)
require.Equal(t, ethtypes.EthUint64(1), nonce)
// Destroy it. // Destroy it.
_, _, err = client.EVM().InvokeContractByFuncName(ctx, client.DefaultKey.Address, contractFilAddr, "destroy()", nil) _, _, err = client.EVM().InvokeContractByFuncName(ctx, client.DefaultKey.Address, contractFilAddr, "destroy()", nil)
require.NoError(t, err) require.NoError(t, err)
@ -69,6 +85,11 @@ func TestGetCode(t *testing.T) {
bytecode, err = client.EVM().EthGetCode(ctx, contractAddr, "latest") bytecode, err = client.EVM().EthGetCode(ctx, contractAddr, "latest")
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, bytecode) require.Empty(t, bytecode)
// Nonce should go back to zero
nonce, err = client.EVM().EthGetTransactionCount(ctx, contractAddr, "latest")
require.NoError(t, err)
require.Zero(t, nonce)
} }
} }

View File

@ -31,6 +31,7 @@ import (
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin" 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/ethhashlookup"
"github.com/filecoin-project/lotus/chain/events/filter" "github.com/filecoin-project/lotus/chain/events/filter"
"github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/messagepool"
@ -367,6 +368,26 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.
return ethtypes.EthUint64(0), xerrors.Errorf("cannot parse block param: %s", blkParam) 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()) nonce, err := a.Mpool.GetNonce(ctx, addr, ts.Key())
if err != nil { if err != nil {
return ethtypes.EthUint64(0), nil return ethtypes.EthUint64(0), nil