diff --git a/app/app.go b/app/app.go index 8cddb2032a..7054da3e81 100644 --- a/app/app.go +++ b/app/app.go @@ -24,7 +24,6 @@ import ( tmjson "github.com/cometbft/cometbft/libs/json" "github.com/cometbft/cometbft/libs/log" tmos "github.com/cometbft/cometbft/libs/os" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec/types" "github.com/gorilla/mux" @@ -328,6 +327,7 @@ type App struct { interfaceRegistry types.InterfaceRegistry invCheckPeriod uint + blockedMap map[string]struct{} // keys to access the substores keys map[string]*storetypes.KVStoreKey @@ -385,8 +385,6 @@ type App struct { configurator module.Configurator qms storetypes.MultiStore - - blockProposalHandler *ProposalHandler } // New returns a reference to an initialized chain. @@ -396,7 +394,7 @@ func New( homePath string, invCheckPeriod uint, encodingConfig ethermint.EncodingConfig, // this line is used by starport scaffolding # stargate/app/newArgument appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), -) *App { +) (app *App) { appCodec := encodingConfig.Codec cdc := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry @@ -423,15 +421,25 @@ func New( baseAppOptions = memiavlstore.SetupMemIAVL(logger, homePath, appOpts, false, false, baseAppOptions) - blockProposalHandler := NewProposalHandler(encodingConfig.TxConfig.TxDecoder(), identity) + keys, memKeys, tkeys := StoreKeys(skipGravity) + cronosKey := keys[cronostypes.StoreKey] + txConfig := encodingConfig.TxConfig + maxTxGasWanted := cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted)) // NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx // Setup Mempool and Proposal Handlers - baseAppOptions = append(baseAppOptions, func(app *baseapp.BaseApp) { + baseAppOptions = append(baseAppOptions, func(bapp *baseapp.BaseApp) { mempool := mempool.NoOpMempool{} - app.SetMempool(mempool) - app.SetPrepareProposal(blockProposalHandler.PrepareProposalHandler()) - app.SetProcessProposal(blockProposalHandler.ProcessProposalHandler()) + bapp.SetMempool(mempool) + blockProposalHandler := NewProposalHandler( + appCodec, + cronosKey, + txConfig.TxDecoder(), + identity, + func(blacklist []string) { app.setAnteHandler(txConfig, maxTxGasWanted, blacklist) }, + ) + bapp.SetPrepareProposal(blockProposalHandler.PrepareProposalHandler()) + bapp.SetProcessProposal(blockProposalHandler.ProcessProposalHandler()) }) bApp := baseapp.NewBaseApp(Name, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...) @@ -439,18 +447,15 @@ func New( bApp.SetVersion(version.Version) bApp.SetInterfaceRegistry(interfaceRegistry) - keys, memKeys, tkeys := StoreKeys(skipGravity) - - app := &App{ - BaseApp: bApp, - cdc: cdc, - appCodec: appCodec, - interfaceRegistry: interfaceRegistry, - invCheckPeriod: invCheckPeriod, - keys: keys, - tkeys: tkeys, - memKeys: memKeys, - blockProposalHandler: blockProposalHandler, + app = &App{ + BaseApp: bApp, + cdc: cdc, + appCodec: appCodec, + interfaceRegistry: interfaceRegistry, + invCheckPeriod: invCheckPeriod, + keys: keys, + tkeys: tkeys, + memKeys: memKeys, } // init params keeper and subspaces @@ -606,7 +611,7 @@ func New( app.CronosKeeper = *cronoskeeper.NewKeeper( appCodec, - keys[cronostypes.StoreKey], + cronosKey, keys[cronostypes.MemStoreKey], app.BankKeeper, app.TransferKeeper, @@ -955,10 +960,6 @@ func New( tmos.Exit(fmt.Sprintf("versiondb version %d lag behind iavl version %d", v1, v2)) } } - - if err := app.RefreshBlockList(app.NewUncachedContext(false, tmproto.Header{})); err != nil { - panic(err) - } } app.ScopedIBCKeeper = scopedIBCKeeper @@ -970,8 +971,11 @@ func New( return app } -// use Ethermint's custom AnteHandler -func (app *App) setAnteHandler(txConfig client.TxConfig, maxGasWanted uint64, blacklist []string) error { +func (app *App) getBlockedMap() map[string]struct{} { + return app.blockedMap +} + +func (app *App) setBlacklist(blacklist []string) error { if len(blacklist) > 0 { sort.Strings(blacklist) // hash blacklist concatenated @@ -991,14 +995,16 @@ func (app *App) setAnteHandler(txConfig client.TxConfig, maxGasWanted uint64, bl } blockedMap := make(map[string]struct{}, len(blacklist)) for _, str := range blacklist { - addr, err := sdk.AccAddressFromBech32(str) - if err != nil { - return fmt.Errorf("invalid bech32 address: %s, err: %w", str, err) - } - - blockedMap[string(addr)] = struct{}{} + blockedMap[str] = struct{}{} } - blockAddressDecorator := NewBlockAddressesDecorator(blockedMap) + app.blockedMap = blockedMap + return nil +} + +// use Ethermint's custom AnteHandler +func (app *App) setAnteHandler(txConfig client.TxConfig, maxGasWanted uint64, blacklist []string) error { + app.setBlacklist(blacklist) + blockAddressDecorator := NewBlockAddressesDecorator(app.getBlockedMap) options := evmante.HandlerOptions{ AccountKeeper: app.AccountKeeper, BankKeeper: app.BankKeeper, @@ -1053,22 +1059,7 @@ func (app *App) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.R // EndBlocker application updates every end block func (app *App) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { - rsp := app.mm.EndBlock(ctx, req) - - if err := app.RefreshBlockList(ctx); err != nil { - app.Logger().Error("failed to update blocklist", "error", err) - } - - return rsp -} - -func (app *App) RefreshBlockList(ctx sdk.Context) error { - if app.blockProposalHandler.Identity == nil { - return nil - } - - // refresh blocklist - return app.blockProposalHandler.SetBlockList(app.CronosKeeper.GetBlockList(ctx)) + return app.mm.EndBlock(ctx, req) } // InitChainer application update at chain initialization diff --git a/app/block_address.go b/app/block_address.go index 11cb1cfa68..eb92ddd8e9 100644 --- a/app/block_address.go +++ b/app/block_address.go @@ -8,20 +8,21 @@ import ( // BlockAddressesDecorator block addresses from sending transactions type BlockAddressesDecorator struct { - blockedMap map[string]struct{} + blockedMapGetter func() map[string]struct{} } -func NewBlockAddressesDecorator(blacklist map[string]struct{}) BlockAddressesDecorator { - return BlockAddressesDecorator{ - blockedMap: blacklist, +func NewBlockAddressesDecorator(blockedMapGetter func() map[string]struct{}) *BlockAddressesDecorator { + return &BlockAddressesDecorator{ + blockedMapGetter: blockedMapGetter, } } func (bad BlockAddressesDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + blockedMap := bad.blockedMapGetter() if ctx.IsCheckTx() { for _, msg := range tx.GetMsgs() { for _, signer := range msg.GetSigners() { - if _, ok := bad.blockedMap[string(signer)]; ok { + if _, ok := blockedMap[signer.String()]; ok { return ctx, fmt.Errorf("signer is blocked: %s", signer.String()) } } diff --git a/app/proposal.go b/app/proposal.go index 14f646a52f..857a2c34fd 100644 --- a/app/proposal.go +++ b/app/proposal.go @@ -3,111 +3,76 @@ package app import ( "bytes" "encoding/json" - "fmt" "io" "filippo.io/age" abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/signing" + cronostypes "github.com/crypto-org-chain/cronos/v2/x/cronos/types" ) -type BlockList struct { - Addresses []string `mapstructure:"addresses"` -} - type ProposalHandler struct { - TxDecoder sdk.TxDecoder - Identity age.Identity - Blocklist map[string]struct{} - LastBlockList []byte -} - -func NewProposalHandler(txDecoder sdk.TxDecoder, identity age.Identity) *ProposalHandler { - return &ProposalHandler{ - TxDecoder: txDecoder, - Identity: identity, - Blocklist: make(map[string]struct{}), - } + cdc codec.BinaryCodec + cronosKey *storetypes.KVStoreKey + TxDecoder sdk.TxDecoder + Identity age.Identity + LastBlockList []byte + refreshBlocklistHandler refreshBlocklistHandler } -func (h *ProposalHandler) SetBlockList(blob []byte) error { - if h.Identity == nil { - return nil - } - - if bytes.Equal(h.LastBlockList, blob) { - return nil - } - h.LastBlockList = blob - - reader, err := age.Decrypt(bytes.NewBuffer(blob), h.Identity) - if err != nil { - return err - } - - data, err := io.ReadAll(reader) - if err != nil { - return err - } - - var blocklist BlockList - if err := json.Unmarshal(data, &blocklist); err != nil { - return err - } - - // convert to map - m := make(map[string]struct{}, len(blocklist.Addresses)) - for _, s := range blocklist.Addresses { - addr, err := sdk.AccAddressFromBech32(s) - if err != nil { - return fmt.Errorf("invalid bech32 address: %s, err: %w", s, err) - } - m[addr.String()] = struct{}{} - } - - h.Blocklist = m - return nil +type blockList struct { + Addresses []string `mapstructure:"addresses"` } -func (h *ProposalHandler) ValidateTransactions(txs [][]byte) error { - for _, txBz := range txs { - tx, err := h.TxDecoder(txBz) - if err != nil { - return err - } - - sigTx, ok := tx.(signing.SigVerifiableTx) - if !ok { - return fmt.Errorf("tx of type %T does not implement SigVerifiableTx", tx) - } +type refreshBlocklistHandler func(blacklist []string) - for _, signer := range sigTx.GetSigners() { - if _, ok := h.Blocklist[signer.String()]; ok { - return fmt.Errorf("signer is blocked: %s", signer.String()) - } - } +func NewProposalHandler( + cdc codec.BinaryCodec, + cronosKey *storetypes.KVStoreKey, + txDecoder sdk.TxDecoder, + identity age.Identity, + refreshBlocklistHandler refreshBlocklistHandler, +) *ProposalHandler { + return &ProposalHandler{ + cdc: cdc, + cronosKey: cronosKey, + TxDecoder: txDecoder, + Identity: identity, + refreshBlocklistHandler: refreshBlocklistHandler, } - return nil } func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler { return func(ctx sdk.Context, req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - if err := h.ValidateTransactions(req.Txs); err != nil { - panic(err) - } - return abci.ResponsePrepareProposal{Txs: req.Txs} } } func (h *ProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler { return func(ctx sdk.Context, req abci.RequestProcessProposal) abci.ResponseProcessProposal { - if err := h.ValidateTransactions(req.Txs); err != nil { - panic(err) + if h.Identity != nil { + reject := abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + blob := ctx.KVStore(h.cronosKey).Get(cronostypes.KeyPrefixBlockList) + if !bytes.Equal(h.LastBlockList, blob) { + reader, err := age.Decrypt(bytes.NewBuffer(blob), h.Identity) + if err != nil { + return reject + } + data, err := io.ReadAll(reader) + if err != nil { + return reject + } + var blocklist blockList + if err := json.Unmarshal(data, &blocklist); err != nil { + return reject + } + h.LastBlockList = blob + h.refreshBlocklistHandler(blocklist.Addresses) + } } - return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT} } } diff --git a/integration_tests/test_gov_update_params.py b/integration_tests/test_gov_update_params.py index d410872433..792235cf5b 100644 --- a/integration_tests/test_gov_update_params.py +++ b/integration_tests/test_gov_update_params.py @@ -97,11 +97,15 @@ def test_gov_update_params(cronos, tmp_path): # gen two keys for two accounts name = "e2ee-identity" + cli1 = cronos.cosmos_cli(1) pubkey0 = cli.keygen(keyring_name=name) + pubkey1 = cli.keygen(keyring_name=name) cli.register_e2ee_key(pubkey0, _from="validator") + cli1.register_e2ee_key(pubkey1, _from="validator") assert cli.query_e2ee_key(cli.address("validator")) == pubkey0 - cronos.supervisorctl("stop", "cronos_777-1-node0") - cronos.supervisorctl("start", "cronos_777-1-node0") + assert cli1.query_e2ee_key(cli1.address("validator")) == pubkey1 + cronos.supervisorctl("stop", "all") + cronos.supervisorctl("start", "cronos_777-1-node0", "cronos_777-1-node1") wait_for_port(ports.evmrpc_port(cronos.base_port(0))) addr = cli.address("user") @@ -111,11 +115,12 @@ def test_gov_update_params(cronos, tmp_path): cli.encrypt( plainfile, cli.address("validator"), + cli1.address("validator"), output=cipherfile, ) rsp = cli.store_blocklist(cipherfile, from_="validator") assert rsp["code"] == 0, rsp["raw_log"] - wait_for_new_blocks(cli, 4) - rsp = cli.transfer(addr, cli.address("validator"), "1basecro") + wait_for_new_blocks(cli, 2) + rsp = cli.transfer(addr, cli.address("validator"), "1basetcro") assert rsp["code"] != 0 assert "signer is blocked" in rsp["raw_log"]