Skip to content

Commit

Permalink
feat: custom ante handler to verify message creator
Browse files Browse the repository at this point in the history
  • Loading branch information
byte-bandit committed Nov 6, 2023
1 parent bed75e4 commit 126af48
Show file tree
Hide file tree
Showing 7 changed files with 432 additions and 15 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
go-version: '1.21.3'
- name: Run tests
run: go test -v ./...
- name: Go lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.51.2
version: v1.55.2
args: --verbose
# Optional: if set to true then the all caching functionality will be complete disabled,
# takes precedence over all other caching options.
Expand Down
13 changes: 12 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@ func New(
app.SetInitChainer(app.InitChainer)
app.SetBeginBlocker(app.BeginBlocker)

anteHandler, err := ante.NewAnteHandler(
baseAnteHandler, err := ante.NewAnteHandler(
ante.HandlerOptions{
AccountKeeper: app.AccountKeeper,
BankKeeper: app.BankKeeper,
Expand All @@ -925,6 +925,17 @@ func New(
if err != nil {
panic(err)
}
anteDecorators := []sdk.AnteDecorator{
palomamodule.NewAnteHandlerDecorator(baseAnteHandler),
}
anteDecorators = append(anteDecorators,
palomamodule.NewLogMsgDecorator(app.appCodec),
palomamodule.NewVerifyAuthorisedSignatureDecorator(app.FeeGrantKeeper),
)

anteHandler := sdk.ChainAnteDecorators(
anteDecorators...,
)

app.SetAnteHandler(anteHandler)
app.SetEndBlocker(app.EndBlocker)
Expand Down
6 changes: 3 additions & 3 deletions util/libmeta/get_signers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func Test_GetSigners(t *testing.T) {
}{
{
name: "with one valid signer",
signers: []string{sdk.AccAddress("addres-1").String()},
signers: []string{sdk.AccAddress("address-1").String()},
creator: "",
panics: false,
},
Expand All @@ -53,13 +53,13 @@ func Test_GetSigners(t *testing.T) {
},
{
name: "with multiple valid signers",
signers: []string{sdk.AccAddress("addres-1").String(), sdk.AccAddress("addres-2").String(), sdk.AccAddress("addres-3").String()},
signers: []string{sdk.AccAddress("address-1").String(), sdk.AccAddress("address-2").String(), sdk.AccAddress("address-3").String()},
creator: "",
panics: false,
},
{
name: "with an invalid signer among multiple valid signers",
signers: []string{"foo", sdk.AccAddress("addres-2").String(), sdk.AccAddress("addres-3").String()},
signers: []string{"foo", sdk.AccAddress("address-2").String(), sdk.AccAddress("address-3").String()},
creator: "",
panics: true,
},
Expand Down
18 changes: 9 additions & 9 deletions util/libmeta/validate_basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,37 @@ func Test_GetValidateBasic(t *testing.T) {
{
name: "with missing signers",
signers: []string{},
creator: sdk.AccAddress("addres-1").String(),
creator: sdk.AccAddress("address-1").String(),
errors: true,
},
{
name: "with one valid signer and creator",
signers: []string{sdk.AccAddress("addres-1").String()},
creator: sdk.AccAddress("addres-1").String(),
signers: []string{sdk.AccAddress("address-1").String()},
creator: sdk.AccAddress("address-1").String(),
errors: false,
},
{
name: "with one valid signer and invalid creator",
signers: []string{sdk.AccAddress("addres-1").String()},
signers: []string{sdk.AccAddress("address-1").String()},
creator: "foo",
errors: true,
},
{
name: "with multiple valid signers and creator",
signers: []string{sdk.AccAddress("addres-1").String(), sdk.AccAddress("addres-2").String(), sdk.AccAddress("addres-3").String()},
creator: sdk.AccAddress("addres-1").String(),
signers: []string{sdk.AccAddress("address-1").String(), sdk.AccAddress("address-2").String(), sdk.AccAddress("address-3").String()},
creator: sdk.AccAddress("address-1").String(),
errors: false,
},
{
name: "with multiple valid signers and invalid creator",
signers: []string{sdk.AccAddress("addres-1").String(), sdk.AccAddress("addres-2").String(), sdk.AccAddress("addres-3").String()},
signers: []string{sdk.AccAddress("address-1").String(), sdk.AccAddress("address-2").String(), sdk.AccAddress("address-3").String()},
creator: "foo",
errors: true,
},
{
name: "with faulty signer among multiple valid signers and creator",
signers: []string{sdk.AccAddress("addres-1").String(), "foo", sdk.AccAddress("addres-3").String()},
creator: sdk.AccAddress("addres-1").String(),
signers: []string{sdk.AccAddress("address-1").String(), "foo", sdk.AccAddress("address-3").String()},
creator: sdk.AccAddress("address-1").String(),
errors: true,
},
} {
Expand Down
142 changes: 142 additions & 0 deletions x/paloma/ante.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package paloma

import (
"fmt"

"github.com/cometbft/cometbft/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/feegrant"
"github.com/gogo/protobuf/proto"
"github.com/palomachain/paloma/util/libmeta"
"github.com/palomachain/paloma/x/paloma/types"
vtypes "github.com/palomachain/paloma/x/valset/types"
)

func logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
}

// HandlerDecorator is an ante decorator wrapper for an ante handler
type HandlerDecorator struct {
handler sdk.AnteHandler
}

// NewAnteHandlerDecorator constructor for HandlerDecorator
func NewAnteHandlerDecorator(handler sdk.AnteHandler) HandlerDecorator {
return HandlerDecorator{handler}
}

// AnteHandle wraps the next AnteHandler to perform custom pre- and post-processing
func (decorator HandlerDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if newCtx, err = decorator.handler(ctx, tx, simulate); err != nil {
return newCtx, err
}

return next(newCtx, tx, simulate)
}

// LogMsgDecorator logs all messages in blocks
type LogMsgDecorator struct {
cdc codec.Codec
}

// NewLogMsgDecorator is the constructor for LogMsgDecorator
func NewLogMsgDecorator(cdc codec.Codec) LogMsgDecorator {
return LogMsgDecorator{cdc: cdc}
}

// AnteHandle logs all messages in blocks
func (d LogMsgDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
if simulate || ctx.IsCheckTx() {
return next(ctx, tx, simulate)
}

msgs := tx.GetMsgs()

for _, msg := range msgs {
logger(ctx).Debug(fmt.Sprintf("received message of type %s in block %d: %s",
proto.MessageName(msg),
ctx.BlockHeight(),
string(d.cdc.MustMarshalJSON(msg)),
))
}

return next(ctx, tx, simulate)
}

// VerifyAuthorisedSignatureDecorator verifies that the message is signed by at least one signature that has
// active fee grant from the creator address, IF it contains metadata.
type VerifyAuthorisedSignatureDecorator struct {
fk types.FeegrantKeeper
}

func NewVerifyAuthorisedSignatureDecorator(fk types.FeegrantKeeper) VerifyAuthorisedSignatureDecorator {
return VerifyAuthorisedSignatureDecorator{fk: fk}
}

// AnteHandle verifies that the message is signed by at least one signature that has
// active fee grant from the creator address, IF the message contains metadata.
func (d VerifyAuthorisedSignatureDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
if simulate || ctx.IsCheckTx() {
return next(ctx, tx, simulate)
}

for _, msg := range tx.GetMsgs() {
m, ok := msg.(libmeta.MsgWithMetadata[vtypes.MsgMetadata])
if !ok {
logger(ctx).Debug(fmt.Sprintf("msg %s does not contain metadata. skipping ownership verification...", proto.MessageName(msg)))
continue
}

creator := m.GetMetadata().GetCreator()
signers := msg.GetSigners()

signedByCreator := func() bool {
for _, v := range signers {
if v.String() == creator {
return true
}
}
return false
}()
if signedByCreator {
logger(ctx).Debug(fmt.Sprintf("msg %s was signed by creator.", proto.MessageName(msg)))
continue
}

grants, err := d.fk.AllowancesByGranter(ctx, &feegrant.QueryAllowancesByGranterRequest{
Granter: creator,
})
if err != nil {
return ctx, fmt.Errorf("failed to verify message signature authorisation: %w", err)
}

logger(ctx).Debug(fmt.Sprintf("got %d allowances from granter %s", len(grants.GetAllowances()), creator))
grantsLkUp := map[string]feegrant.Grant{}
for _, v := range grants.GetAllowances() {
if v == nil {
continue
}

grantsLkUp[v.GetGrantee()] = *v
}

logger(ctx).Debug("grant lookup built", "map", grantsLkUp)
grantees := make([]string, 0, len(signers))
for _, signer := range signers {
if v, found := grantsLkUp[signer.String()]; found {
logger(ctx).Debug("found granted signature", "signature", v.Grantee)
grantees = append(grantees, v.Grantee)
}
}

if len(grantees) < 1 {
return ctx, fmt.Errorf("no signature from granted address found for message %s", proto.MessageName(msg))
}

logger(ctx).Debug(fmt.Sprintf("found total of %d signatures from granted addresses for message %s", len(grantees), proto.MessageName(msg)))
}

return next(ctx, tx, simulate)
}
Loading

0 comments on commit 126af48

Please sign in to comment.