From 2534828fc64e805d859b9ce2254a06bb5ed37f3f Mon Sep 17 00:00:00 2001 From: Lorenz Herzberger <64837895+LaurentMontBlanc@users.noreply.github.com> Date: Thu, 11 Jan 2024 14:33:20 +0100 Subject: [PATCH] =?UTF-8?q?feature:=20add=20ante=20handler=20to=20block=20?= =?UTF-8?q?non=20validators=20from=20sending=20restri=E2=80=A6=20(#273)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feature: add ante handler to block non validators from sending restricted txs * fix: add missing msg types and linter errors * fix: staticcheck error * refactor: use fallthrough on ante handle switch * fix: set val address on machine attest test --------- Signed-off-by: Lorenz Herzberger --- app/ante/ante.go | 1 + app/ante/check_validator_decorator.go | 57 ++++++++ tests/e2e/dao/cli_test.go | 5 + tests/e2e/dao/gas_consumption_suite.go | 2 +- .../dao/pop_participant_selection_suite.go | 3 +- tests/e2e/dao/restricted_msgs_suite.go | 122 ++++++++++++++++++ tests/e2e/machine/rest.go | 4 +- testutil/sample/sample.go | 3 + x/dao/types/errors.go | 1 + 9 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 app/ante/check_validator_decorator.go create mode 100644 tests/e2e/dao/restricted_msgs_suite.go diff --git a/app/ante/ante.go b/app/ante/ante.go index f5b0b79..78355a7 100644 --- a/app/ante/ante.go +++ b/app/ante/ante.go @@ -57,6 +57,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewValidateBasicDecorator(), ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), + NewCheckValidatorDecorator(options.StakingKeeper), NewCheckMachineDecorator(options.MachineKeeper), NewCheckMintAddressDecorator(options.DaoKeeper), NewCheckReissuanceDecorator(options.DaoKeeper), diff --git a/app/ante/check_validator_decorator.go b/app/ante/check_validator_decorator.go new file mode 100644 index 0000000..369c1e5 --- /dev/null +++ b/app/ante/check_validator_decorator.go @@ -0,0 +1,57 @@ +package ante + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/planetmint/planetmint-go/x/dao/types" +) + +type CheckValidatorDecorator struct { + sk StakingKeeper +} + +func NewCheckValidatorDecorator(sk StakingKeeper) CheckValidatorDecorator { + return CheckValidatorDecorator{sk: sk} +} + +func (cv CheckValidatorDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (_ sdk.Context, err error) { + if simulate || ctx.BlockHeight() == 0 { + return next(ctx, tx, simulate) + } + + for _, msg := range tx.GetMsgs() { + switch sdk.MsgTypeURL(msg) { + case "/planetmintgo.dao.MsgInitPop": + fallthrough + case "/planetmintgo.dao.MsgDistributionRequest": + fallthrough + case "/planetmintgo.dao.MsgDistributionResult": + fallthrough + case "/planetmintgo.dao.MsgReissueRDDLProposal": + fallthrough + case "/planetmintgo.dao.MsgReissueRDDLResult": + fallthrough + case "/planetmintgo.machine.MsgNotarizeLiquidAsset": + fallthrough + case "/planetmintgo.machine.MsgRegisterTrustAnchor": + ctx, err = cv.handleMsg(ctx, msg) + default: + continue + } + } + + if err != nil { + return ctx, err + } + + return next(ctx, tx, simulate) +} + +func (cv CheckValidatorDecorator) handleMsg(ctx sdk.Context, msg sdk.Msg) (_ sdk.Context, err error) { + signer := msg.GetSigners()[0] + _, found := cv.sk.GetValidator(ctx, sdk.ValAddress(signer)) + if !found { + return ctx, errorsmod.Wrapf(types.ErrRestrictedMsg, "error during CheckTx or ReCheckTx") + } + return ctx, nil +} diff --git a/tests/e2e/dao/cli_test.go b/tests/e2e/dao/cli_test.go index 250a190..4aee59b 100644 --- a/tests/e2e/dao/cli_test.go +++ b/tests/e2e/dao/cli_test.go @@ -22,3 +22,8 @@ func TestGasConsumptionE2ETestSuite(t *testing.T) { cfg := network.DefaultConfig() suite.Run(t, NewGasConsumptionE2ETestSuite(cfg)) } + +func TestRestrictedMsgsE2ETestSuite(t *testing.T) { + cfg := network.DefaultConfig() + suite.Run(t, NewRestrictedMsgsE2ESuite(cfg)) +} diff --git a/tests/e2e/dao/gas_consumption_suite.go b/tests/e2e/dao/gas_consumption_suite.go index 50bc891..581cfdb 100644 --- a/tests/e2e/dao/gas_consumption_suite.go +++ b/tests/e2e/dao/gas_consumption_suite.go @@ -27,7 +27,7 @@ func NewGasConsumptionE2ETestSuite(cfg network.Config) *GasConsumptionE2ETestSui func (s *GasConsumptionE2ETestSuite) SetupSuite() { s.T().Log("setting up e2e test suite") conf := config.GetConfig() - conf.FeeDenom = "stake" + conf.FeeDenom = sample.FeeDenom s.network = network.New(s.T(), s.cfg) account, err := e2etestutil.CreateAccount(s.network, sample.Name, sample.Mnemonic) s.Require().NoError(err) diff --git a/tests/e2e/dao/pop_participant_selection_suite.go b/tests/e2e/dao/pop_participant_selection_suite.go index 0826cda..a6d1cc0 100644 --- a/tests/e2e/dao/pop_participant_selection_suite.go +++ b/tests/e2e/dao/pop_participant_selection_suite.go @@ -7,6 +7,7 @@ import ( clitestutil "github.com/planetmint/planetmint-go/testutil/cli" e2etestutil "github.com/planetmint/planetmint-go/testutil/e2e" "github.com/planetmint/planetmint-go/testutil/network" + "github.com/planetmint/planetmint-go/testutil/sample" daocli "github.com/planetmint/planetmint-go/x/dao/client/cli" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" @@ -43,7 +44,7 @@ func NewPopSelectionE2ETestSuite(cfg network.Config) *PopSelectionE2ETestSuite { func (s *PopSelectionE2ETestSuite) SetupSuite() { s.T().Log("setting up e2e test suite") conf := config.GetConfig() - conf.FeeDenom = "stake" + conf.FeeDenom = sample.FeeDenom s.network = network.New(s.T(), s.cfg) diff --git a/tests/e2e/dao/restricted_msgs_suite.go b/tests/e2e/dao/restricted_msgs_suite.go new file mode 100644 index 0000000..14c2f27 --- /dev/null +++ b/tests/e2e/dao/restricted_msgs_suite.go @@ -0,0 +1,122 @@ +package dao + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/planetmint/planetmint-go/config" + "github.com/planetmint/planetmint-go/lib" + e2etestutil "github.com/planetmint/planetmint-go/testutil/e2e" + "github.com/planetmint/planetmint-go/testutil/network" + "github.com/planetmint/planetmint-go/testutil/sample" + daotypes "github.com/planetmint/planetmint-go/x/dao/types" + machinetypes "github.com/planetmint/planetmint-go/x/machine/types" + "github.com/stretchr/testify/suite" +) + +var msgs = []sdk.Msg{ + &daotypes.MsgInitPop{}, + &daotypes.MsgDistributionRequest{}, + &daotypes.MsgDistributionResult{}, + &daotypes.MsgReissueRDDLProposal{}, + &daotypes.MsgReissueRDDLResult{}, + &machinetypes.MsgRegisterTrustAnchor{}, + &machinetypes.MsgNotarizeLiquidAsset{}, +} + +type RestrictedMsgsE2ESuite struct { + suite.Suite + + cfg network.Config + network *network.Network +} + +func NewRestrictedMsgsE2ESuite(cfg network.Config) *RestrictedMsgsE2ESuite { + return &RestrictedMsgsE2ESuite{cfg: cfg} +} + +func (s *RestrictedMsgsE2ESuite) SetupSuite() { + s.T().Log("setting up e2e test suite") + conf := config.GetConfig() + conf.FeeDenom = sample.FeeDenom + + s.network = network.New(s.T(), s.cfg) + account, err := e2etestutil.CreateAccount(s.network, sample.Name, sample.Mnemonic) + s.Require().NoError(err) + err = e2etestutil.FundAccount(s.network, account) + s.Require().NoError(err) +} + +func (s *RestrictedMsgsE2ESuite) TearDownSuite() { + s.T().Log("tearing down e2e test suite") +} + +func (s *RestrictedMsgsE2ESuite) TestRestrictedMsgsValidator() { + val := s.network.Validators[0] + + msg := daotypes.NewMsgInitPop(val.Address.String(), val.Address.String(), val.Address.String(), val.Address.String(), 0) + out, err := lib.BroadcastTxWithFileLock(val.Address, msg) + s.Require().NoError(err) + + txResponse, err := lib.GetTxResponseFromOut(out) + s.Require().NoError(err) + s.Require().Equal(int(0), int(txResponse.Code)) +} + +func (s *RestrictedMsgsE2ESuite) TestRestrictedMsgsNonValidator() { + val := s.network.Validators[0] + + k, err := val.ClientCtx.Keyring.Key(sample.Name) + s.Require().NoError(err) + addr, _ := k.GetAddress() + + for _, msg := range msgs { + msg = setCreator(msg, addr.String()) + out, err := lib.BroadcastTxWithFileLock(addr, msg) + s.Require().NoError(err) + + txResponse, err := lib.GetTxResponseFromOut(out) + s.Require().NoError(err) + s.Require().Equal(int(18), int(txResponse.Code)) + s.Require().NoError(s.network.WaitForNextBlock()) + } +} + +func setCreator(msg sdk.Msg, creator string) sdk.Msg { + switch sdk.MsgTypeURL(msg) { + case "/planetmintgo.dao.MsgInitPop": + msg, ok := msg.(*daotypes.MsgInitPop) + if ok { + msg.Creator = creator + } + case "/planetmintgo.dao.MsgDistributionRequest": + msg, ok := msg.(*daotypes.MsgDistributionRequest) + if ok { + msg.Creator = creator + } + case "/planetmintgo.dao.MsgDistributionResult": + msg, ok := msg.(*daotypes.MsgDistributionResult) + if ok { + msg.Creator = creator + } + case "/planetmintgo.dao.MsgReissueRDDLProposal": + msg, ok := msg.(*daotypes.MsgReissueRDDLProposal) + if ok { + msg.Creator = creator + } + case "/planetmintgo.dao.MsgReissueRDDLResult": + msg, ok := msg.(*daotypes.MsgReissueRDDLResult) + if ok { + msg.Creator = creator + } + case "/planetmintgo.machine.MsgNotarizeLiquidAsset": + msg, ok := msg.(*machinetypes.MsgNotarizeLiquidAsset) + if ok { + msg.Creator = creator + } + case "/planetmintgo.machine.MsgRegisterTrustAnchor": + msg, ok := msg.(*machinetypes.MsgRegisterTrustAnchor) + if ok { + msg.Creator = creator + } + } + return msg +} diff --git a/tests/e2e/machine/rest.go b/tests/e2e/machine/rest.go index 0bc49a1..2be01e2 100644 --- a/tests/e2e/machine/rest.go +++ b/tests/e2e/machine/rest.go @@ -64,10 +64,10 @@ func (s *RestE2ETestSuite) TestAttestMachineREST() { // Register TA ta := sample.TrustAnchor(pubKey) taMsg := machinetypes.MsgRegisterTrustAnchor{ - Creator: addr.String(), + Creator: val.Address.String(), TrustAnchor: &ta, } - out, err := e2etestutil.BuildSignBroadcastTx(s.T(), addr, &taMsg) + out, err := e2etestutil.BuildSignBroadcastTx(s.T(), val.Address, &taMsg) s.Require().NoError(err) s.Require().NoError(s.network.WaitForNextBlock()) diff --git a/testutil/sample/sample.go b/testutil/sample/sample.go index 0592733..b9a3365 100644 --- a/testutil/sample/sample.go +++ b/testutil/sample/sample.go @@ -32,6 +32,9 @@ const Amount = "1000stake" // Fees is the amount of fees to use in tests const Fees = "1stake" +// FeeDenom is the fee denomination for e2e test cases +const FeeDenom = "stake" + // DefaultDerivationPath is the BIP44Prefix for PLMNT (see https://github.com/satoshilabs/slips/blob/master/slip-0044.md) const DefaultDerivationPath = "m/44'/8680'/0'/0/0" diff --git a/x/dao/types/errors.go b/x/dao/types/errors.go index a681c87..779ff03 100644 --- a/x/dao/types/errors.go +++ b/x/dao/types/errors.go @@ -24,4 +24,5 @@ var ( ErrFailedPoPRewardsIssuance = errorsmod.Register(ModuleName, 15, "PoP rewards issuance failed") ErrResolvingStagedClaims = errorsmod.Register(ModuleName, 16, "resolving staged claims failed") ErrReissuanceTxIDMissing = errorsmod.Register(ModuleName, 17, "reissuance has no transaction id") + ErrRestrictedMsg = errorsmod.Register(ModuleName, 18, "restricted validator msg") )