Merge pull request #10300 from filecoin-project/steb/fix-eth-nonce
fix: eth: return the correct nonce from EthGetTransactionCount
This commit is contained in:
commit
efcdec6517
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
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
|
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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user