Merge pull request #107 from 0glabs/suggestion_gas_price

generate suggestion gas price during prepare proposal and pass it to …
This commit is contained in:
Solovyov1796 2025-02-10 23:31:44 +08:00 committed by GitHub
commit e54d5ba99a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 181 additions and 456 deletions

View File

@ -2,7 +2,10 @@ package app
import (
"fmt"
"math/big"
"sort"
"github.com/0glabs/0g-chain/chaincfg"
"github.com/cockroachdb/errors"
abci "github.com/cometbft/cometbft/abci/types"
gethtypes "github.com/ethereum/go-ethereum/core/types"
@ -13,6 +16,8 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth/signing"
)
const gasPriceSuggestionBlockNum int64 = 5
type (
// GasTx defines the contract that a transaction with a gas limit must implement.
GasTx interface {
@ -30,17 +35,29 @@ type (
// DefaultProposalHandler defines the default ABCI PrepareProposal and
// ProcessProposal handlers.
DefaultProposalHandler struct {
mempool mempool.Mempool
txVerifier ProposalTxVerifier
txSelector TxSelector
mempool mempool.Mempool
txVerifier ProposalTxVerifier
txSelector TxSelector
feemarketKeeper FeeMarketKeeper
}
FeeMarketKeeper interface {
SetSuggestionGasPrice(ctx sdk.Context, gas *big.Int)
}
txnInfo struct {
gasPrice *big.Int
gasLimit uint64
nonce uint64
sender string
}
)
func NewDefaultProposalHandler(mp mempool.Mempool, txVerifier ProposalTxVerifier) *DefaultProposalHandler {
func NewDefaultProposalHandler(mp mempool.Mempool, txVerifier ProposalTxVerifier, feemarketKeeper FeeMarketKeeper) *DefaultProposalHandler {
return &DefaultProposalHandler{
mempool: mp,
txVerifier: txVerifier,
txSelector: NewDefaultTxSelector(),
mempool: mp,
txVerifier: txVerifier,
txSelector: NewDefaultTxSelector(),
feemarketKeeper: feemarketKeeper,
}
}
@ -97,11 +114,14 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
return abci.ResponsePrepareProposal{Txs: h.txSelector.SelectedTxs()}
}
txnInfoMap := make(map[string][]*txnInfo, h.mempool.CountTx())
iterator := h.mempool.Select(ctx, req.Txs)
selectedTxsSignersSeqs := make(map[string]uint64)
var selectedTxsNums int
for iterator != nil {
memTx := iterator.Tx()
sigs, err := memTx.(signing.SigVerifiableTx).GetSignaturesV2()
if err != nil {
panic(fmt.Errorf("failed to get signatures: %w", err))
@ -134,10 +154,42 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
txSignersSeqs[signer] = nonce
}
}
if _, exists := txnInfoMap[signer]; !exists {
txnInfoMap[signer] = make([]*txnInfo, 0, 128)
}
txnInfoMap[signer] = append(txnInfoMap[signer], &txnInfo{
gasPrice: ethTx.GasPrice(),
gasLimit: ethTx.Gas(),
nonce: nonce,
sender: signer,
})
}
}
}
} else {
// ignore multisig case now
fee := memTx.(sdk.Fee)
if len(sigs) == 1 {
signer := sdk.AccAddress(sigs[0].PubKey.Address()).String()
if _, exists := txnInfoMap[signer]; !exists {
txnInfoMap[signer] = make([]*txnInfo, 0, 16)
}
evmGasPrice, err := utilCosmosDemonGasPriceToEvmDemonGasPrice(fee.GetAmount())
if err == nil {
txnInfoMap[signer] = append(txnInfoMap[signer], &txnInfo{
gasPrice: evmGasPrice,
gasLimit: utilCosmosDemonGasLimitToEvmDemonGasLimit(fee.GetGas()),
nonce: sigs[0].Sequence,
sender: signer,
})
}
}
for _, sig := range sigs {
signer := sdk.AccAddress(sig.PubKey.Address()).String()
seq, ok := selectedTxsSignersSeqs[signer]
@ -198,6 +250,65 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
iterator = iterator.Next()
}
if len(txnInfoMap) == 0 {
h.feemarketKeeper.SetSuggestionGasPrice(ctx, big.NewInt(0))
} else {
senderCnt := 0
txnCnt := 0
for sender := range txnInfoMap {
sort.Slice(txnInfoMap[sender], func(i, j int) bool {
return txnInfoMap[sender][i].nonce < txnInfoMap[sender][j].nonce
})
txnCnt += len(txnInfoMap[sender])
senderCnt++
}
remaing := gasPriceSuggestionBlockNum * int64(maxBlockGas)
var lastProcessedTx *txnInfo
for remaing > 0 && len(txnInfoMap) > 0 {
// Find the highest gas price among the first transaction of each account
var highestGasPrice *big.Int
var selectedSender string
// Compare first transaction (lowest nonce) from each account
for sender, txns := range txnInfoMap {
if len(txns) == 0 {
delete(txnInfoMap, sender)
continue
}
// First tx has lowest nonce due to earlier sorting
if highestGasPrice == nil || txns[0].gasPrice.Cmp(highestGasPrice) > 0 {
highestGasPrice = txns[0].gasPrice
selectedSender = sender
}
}
if selectedSender == "" {
break
}
// Process the selected transaction
selectedTx := txnInfoMap[selectedSender][0]
remaing -= int64(selectedTx.gasLimit)
lastProcessedTx = selectedTx
// Remove processed transaction
txnInfoMap[selectedSender] = txnInfoMap[selectedSender][1:]
if len(txnInfoMap[selectedSender]) == 0 {
delete(txnInfoMap, selectedSender)
}
}
if lastProcessedTx != nil && remaing <= 0 {
h.feemarketKeeper.SetSuggestionGasPrice(ctx, lastProcessedTx.gasPrice)
} else {
h.feemarketKeeper.SetSuggestionGasPrice(ctx, big.NewInt(0))
}
}
return abci.ResponsePrepareProposal{Txs: h.txSelector.SelectedTxs()}
}
}
@ -336,3 +447,22 @@ func (ts *defaultTxSelector) SelectTxForProposal(maxTxBytes, maxBlockGas uint64,
// check if we've reached capacity; if so, we cannot select any more transactions
return ts.totalTxBytes >= maxTxBytes || (maxBlockGas > 0 && (ts.totalTxGas >= maxBlockGas))
}
func utilCosmosDemonGasPriceToEvmDemonGasPrice(gasGroup sdk.Coins) (*big.Int, error) {
gasPrice := big.NewInt(0)
for _, coin := range gasGroup {
if coin.Denom == chaincfg.GasDenom {
thisGasPrice := big.NewInt(0).SetUint64(coin.Amount.Uint64())
thisGasPrice = thisGasPrice.Mul(thisGasPrice, big.NewInt(0).SetInt64(chaincfg.GasDenomConversionMultiplier))
gasPrice = gasPrice.Add(gasPrice, thisGasPrice)
} else {
return big.NewInt(0), fmt.Errorf("invalid denom: %s", coin.Denom)
}
}
return gasPrice, nil
}
func utilCosmosDemonGasLimitToEvmDemonGasLimit(gasLimit uint64) uint64 {
return gasLimit * chaincfg.GasDenomConversionMultiplier
}

View File

@ -52,13 +52,17 @@ func TestAppAnteHandler_AuthorizedMempool(t *testing.T) {
tApp := app.TestApp{
App: *app.NewApp(
log.NewNopLogger(),
tmdb.NewMemDB(),
chaincfg.DefaultNodeHome,
nil,
encodingConfig,
opts,
baseapp.SetChainID(app.TestChainId),
app.NewBaseApp(
log.NewNopLogger(),
tmdb.NewMemDB(),
encodingConfig,
baseapp.SetChainID(app.TestChainId),
),
nil,
),
}

View File

@ -267,7 +267,7 @@ type App struct {
packetForwardKeeper *packetforwardkeeper.Keeper
evmKeeper *evmkeeper.Keeper
evmutilKeeper evmutilkeeper.Keeper
feeMarketKeeper feemarketkeeper.Keeper
feeMarketKeeper *feemarketkeeper.Keeper
upgradeKeeper upgradekeeper.Keeper
evidenceKeeper evidencekeeper.Keeper
transferKeeper ibctransferkeeper.Keeper
@ -313,6 +313,7 @@ func NewApp(
encodingConfig chainparams.EncodingConfig,
options Options,
bApp *baseapp.BaseApp,
setAbciProposalHandler func(feemarketKeeper FeeMarketKeeper) sdk.PrepareProposalHandler,
) *App {
appCodec := encodingConfig.Marshaler
legacyAmino := encodingConfig.Amino
@ -901,6 +902,10 @@ func NewApp(
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
if setAbciProposalHandler != nil {
abciProposalHandler := setAbciProposalHandler(app.feeMarketKeeper)
bApp.SetPrepareProposal(abciProposalHandler)
}
// load store
if !options.SkipLoadLatest {
if err := app.LoadLatestVersion(); err != nil {

View File

@ -28,19 +28,36 @@ import (
func TestNewApp(t *testing.T) {
chaincfg.SetSDKConfig()
NewApp(
log.NewTMLogger(log.NewSyncWriter(os.Stdout)),
db.NewMemDB(),
chaincfg.DefaultNodeHome,
nil,
MakeEncodingConfig(),
DefaultOptions,
NewBaseApp(
log.NewTMLogger(log.NewSyncWriter(os.Stdout)),
db.NewMemDB(),
MakeEncodingConfig(),
baseapp.SetChainID(TestChainId),
),
nil,
)
}
func TestExport(t *testing.T) {
chaincfg.SetSDKConfig()
db := db.NewMemDB()
app := NewApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, chaincfg.DefaultNodeHome, nil, MakeEncodingConfig(), DefaultOptions, baseapp.SetChainID(TestChainId))
app := NewApp(
chaincfg.DefaultNodeHome,
nil,
MakeEncodingConfig(),
DefaultOptions,
NewBaseApp(
log.NewTMLogger(log.NewSyncWriter(os.Stdout)),
db,
MakeEncodingConfig(),
baseapp.SetChainID(TestChainId),
),
nil,
)
genesisState := GenesisStateWithSingleValidator(&TestApp{App: *app}, NewDefaultGenesisState())

View File

@ -96,7 +96,7 @@ func NewTestAppFromSealed() TestApp {
bApp := NewBaseApp(log.NewNopLogger(), db, encCfg, baseapp.SetChainID(TestChainId))
app := NewApp(
chaincfg.DefaultNodeHome, nil,
encCfg, DefaultOptions, bApp,
encCfg, DefaultOptions, bApp, nil,
)
return TestApp{App: *app}
}
@ -117,7 +117,7 @@ func (tApp TestApp) GetPriceFeedKeeper() pricefeedkeeper.Keeper { return tAp
func (tApp TestApp) GetCommitteeKeeper() committeekeeper.Keeper { return tApp.committeeKeeper }
func (tApp TestApp) GetEvmutilKeeper() evmutilkeeper.Keeper { return tApp.evmutilKeeper }
func (tApp TestApp) GetEvmKeeper() *evmkeeper.Keeper { return tApp.evmKeeper }
func (tApp TestApp) GetFeeMarketKeeper() feemarketkeeper.Keeper { return tApp.feeMarketKeeper }
func (tApp TestApp) GetFeeMarketKeeper() *feemarketkeeper.Keeper { return tApp.feeMarketKeeper }
func (tApp TestApp) GetDASignersKeeper() dasignerskeeper.Keeper { return tApp.dasignersKeeper }
func (tApp TestApp) GetPrecisebankKeeper() precisebankkeeper.Keeper { return tApp.precisebankKeeper }
func (tApp TestApp) GetWrappedA0GIBaseKeeper() wrappeda0gibasekeeper.Keeper {

View File

@ -1,434 +1 @@
package app_test
import (
"strconv"
"testing"
"time"
sdkmath "cosmossdk.io/math"
"github.com/0glabs/0g-chain/app"
evmutiltypes "github.com/0glabs/0g-chain/x/evmutil/types"
precisebankkeeper "github.com/0glabs/0g-chain/x/precisebank/keeper"
precisebanktypes "github.com/0glabs/0g-chain/x/precisebank/types"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
func TestMigrateEvmutilToPrecisebank(t *testing.T) {
// Full test case with all components together
tests := []struct {
name string
initialReserve sdkmath.Int
fractionalBalances []sdkmath.Int
}{
{
"no fractional balances",
sdkmath.NewInt(0),
[]sdkmath.Int{},
},
{
"sufficient reserve, 0 remainder",
// Accounts adding up to 2 int units, same as reserve
sdkmath.NewInt(2),
[]sdkmath.Int{
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
{
"insufficient reserve, 0 remainder",
// Accounts adding up to 2 int units, but only 1 int unit in reserve
sdkmath.NewInt(1),
[]sdkmath.Int{
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
{
"excess reserve, 0 remainder",
// Accounts adding up to 2 int units, but 3 int unit in reserve
sdkmath.NewInt(3),
[]sdkmath.Int{
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
{
"sufficient reserve, non-zero remainder",
// Accounts adding up to 1.5 int units, same as reserve
sdkmath.NewInt(2),
[]sdkmath.Int{
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
{
"insufficient reserve, non-zero remainder",
// Accounts adding up to 1.5 int units, less than reserve,
// Reserve should be 2 and remainder 0.5
sdkmath.NewInt(1),
[]sdkmath.Int{
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
{
"excess reserve, non-zero remainder",
// Accounts adding up to 1.5 int units, 3 int units in reserve
sdkmath.NewInt(3),
[]sdkmath.Int{
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tApp := app.NewTestApp()
tApp.InitializeFromGenesisStates()
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
ak := tApp.GetAccountKeeper()
bk := tApp.GetBankKeeper()
evmuk := tApp.GetEvmutilKeeper()
pbk := tApp.GetPrecisebankKeeper()
reserveCoin := sdk.NewCoin(precisebanktypes.IntegerCoinDenom, tt.initialReserve)
err := bk.MintCoins(ctx, evmutiltypes.ModuleName, sdk.NewCoins(reserveCoin))
require.NoError(t, err)
oldReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(evmutiltypes.ModuleName)
newReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(precisebanktypes.ModuleName)
// Double check balances
oldReserveBalance := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
newReserveBalance := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
require.Equal(t, tt.initialReserve, oldReserveBalance.Amount, "initial x/evmutil reserve balance")
require.True(t, newReserveBalance.IsZero(), "empty initial new reserve")
// Set accounts
for i, balance := range tt.fractionalBalances {
addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
err := evmuk.SetBalance(ctx, addr, balance)
require.NoError(t, err)
}
// Run full x/evmutil -> x/precisebank migration
err = app.MigrateEvmutilToPrecisebank(
ctx,
ak,
bk,
evmuk,
pbk,
)
require.NoError(t, err)
// Check old reserve is empty
oldReserveBalanceAfter := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
require.True(t, oldReserveBalanceAfter.IsZero(), "old reserve should be empty")
// Check new reserve fully backs fractional balances
newReserveBalanceAfter := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
fractionalBalanceTotal := pbk.GetTotalSumFractionalBalances(ctx)
remainder := pbk.GetRemainderAmount(ctx)
expectedReserveBal := fractionalBalanceTotal.Add(remainder)
require.Equal(
t,
expectedReserveBal,
newReserveBalanceAfter.Amount.Mul(precisebanktypes.ConversionFactor()),
"new reserve should equal total fractional balances",
)
// Check balances are deleted in evmutil and migrated to precisebank
for i := range tt.fractionalBalances {
addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
acc := evmuk.GetAccount(ctx, addr)
require.Nil(t, acc, "account should be deleted")
balance := pbk.GetFractionalBalance(ctx, addr)
require.Equal(t, tt.fractionalBalances[i], balance, "balance should be migrated")
}
// Checks balances valid and remainder
res, stop := precisebankkeeper.AllInvariants(pbk)(ctx)
require.Falsef(t, stop, "invariants should pass: %s", res)
})
}
}
func TestTransferFractionalBalances(t *testing.T) {
tests := []struct {
name string
fractionalBalances []sdkmath.Int
}{
{
"no fractional balances",
[]sdkmath.Int{},
},
{
"balanced fractional balances",
[]sdkmath.Int{
// 4 accounts
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
{
"unbalanced balances",
[]sdkmath.Int{
// 3 accounts
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tApp := app.NewTestApp()
tApp.InitializeFromGenesisStates()
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
evmutilk := tApp.GetEvmutilKeeper()
pbk := tApp.GetPrecisebankKeeper()
for i, balance := range tt.fractionalBalances {
addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
err := evmutilk.SetBalance(ctx, addr, balance)
require.NoError(t, err)
}
// Run balance transfer
aggregateSum, err := app.TransferFractionalBalances(
ctx,
evmutilk,
pbk,
)
require.NoError(t, err)
// Check balances are deleted in evmutil and migrated to precisebank
sum := sdkmath.ZeroInt()
for i := range tt.fractionalBalances {
sum = sum.Add(tt.fractionalBalances[i])
addr := sdk.AccAddress([]byte(strconv.Itoa(i)))
acc := evmutilk.GetAccount(ctx, addr)
require.Nil(t, acc, "account should be deleted")
balance := pbk.GetFractionalBalance(ctx, addr)
require.Equal(t, tt.fractionalBalances[i], balance, "balance should be migrated")
}
require.Equal(t, sum, aggregateSum, "aggregate sum should be correct")
})
}
}
func TestInitializeRemainder(t *testing.T) {
tests := []struct {
name string
giveAggregateSum sdkmath.Int
wantRemainder sdkmath.Int
}{
{
"0 remainder, 1ukava",
precisebanktypes.ConversionFactor(),
sdkmath.NewInt(0),
},
{
"0 remainder, multiple ukava",
precisebanktypes.ConversionFactor().MulRaw(5),
sdkmath.NewInt(0),
},
{
"non-zero remainder, min",
precisebanktypes.ConversionFactor().SubRaw(1),
sdkmath.NewInt(1),
},
{
"non-zero remainder, max",
sdkmath.NewInt(1),
precisebanktypes.ConversionFactor().SubRaw(1),
},
{
"non-zero remainder, half",
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tApp := app.NewTestApp()
tApp.InitializeFromGenesisStates()
pbk := tApp.GetPrecisebankKeeper()
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
remainder := app.InitializeRemainder(
ctx,
tApp.GetPrecisebankKeeper(),
tt.giveAggregateSum,
)
require.Equal(t, tt.wantRemainder, remainder)
// Check actual state
remainderAfter := pbk.GetRemainderAmount(ctx)
require.Equal(t, tt.wantRemainder, remainderAfter)
// Not checking invariants here since it requires actual balance state
aggregateSumWithRemainder := tt.giveAggregateSum.Add(remainder)
require.True(
t,
aggregateSumWithRemainder.
Mod(precisebanktypes.ConversionFactor()).
IsZero(),
"remainder + aggregate sum should be a multiple of the conversion factor",
)
})
}
}
func TestTransferFractionalBalanceReserve(t *testing.T) {
tests := []struct {
name string
initialReserve sdk.Coin
fractionalBalances []sdkmath.Int
}{
{
"balanced reserve, no remainder",
sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(1)),
[]sdkmath.Int{
// 2 accounts
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
{
"insufficient reserve",
sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(1)),
[]sdkmath.Int{
// 4 accounts, total 2 int units
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
{
"extra reserve funds",
sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(2)),
[]sdkmath.Int{
// 2 accounts, total 1 int units
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
{
"insufficient reserve, with remainder",
sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(1)),
[]sdkmath.Int{
// 5 accounts, total 2.5 int units
// Expected 3 int units in reserve, 0.5 remainder
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
{
"extra reserve funds, with remainder",
sdk.NewCoin(precisebanktypes.IntegerCoinDenom, sdk.NewInt(3)),
[]sdkmath.Int{
// 3 accounts, total 1.5 int units.
// Expected 2 int units in reserve, 0.5 remainder
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
precisebanktypes.ConversionFactor().QuoRaw(2),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tApp := app.NewTestApp()
tApp.InitializeFromGenesisStates()
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: time.Now()})
bk := tApp.GetBankKeeper()
pbk := tApp.GetPrecisebankKeeper()
err := bk.MintCoins(ctx, evmutiltypes.ModuleName, sdk.NewCoins(tt.initialReserve))
require.NoError(t, err)
oldReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(evmutiltypes.ModuleName)
newReserveAddr := tApp.GetAccountKeeper().GetModuleAddress(precisebanktypes.ModuleName)
// Double check balances
oldReserveBalance := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
newReserveBalance := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
require.Equal(t, tt.initialReserve, oldReserveBalance)
require.True(t, newReserveBalance.IsZero(), "empty initial new reserve")
for i, balance := range tt.fractionalBalances {
addr := sdk.AccAddress([]byte{byte(i)})
require.NotPanics(t, func() {
pbk.SetFractionalBalance(ctx, addr, balance)
}, "given fractional balances should be valid")
}
// Run reserve migration
err = app.TransferFractionalBalanceReserve(
ctx,
tApp.GetAccountKeeper(),
bk,
tApp.GetPrecisebankKeeper(),
)
require.NoError(t, err)
// Check old reserve is empty
oldReserveBalanceAfter := bk.GetBalance(ctx, oldReserveAddr, precisebanktypes.IntegerCoinDenom)
require.True(t, oldReserveBalanceAfter.IsZero(), "old reserve should be empty")
// Check new reserve fully backs fractional balances
newReserveBalanceAfter := bk.GetBalance(ctx, newReserveAddr, precisebanktypes.IntegerCoinDenom)
fractionalBalanceTotal := pbk.GetTotalSumFractionalBalances(ctx)
expectedReserveBal := fractionalBalanceTotal.
Quo(precisebanktypes.ConversionFactor())
// Check if theres a remainder
if fractionalBalanceTotal.Mod(precisebanktypes.ConversionFactor()).IsPositive() {
expectedReserveBal = expectedReserveBal.Add(sdkmath.OneInt())
}
require.Equal(
t,
expectedReserveBal,
newReserveBalanceAfter.Amount,
"new reserve should equal total fractional balances + remainder",
)
})
}
}

View File

@ -126,8 +126,6 @@ func (ac appCreator) newApp(
baseapp.SetMempool(mempool),
)
bApp.SetTxEncoder(ac.encodingConfig.TxConfig.TxEncoder())
abciProposalHandler := app.NewDefaultProposalHandler(mempool, bApp)
bApp.SetPrepareProposal(abciProposalHandler.PrepareProposalHandler())
newApp := app.NewApp(
homeDir, traceStore, ac.encodingConfig,
@ -142,6 +140,10 @@ func (ac appCreator) newApp(
EVMMaxGasWanted: cast.ToUint64(appOpts.Get(ethermintflags.EVMMaxTxGasWanted)),
},
bApp,
func(k app.FeeMarketKeeper) sdk.PrepareProposalHandler {
abciProposalHandler := app.NewDefaultProposalHandler(mempool, bApp, k)
return abciProposalHandler.PrepareProposalHandler()
},
)
return newApp
@ -170,14 +172,14 @@ func (ac appCreator) appExport(
var tempApp *app.App
if height != -1 {
bApp := app.NewBaseApp(logger, db, ac.encodingConfig)
tempApp = app.NewApp(homePath, traceStore, ac.encodingConfig, options, bApp)
tempApp = app.NewApp(homePath, traceStore, ac.encodingConfig, options, bApp, nil)
if err := tempApp.LoadHeight(height); err != nil {
return servertypes.ExportedApp{}, err
}
} else {
bApp := app.NewBaseApp(logger, db, ac.encodingConfig)
tempApp = app.NewApp(homePath, traceStore, ac.encodingConfig, options, bApp)
tempApp = app.NewApp(homePath, traceStore, ac.encodingConfig, options, bApp, nil)
}
return tempApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport)
}

2
go.mod
View File

@ -250,7 +250,7 @@ replace (
// TODO: Tag before release
github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc2
// Use ethermint fork that respects min-gas-price with NoBaseFee true and london enabled, and includes eip712 support
github.com/evmos/ethermint => github.com/0glabs/ethermint v0.21.0-0g.v3.1.9
github.com/evmos/ethermint => github.com/0glabs/ethermint v0.21.0-0g.v3.1.10
// See https://github.com/cosmos/cosmos-sdk/pull/10401, https://github.com/cosmos/cosmos-sdk/commit/0592ba6158cd0bf49d894be1cef4faeec59e8320
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.0
// Downgraded to avoid bugs in following commits which causes "version does not exist" errors

4
go.sum
View File

@ -213,8 +213,8 @@ github.com/0glabs/cometbft v0.37.9-0glabs.1 h1:KQJG17Y21suKP3QNICLto4b5Ak73XbSmK
github.com/0glabs/cometbft v0.37.9-0glabs.1/go.mod h1:j0Q3RqrCd+cztWCugs3obbzC4NyHGBPZZjtm/fWV00I=
github.com/0glabs/cosmos-sdk v0.47.10-0glabs.10 h1:NJp0RwczHBO4EvrQdDxxftHOgUDBtNh7M/vpaG7wFtQ=
github.com/0glabs/cosmos-sdk v0.47.10-0glabs.10/go.mod h1:KskIVnhXTFqrw7CDccMvx7To5KzUsOomIsQV7sPGOog=
github.com/0glabs/ethermint v0.21.0-0g.v3.1.9 h1:oTHp7tSAqoML7D/+RXsBzA9DsbZ80MX93VJYjR/Akh4=
github.com/0glabs/ethermint v0.21.0-0g.v3.1.9/go.mod h1:6e/gOcDLhvlDWK3JLJVBgki0gD6H4E1eG7l9byocgWA=
github.com/0glabs/ethermint v0.21.0-0g.v3.1.10 h1:DE8hK2OJp9rKYdT2Y0G259/6nAFcOQi383l2e7/VFnE=
github.com/0glabs/ethermint v0.21.0-0g.v3.1.10/go.mod h1:6e/gOcDLhvlDWK3JLJVBgki0gD6H4E1eG7l9byocgWA=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM=