Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions app/ante/evm_delivertx.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/sei-protocol/sei-chain/sei-cosmos/client"
"github.com/sei-protocol/sei-chain/sei-cosmos/crypto/keys/secp256k1"
sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types"
sdkerrors "github.com/sei-protocol/sei-chain/sei-cosmos/types/errors"
upgradekeeper "github.com/sei-protocol/sei-chain/sei-cosmos/x/upgrade/keeper"
"github.com/sei-protocol/sei-chain/x/evm/derived"
evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper"
Expand Down Expand Up @@ -46,6 +47,22 @@ func EvmDeliverTxAnte(
}

func EvmDeliverHandleSignatures(ctx sdk.Context, ek *evmkeeper.Keeper, txData ethtx.TxData, chainID *big.Int, msg *evmtypes.MsgEVMTransaction) (common.Address, derived.SignerVersion, error) {
if msg.Derived != nil {
if msg.Derived.PubKey == nil {
return common.Address{}, 0, sdkerrors.ErrInvalidPubKey
}
evmAddr := msg.Derived.SenderEVMAddr
seiAddr := msg.Derived.SenderSeiAddr
version := msg.Derived.Version
if err := AssociateAddress(ctx, ek, evmAddr, seiAddr, msg.Derived.PubKey); err != nil {
return evmAddr, version, err
}
if ek.EthReplayConfig.Enabled {
ek.PrepareReplayedAddr(ctx, evmAddr)
}
return evmAddr, version, nil
}

evmAddr, seiAddr, seiPubkey, version, err := CheckAndDecodeSignature(ctx, txData, chainID, ek.EthBlockTestConfig.Enabled)
if err != nil {
return evmAddr, version, err
Expand Down
36 changes: 35 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -1529,6 +1529,35 @@ func (app *App) ProcessTxsSynchronousGiga(ctx sdk.Context, txs [][]byte, typedTx
return txResults
}

func (app *App) shouldProcessSingleRecipientEVMTransfersSynchronously(typedTxs []sdk.Tx) bool {
const minSingleRecipientEVMTransfers = 64

if len(typedTxs) < minSingleRecipientEVMTransfers {
return false
}

var recipient common.Address
for i, tx := range typedTxs {
msg := app.GetEVMMsg(tx)
if msg == nil {
return false
}
etx, _ := msg.AsTransaction()
if etx == nil || etx.To() == nil || len(etx.Data()) != 0 || etx.Value().Sign() <= 0 {
return false
}
if i == 0 {
recipient = *etx.To()
continue
}
if *etx.To() != recipient {
return false
}
}

return true
}

// cacheContext returns a new context based off of the provided context with
// a branched multi-store.
func (app *App) CacheContext(ctx sdk.Context) (sdk.Context, sdk.CacheMultiStore) {
Expand All @@ -1539,14 +1568,19 @@ func (app *App) CacheContext(ctx sdk.Context) (sdk.Context, sdk.CacheMultiStore)

// ExecuteTxsConcurrently calls the appropriate function for processing transacitons
func (app *App) ExecuteTxsConcurrently(ctx sdk.Context, txs [][]byte, typedTxs []sdk.Tx) ([]*abci.ExecTxResult, sdk.Context) {
processSynchronously := app.shouldProcessSingleRecipientEVMTransfersSynchronously(typedTxs)

// Giga only supports synchronous execution for now
if app.GigaExecutorEnabled && app.GigaOCCEnabled {
if app.GigaExecutorEnabled && app.GigaOCCEnabled && !processSynchronously {
return app.ProcessTXsWithOCCGiga(ctx, txs, typedTxs)
} else if app.GigaExecutorEnabled {
return app.ProcessTxsSynchronousGiga(ctx, txs, typedTxs), ctx
} else if !ctx.IsOCCEnabled() {
return app.ProcessTxsSynchronousV2(ctx, txs, typedTxs), ctx
}
if processSynchronously {
return app.ProcessTxsSynchronousV2(ctx, txs, typedTxs), ctx
}

return app.ProcessTXsWithOCCV2(ctx, txs, typedTxs)
}
Expand Down
10 changes: 10 additions & 0 deletions utils/helpers/associate.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ func NewAssociationHelper(evmKeeper evmKeeper, bankKeeper bankKeeper, accountKee
}

func (p AssociationHelper) AssociateAddresses(ctx sdk.Context, seiAddr sdk.AccAddress, evmAddr common.Address, pubkey cryptotypes.PubKey, migrateUseiOnly bool) error {
castAddr := sdk.AccAddress(evmAddr[:])
if !castAddr.Equals(seiAddr) && p.accountKeeper.GetAccount(ctx, seiAddr) == nil {
castAcc := p.accountKeeper.GetAccount(ctx, castAddr)
if castAcc != nil && castAcc.GetPubKey() == nil && p.bankKeeper.LockedCoins(ctx, castAddr).IsZero() {
p.accountKeeper.SetAccount(ctx, authtypes.NewBaseAccount(seiAddr, pubkey, castAcc.GetAccountNumber(), castAcc.GetSequence()))
}
}
p.evmKeeper.SetAddressMapping(ctx, seiAddr, evmAddr)
if acc := p.accountKeeper.GetAccount(ctx, seiAddr); acc.GetPubKey() == nil {
if err := acc.SetPubKey(pubkey); err != nil {
Expand All @@ -44,6 +51,9 @@ func (p AssociationHelper) AssociateAddresses(ctx sdk.Context, seiAddr sdk.AccAd

func (p AssociationHelper) MigrateBalance(ctx sdk.Context, evmAddr common.Address, seiAddr sdk.AccAddress, migrateUseiOnly bool) error {
castAddr := sdk.AccAddress(evmAddr[:])
if castAddr.Equals(seiAddr) {
return nil
}
var castAddrBalances sdk.Coins
if migrateUseiOnly {
castAddrBalances = sdk.Coins{p.bankKeeper.GetBalance(ctx, castAddr, "usei")}
Expand Down
113 changes: 113 additions & 0 deletions utils/helpers/associate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package helpers
import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/sei-protocol/sei-chain/sei-cosmos/crypto/keys/secp256k1"
sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types"
authtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/auth/types"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -158,3 +160,114 @@ func TestEdgeCases(t *testing.T) {
require.Equal(t, 20, len(evmAddr.Bytes()))
})
}

type mockEVMKeeper struct {
mappings map[string]common.Address
}

func (m *mockEVMKeeper) SetAddressMapping(_ sdk.Context, seiAddress sdk.AccAddress, evmAddress common.Address) {
if m.mappings == nil {
m.mappings = map[string]common.Address{}
}
m.mappings[seiAddress.String()] = evmAddress
}

type mockBankKeeper struct {
sendCalls int
}

func (m *mockBankKeeper) SpendableCoins(sdk.Context, sdk.AccAddress) sdk.Coins {
return sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100)))
}

func (m *mockBankKeeper) SendCoins(sdk.Context, sdk.AccAddress, sdk.AccAddress, sdk.Coins) error {
m.sendCalls++
return nil
}

func (m *mockBankKeeper) GetWeiBalance(sdk.Context, sdk.AccAddress) sdk.Int {
return sdk.ZeroInt()
}

func (m *mockBankKeeper) SendCoinsAndWei(sdk.Context, sdk.AccAddress, sdk.AccAddress, sdk.Int, sdk.Int) error {
return nil
}

func (m *mockBankKeeper) LockedCoins(sdk.Context, sdk.AccAddress) sdk.Coins {
return nil
}

func (m *mockBankKeeper) GetBalance(sdk.Context, sdk.AccAddress, string) sdk.Coin {
return sdk.NewCoin("usei", sdk.NewInt(100))
}

type mockAccountKeeper struct {
accounts map[string]authtypes.AccountI
newAccountCalls int
}

func (m *mockAccountKeeper) GetAccount(_ sdk.Context, addr sdk.AccAddress) authtypes.AccountI {
return m.accounts[addr.String()]
}

func (m *mockAccountKeeper) HasAccount(_ sdk.Context, addr sdk.AccAddress) bool {
_, ok := m.accounts[addr.String()]
return ok
}

func (m *mockAccountKeeper) SetAccount(_ sdk.Context, acc authtypes.AccountI) {
if m.accounts == nil {
m.accounts = map[string]authtypes.AccountI{}
}
m.accounts[acc.GetAddress().String()] = acc
}

func (m *mockAccountKeeper) RemoveAccount(_ sdk.Context, acc authtypes.AccountI) {
delete(m.accounts, acc.GetAddress().String())
}

func (m *mockAccountKeeper) NewAccountWithAddress(_ sdk.Context, addr sdk.AccAddress) authtypes.AccountI {
m.newAccountCalls++
return authtypes.NewBaseAccountWithAddress(addr)
}

func (m *mockAccountKeeper) GetParams(sdk.Context) authtypes.Params {
return authtypes.DefaultParams()
}

func TestAssociateAddressesReusesEmptyCastAccount(t *testing.T) {
ctx := sdk.Context{}
evmAddr := common.HexToAddress("0x1111111111111111111111111111111111111111")
castAddr := sdk.AccAddress(evmAddr[:])
seiAddr := sdk.AccAddress(common.HexToAddress("0x2222222222222222222222222222222222222222").Bytes())
pubkey := secp256k1.GenPrivKey().PubKey().(*secp256k1.PubKey)

ak := &mockAccountKeeper{accounts: map[string]authtypes.AccountI{}}
ak.SetAccount(ctx, authtypes.NewBaseAccount(castAddr, nil, 42, 7))
bk := &mockBankKeeper{}
ek := &mockEVMKeeper{}

helper := NewAssociationHelper(ek, bk, ak)
require.NoError(t, helper.AssociateAddresses(ctx, seiAddr, evmAddr, pubkey, false))

require.Zero(t, ak.newAccountCalls)
require.Nil(t, ak.GetAccount(ctx, castAddr))
require.Equal(t, evmAddr, ek.mappings[seiAddr.String()])
acc := ak.GetAccount(ctx, seiAddr)
require.NotNil(t, acc)
require.Equal(t, uint64(42), acc.GetAccountNumber())
require.Equal(t, uint64(7), acc.GetSequence())
require.Equal(t, pubkey.Bytes(), acc.GetPubKey().Bytes())
require.Equal(t, 1, bk.sendCalls)
}

func TestMigrateBalanceSkipsDirectCastAddress(t *testing.T) {
ctx := sdk.Context{}
evmAddr := common.HexToAddress("0x1111111111111111111111111111111111111111")
seiAddr := sdk.AccAddress(evmAddr[:])

bk := &mockBankKeeper{}
helper := NewAssociationHelper(&mockEVMKeeper{}, bk, &mockAccountKeeper{})
require.NoError(t, helper.MigrateBalance(ctx, evmAddr, seiAddr, false))
require.Zero(t, bk.sendCalls)
}
Loading