Add custom ante handler (#76)

* add initial custom ante handler
* implement CheckMachineDecorator.AnteHandle
* add machine error code
* add TA check to antehandler
* change machine error codes

---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
This commit is contained in:
Lorenz Herzberger 2023-09-20 16:27:16 +02:00 committed by GitHub
parent 2a09f9d90d
commit 56ad4822d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 173 additions and 15 deletions

105
app/ante/ante.go Normal file
View File

@ -0,0 +1,105 @@
package ante
import (
assettypes "planetmint-go/x/asset/types"
machinetypes "planetmint-go/x/machine/types"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
ante "github.com/cosmos/cosmos-sdk/x/auth/ante"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
type CheckMachineDecorator struct {
mk MachineKeeper
}
func NewCheckMachineDecorator(mk MachineKeeper) CheckMachineDecorator {
return CheckMachineDecorator{
mk: mk,
}
}
func (cm CheckMachineDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
for _, msg := range tx.GetMsgs() {
switch sdk.MsgTypeURL(msg) {
case "/planetmintgo.asset.MsgNotarizeAsset":
notarizeMsg, ok := msg.(*assettypes.MsgNotarizeAsset)
if ok {
_, found := cm.mk.GetMachineIndex(ctx, notarizeMsg.PubKey)
if !found {
return ctx, errorsmod.Wrapf(machinetypes.ErrMachineNotFound, "error during CheckTx or ReCheckTx")
}
}
case "/planetmintgo.machine.MsgAttestMachine":
attestMsg, ok := msg.(*machinetypes.MsgAttestMachine)
if ok {
_, activated, found := cm.mk.GetTrustAnchor(ctx, attestMsg.Machine.MachineId)
if !found {
return ctx, errorsmod.Wrapf(machinetypes.ErrTrustAnchorNotFound, "error during CheckTx or ReCheckTx")
}
if activated {
return ctx, errorsmod.Wrapf(machinetypes.ErrTrustAnchorAlreadyInUse, "error during CheckTx or ReCheckTx")
}
}
default:
continue
}
}
return next(ctx, tx, simulate)
}
// HandlerOptions are the options required for constructing a default SDK AnteHandler.
type HandlerOptions struct {
AccountKeeper AccountKeeper
BankKeeper BankKeeper
ExtensionOptionChecker ante.ExtensionOptionChecker
FeegrantKeeper FeegrantKeeper
SignModeHandler authsigning.SignModeHandler
SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params) error
TxFeeChecker ante.TxFeeChecker
MachineKeeper MachineKeeper
}
// NewAnteHandler returns an AnteHandler that checks and increments sequence
// numbers, checks signatures & account numbers, and deducts fees from the first
// signer.
func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
if options.AccountKeeper == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "account keeper is required for ante builder")
}
if options.BankKeeper == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "bank keeper is required for ante builder")
}
if options.SignModeHandler == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder")
}
if options.MachineKeeper == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "machine keeper is required for ante builder")
}
anteDecorators := []sdk.AnteDecorator{
ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
ante.NewValidateBasicDecorator(),
ante.NewTxTimeoutHeightDecorator(),
ante.NewValidateMemoDecorator(options.AccountKeeper),
NewCheckMachineDecorator(options.MachineKeeper),
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
ante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators
ante.NewValidateSigCountDecorator(options.AccountKeeper),
ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer),
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
}
return sdk.ChainAnteDecorators(anteDecorators...), nil
}

View File

@ -0,0 +1,33 @@
package ante
import (
"planetmint-go/x/machine/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
type MachineKeeper interface {
GetMachineIndex(ctx sdk.Context, pubKey string) (val types.MachineIndex, found bool)
GetTrustAnchor(ctx sdk.Context, pubKey string) (val types.TrustAnchor, activated bool, found bool)
}
// AccountKeeper defines the contract needed for AccountKeeper related APIs.
// Interface provides support to use non-sdk AccountKeeper for AnteHandler's decorators.
type AccountKeeper interface {
GetParams(ctx sdk.Context) (params authtypes.Params)
GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI
SetAccount(ctx sdk.Context, acc authtypes.AccountI)
GetModuleAddress(moduleName string) sdk.AccAddress
}
// FeegrantKeeper defines the expected feegrant keeper.
type FeegrantKeeper interface {
UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error
}
type BankKeeper interface {
IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error
SendCoins(ctx sdk.Context, from, to sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
}

View File

@ -123,6 +123,7 @@ import (
// this line is used by starport scaffolding # stargate/app/moduleImport
pmante "planetmint-go/app/ante"
appparams "planetmint-go/app/params"
"planetmint-go/docs"
)
@ -763,13 +764,14 @@ func New(
app.MountMemoryStores(memKeys)
// initialize BaseApp
anteHandler, err := ante.NewAnteHandler(
ante.HandlerOptions{
anteHandler, err := pmante.NewAnteHandler(
pmante.HandlerOptions{
AccountKeeper: app.AccountKeeper,
BankKeeper: app.BankKeeper,
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
FeegrantKeeper: app.FeeGrantKeeper,
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
MachineKeeper: app.MachineKeeper,
},
)
if err != nil {

View File

@ -31,9 +31,10 @@ func (s *E2ETestSuite) TestNotarizeAssetREST() {
cid, signatureHex := sample.Asset(sk)
testCases := []struct {
name string
msg assettypes.MsgNotarizeAsset
rawLog string
name string
msg assettypes.MsgNotarizeAsset
rawLog string
expectCheckTxErr bool
}{
{
"machine not found",
@ -44,6 +45,7 @@ func (s *E2ETestSuite) TestNotarizeAssetREST() {
PubKey: "human pubkey",
},
"machine not found",
true,
},
{
"invalid signature hex string",
@ -64,6 +66,7 @@ func (s *E2ETestSuite) TestNotarizeAssetREST() {
PubKey: xPubKey,
},
"invalid signature",
false,
},
{
"valid notarization",
@ -74,6 +77,7 @@ func (s *E2ETestSuite) TestNotarizeAssetREST() {
PubKey: xPubKey,
},
"planetmintgo.asset.MsgNotarizeAsset",
false,
},
}
@ -91,9 +95,13 @@ func (s *E2ETestSuite) TestNotarizeAssetREST() {
tx, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", val.APIAddress, broadcastTxResponse.TxResponse.TxHash))
s.Require().NoError(err)
var txRes txtypes.GetTxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(tx, &txRes)
s.Require().NoError(err)
s.Require().Contains(txRes.TxResponse.RawLog, tc.rawLog)
if !tc.expectCheckTxErr {
var txRes txtypes.GetTxResponse
err = val.ClientCtx.Codec.UnmarshalJSON(tx, &txRes)
s.Require().NoError(err)
s.Require().Contains(txRes.TxResponse.RawLog, tc.rawLog)
} else {
s.Require().Contains(broadcastTxResponse.TxResponse.RawLog, tc.rawLog)
}
}
}

View File

@ -134,9 +134,10 @@ func (s *E2ETestSuite) TestNotarizeAsset() {
cid, signatureHex := sample.Asset(sk)
testCases := []struct {
name string
args []string
rawLog string
name string
args []string
rawLog string
expectCheckTxErr bool
}{
{
"machine not found",
@ -149,6 +150,7 @@ func (s *E2ETestSuite) TestNotarizeAsset() {
"--yes",
},
"machine not found",
true,
},
{
"invalid signature hex string",
@ -173,6 +175,7 @@ func (s *E2ETestSuite) TestNotarizeAsset() {
"--yes",
},
"invalid signature",
false,
},
{
"valid notarization",
@ -185,6 +188,7 @@ func (s *E2ETestSuite) TestNotarizeAsset() {
"--yes",
},
"planetmintgo.asset.MsgNotarizeAsset",
false,
},
}
@ -197,8 +201,12 @@ func (s *E2ETestSuite) TestNotarizeAsset() {
s.Require().NoError(s.network.WaitForNextBlock())
rawLog, err := clitestutil.GetRawLogFromTxResponse(val, txResponse)
s.Require().NoError(err)
assert.Contains(s.T(), rawLog, tc.rawLog)
if !tc.expectCheckTxErr {
s.Require().NoError(err)
assert.Contains(s.T(), rawLog, tc.rawLog)
} else {
assert.Contains(s.T(), txResponse.RawLog, tc.rawLog)
}
}
}

View File

@ -8,5 +8,7 @@ import (
// x/machine module sentinel errors
var (
ErrSample = errorsmod.Register(ModuleName, 1100, "sample error")
ErrMachineNotFound = errorsmod.Register(ModuleName, 2, "machine not found")
ErrTrustAnchorNotFound = errorsmod.Register(ModuleName, 3, "trust anchor not found")
ErrTrustAnchorAlreadyInUse = errorsmod.Register(ModuleName, 4, "trust anchor already in use")
)