Compare commits

...

12 Commits

Author SHA1 Message Date
crStiv
0a31f108df
Merge 7fbf83bacb into e54d5ba99a 2025-02-10 16:32:24 +01:00
Solovyov1796
e54d5ba99a
Merge pull request #107 from 0glabs/suggestion_gas_price
generate suggestion gas price during prepare proposal and pass it to …
2025-02-10 23:31:44 +08:00
Solovyov1796
a0426c63f7 set suggetsion gas price as 0 if not found 2025-02-10 23:27:22 +08:00
Solovyov1796
a32dad8373 remove useless code 2025-02-10 23:13:10 +08:00
Solovyov1796
4f53e59af7
Merge pull request #108 from 0g-wh/suggestion_gas_price
update txn selection algo
2025-02-10 22:47:43 +08:00
Solovyov1796
8ecfda7bd2 update ethermint version 2025-02-10 22:23:46 +08:00
0g-wh
bbd02215f7 update txn selection algo 2025-02-10 14:23:18 +00:00
Solovyov1796
d4066b6a3d using merge sort 2025-02-10 19:35:13 +08:00
Solovyov1796
7900795654 update 2025-02-10 17:55:58 +08:00
Solovyov1796
6df54c84b5 update suggetsion gas price code 2025-02-10 14:37:15 +08:00
Solovyov1796
ec7e0c3163 generate suggestion gas price during prepare proposal and pass it to ethermint via fee market keeper 2025-02-08 21:53:25 +08:00
crStiv
7fbf83bacb
Update README.md 2025-01-12 02:58:41 +01:00
10 changed files with 230 additions and 458 deletions

View File

@ -25,11 +25,58 @@ Continue reading [here](https://docs.0g.ai/intro) if you want to learn more abou
- If you want to run a validator node, DA node, or storage node, please refer to the [Run a Node Documentation](https://docs.0g.ai/run-a-node/overview).
## Getting Started
To get started with 0G Chain, you'll need to:
1. Read our [documentation](https://docs.0g.ai/intro)
2. Choose which component you want to work with (DA, Storage, Inference Serving, or Network)
3. Follow the setup instructions in the relevant documentation section
## Contributing
We welcome contributions from the community! Here's how you can contribute:
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request
Please make sure to:
- Follow our coding standards
- Write clear commit messages
- Update documentation as needed
- Add tests for new features
## Technical Overview
0G Chain consists of several key components:
### Data Availability (DA) Layer
- Ultra high-performance with KZG commitments
- Quorum-based Data Availability Sampling
- Optimized for AI workloads
### Decentralized Storage
- Erasure coding for data reliability
- Efficient replication mechanisms
- Optimized for large-scale AI models
### Inference Serving
- Flexible framework for AI model deployment
- Support for model fine-tuning
- Distributed inference capabilities
### Network Layer
- High-performance P2P communication
- Low-latency data transfer
- Decentralized architecture
## Support and Additional Resources
We want to do everything we can to help you be successful while working on your contribution and projects. Here you'll find various resources and communities that may help you complete a project or contribute to 0G.
We're here to help you succeed in contributing to and building with 0G Chain:
### Official Links
- [Official Website](https://0g.ai)
- [Technical Documentation](https://docs.0g.ai)
- [GitHub Repository](https://github.com/0glabs)
### Communities
- [0G Telegram](https://t.me/web3_0glabs)
- [0G Discord](https://discord.com/invite/0glabs)
- [0G Discord](https://discord.com/invite/0glabs)

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=