From f3d96d9b9bda2930a7e82dc79b0118ac58531920 Mon Sep 17 00:00:00 2001 From: yihuang Date: Tue, 30 Apr 2024 16:25:29 +0800 Subject: [PATCH] proposal handler --- app/app.go | 22 ++++++++++- app/proposal.go | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 app/proposal.go diff --git a/app/app.go b/app/app.go index 61bcf54f00..db71162c32 100644 --- a/app/app.go +++ b/app/app.go @@ -15,6 +15,7 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" + "filippo.io/age" runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" "golang.org/x/exp/slices" @@ -123,6 +124,7 @@ import ( icaauthkeeper "github.com/crypto-org-chain/cronos/v2/x/icaauth/keeper" icaauthtypes "github.com/crypto-org-chain/cronos/v2/x/icaauth/types" + clientflags "github.com/cosmos/cosmos-sdk/client/flags" evmante "github.com/evmos/ethermint/app/ante" srvflags "github.com/evmos/ethermint/server/flags" ethermint "github.com/evmos/ethermint/types" @@ -161,6 +163,7 @@ import ( e2ee "github.com/crypto-org-chain/cronos/v2/x/e2ee" e2eekeeper "github.com/crypto-org-chain/cronos/v2/x/e2ee/keeper" + e2eekeyring "github.com/crypto-org-chain/cronos/v2/x/e2ee/keyring" e2eetypes "github.com/crypto-org-chain/cronos/v2/x/e2ee/types" // force register the extension json-rpc. @@ -395,13 +398,30 @@ func New( cdc := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry + var identity age.Identity + { + krBackend := cast.ToString(appOpts.Get(clientflags.FlagKeyringBackend)) + kr, err := e2eekeyring.New("cronosd", krBackend, homePath, os.Stdin) + if err != nil { + panic(err) + } + key, err := kr.Get(e2eetypes.DefaultKeyringName) + if err != nil { + panic(err) + } + identity, err = age.ParseX25519Identity(string(key)) + if err != nil { + panic(err) + } + } + baseAppOptions = memiavlstore.SetupMemIAVL(logger, homePath, appOpts, false, false, baseAppOptions) // 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) { mempool := mempool.NoOpMempool{} app.SetMempool(mempool) - handler := baseapp.NewDefaultProposalHandler(mempool, app) + handler := NewProposalHandler(encodingConfig.TxConfig.TxDecoder(), identity) app.SetPrepareProposal(handler.PrepareProposalHandler()) app.SetProcessProposal(handler.ProcessProposalHandler()) }) diff --git a/app/proposal.go b/app/proposal.go new file mode 100644 index 0000000000..a7aa319cf7 --- /dev/null +++ b/app/proposal.go @@ -0,0 +1,103 @@ +package app + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + + "filippo.io/age" + + abci "github.com/cometbft/cometbft/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/signing" +) + +type BlockList struct { + Addresses []string `mapstructure:"addresses"` +} + +type ProposalHandler struct { + txDecoder sdk.TxDecoder + identity age.Identity + blocklist map[string]struct{} +} + +func NewProposalHandler(txDecoder sdk.TxDecoder, identity age.Identity) *ProposalHandler { + return &ProposalHandler{ + txDecoder: txDecoder, + identity: identity, + blocklist: make(map[string]struct{}), + } +} + +func (h *ProposalHandler) SetBlockList(blob []byte) error { + 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[string(addr)] = struct{}{} + } + + h.blocklist = m + return nil +} + +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) + } + + for _, signer := range sigTx.GetSigners() { + if _, ok := h.blocklist[string(signer)]; ok { + return fmt.Errorf("signer is blocked: %s", sdk.AccAddress(signer).String()) + } + } + } + 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) + } + + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT} + } +}