fix: eth: return the correct nonce from EthGetTransactionCount
EVM contracts track this number internally. fixes https://github.com/filecoin-project/lotus/issues/10255
This commit is contained in:
parent
00b6d06041
commit
a3bc65ba05
@ -48,6 +48,7 @@ type State interface {
|
||||
cbor.Marshaler
|
||||
|
||||
Nonce() (uint64, error)
|
||||
IsAlive() (bool, error)
|
||||
GetState() interface{}
|
||||
|
||||
GetBytecode() ([]byte, error)
|
||||
|
@ -48,6 +48,7 @@ type State interface {
|
||||
cbor.Marshaler
|
||||
|
||||
Nonce() (uint64, error)
|
||||
IsAlive() (bool, error)
|
||||
GetState() interface{}
|
||||
|
||||
GetBytecode() ([]byte, error)
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"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/go-state-types/abi"
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (s *state{{.v}}) IsAlive() (bool, error) {
|
||||
return s.State.Tombstone == nil, nil
|
||||
}
|
||||
|
||||
func (s *state{{.v}}) GetState() interface{} {
|
||||
return &s.State
|
||||
}
|
||||
|
4
chain/actors/builtin/evm/v10.go
generated
4
chain/actors/builtin/evm/v10.go
generated
@ -41,6 +41,10 @@ func (s *state10) Nonce() (uint64, error) {
|
||||
return s.State.Nonce, nil
|
||||
}
|
||||
|
||||
func (s *state10) IsAlive() (bool, error) {
|
||||
return s.State.Tombstone == nil, nil
|
||||
}
|
||||
|
||||
func (s *state10) GetState() interface{} {
|
||||
return &s.State
|
||||
}
|
||||
|
@ -10,15 +10,16 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
"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.
|
||||
// 2. Non-existent actors.
|
||||
// 3. Normal EVM actors.
|
||||
// 4. Self-destructed EVM actors.
|
||||
func TestGetCode(t *testing.T) {
|
||||
func TestGetCodeAndNonce(t *testing.T) {
|
||||
kit.QuietMiningLogs()
|
||||
|
||||
blockTime := 100 * time.Millisecond
|
||||
@ -28,7 +29,7 @@ func TestGetCode(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
|
||||
// Accounts should have empty code.
|
||||
// Accounts should have empty code, empty nonce.
|
||||
{
|
||||
// A random eth address should have no code.
|
||||
_, ethAddr, filAddr := client.EVM().NewAccount()
|
||||
@ -36,6 +37,11 @@ func TestGetCode(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
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.
|
||||
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")
|
||||
require.NoError(t, err)
|
||||
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.
|
||||
@ -61,6 +72,11 @@ func TestGetCode(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
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.
|
||||
_, _, err = client.EVM().InvokeContractByFuncName(ctx, client.DefaultKey.Address, contractFilAddr, "destroy()", nil)
|
||||
require.NoError(t, err)
|
||||
@ -69,6 +85,11 @@ func TestGetCode(t *testing.T) {
|
||||
bytecode, err = client.EVM().EthGetCode(ctx, contractAddr, "latest")
|
||||
require.NoError(t, err)
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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"
|
||||
@ -367,6 +368,29 @@ 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.
|
||||
actor, err := a.StateManager.LoadActor(ctx, addr, ts)
|
||||
if err != nil {
|
||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||
return 0, nil
|
||||
}
|
||||
return 0, xerrors.Errorf("failed to lookup contract %s: %w", sender, err)
|
||||
}
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user