Skip to content

Commit

Permalink
Add RejectExtensionOptionsDecorator (cosmos#6988)
Browse files Browse the repository at this point in the history
* Add RejectExtensionOptionsDecorator

* Fix error code

* Fix lint

* Add ExtensionOptionsTxBuilder

* Add tests

* Add tests

* Update tests

* Docs

Co-authored-by: sahith-narahari <[email protected]>
Co-authored-by: Alexander Bezobchuk <[email protected]>
  • Loading branch information
3 people authored Aug 18, 2020
1 parent 7f0c3f0 commit 94b3cc5
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 2 deletions.
3 changes: 3 additions & 0 deletions types/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ var (
// explicitly set timeout height.
ErrTxTimeoutHeight = Register(RootCodespace, 30, "tx timeout height")

// ErrUnknownExtensionOptions defines an error for unknown extension options.
ErrUnknownExtensionOptions = Register(RootCodespace, 31, "unknown extension options")

// ErrPanic is only set when we recover from a panic, so we know to
// redact potentially sensitive system info
ErrPanic = Register(UndefinedCodespace, 111222, "panic")
Expand Down
1 change: 1 addition & 0 deletions x/auth/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func NewAnteHandler(
) sdk.AnteHandler {
return sdk.ChainAnteDecorators(
NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
NewRejectExtensionOptionsDecorator(),
NewMempoolFeeDecorator(),
NewValidateBasicDecorator(),
TxTimeoutHeightDecorator{},
Expand Down
36 changes: 36 additions & 0 deletions x/auth/ante/ext.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package ante

import (
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

type HasExtensionOptionsTx interface {
GetExtensionOptions() []*codectypes.Any
GetNonCriticalExtensionOptions() []*codectypes.Any
}

// RejectExtensionOptionsDecorator is an AnteDecorator that rejects all extension
// options which can optionally be included in protobuf transactions. Users that
// need extension options should create a custom AnteHandler chain that handles
// needed extension options properly and rejects unknown ones.
type RejectExtensionOptionsDecorator struct{}

// NewRejectExtensionOptionsDecorator creates a new RejectExtensionOptionsDecorator
func NewRejectExtensionOptionsDecorator() RejectExtensionOptionsDecorator {
return RejectExtensionOptionsDecorator{}
}

var _ types.AnteDecorator = RejectExtensionOptionsDecorator{}

// AnteHandle implements the AnteDecorator.AnteHandle method
func (r RejectExtensionOptionsDecorator) AnteHandle(ctx types.Context, tx types.Tx, simulate bool, next types.AnteHandler) (newCtx types.Context, err error) {
if hasExtOptsTx, ok := tx.(HasExtensionOptionsTx); ok {
if len(hasExtOptsTx.GetExtensionOptions()) != 0 {
return ctx, sdkerrors.ErrUnknownExtensionOptions
}
}

return next(ctx, tx, simulate)
}
36 changes: 36 additions & 0 deletions x/auth/ante/ext_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package ante_test

import (
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
)

func (suite *AnteTestSuite) TestRejectExtensionOptionsDecorator() {
suite.SetupTest(true) // setup
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()

reod := ante.NewRejectExtensionOptionsDecorator()
antehandler := sdk.ChainAnteDecorators(reod)

// no extension options should not trigger an error
theTx := suite.txBuilder.GetTx()
_, err := antehandler(suite.ctx, theTx, false)
suite.Require().NoError(err)

extOptsTxBldr, ok := suite.txBuilder.(tx.ExtensionOptionsTxBuilder)
if !ok {
// if we can't set extension options, this decorator doesn't apply and we're done
return
}

// setting any extension option should cause an error
any, err := types.NewAnyWithValue(testdata.NewTestMsg())
suite.Require().NoError(err)
extOptsTxBldr.SetExtensionOptions(any)
theTx = suite.txBuilder.GetTx()
_, err = antehandler(suite.ctx, theTx, false)
suite.Require().EqualError(err, "unknown extension options")
}
32 changes: 30 additions & 2 deletions x/auth/tx/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
)

Expand All @@ -38,10 +39,19 @@ type builder struct {
}

var (
_ authsigning.Tx = &builder{}
_ client.TxBuilder = &builder{}
_ authsigning.Tx = &builder{}
_ client.TxBuilder = &builder{}
_ ante.HasExtensionOptionsTx = &builder{}
_ ExtensionOptionsTxBuilder = &builder{}
)

type ExtensionOptionsTxBuilder interface {
client.TxBuilder

SetExtensionOptions(...*codectypes.Any)
SetNonCriticalExtensionOptions(...*codectypes.Any)
}

func newBuilder(pubkeyCodec types.PublicKeyCodec) *builder {
return &builder{
tx: &tx.Tx{
Expand Down Expand Up @@ -391,3 +401,21 @@ func (t *builder) setSignatures(sigs [][]byte) {
func (t *builder) GetTx() authsigning.Tx {
return t
}

func (t *builder) GetExtensionOptions() []*codectypes.Any {
return t.tx.Body.ExtensionOptions
}

func (t *builder) GetNonCriticalExtensionOptions() []*codectypes.Any {
return t.tx.Body.NonCriticalExtensionOptions
}

func (t *builder) SetExtensionOptions(extOpts ...*codectypes.Any) {
t.tx.Body.ExtensionOptions = extOpts
t.bodyBz = nil
}

func (t *builder) SetNonCriticalExtensionOptions(extOpts ...*codectypes.Any) {
t.tx.Body.NonCriticalExtensionOptions = extOpts
t.bodyBz = nil
}
7 changes: 7 additions & 0 deletions x/auth/tx/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ func TestTxBuilder(t *testing.T) {
require.Equal(t, 1, len(txBuilder.GetPubKeys()))
require.Equal(t, legacy.Cdc.MustMarshalBinaryBare(pubkey), legacy.Cdc.MustMarshalBinaryBare(txBuilder.GetPubKeys()[0]))

any, err := codectypes.NewAnyWithValue(testdata.NewTestMsg())
require.NoError(t, err)
txBuilder.SetExtensionOptions(any)
require.Equal(t, []*codectypes.Any{any}, txBuilder.GetExtensionOptions())
txBuilder.SetNonCriticalExtensionOptions(any)
require.Equal(t, []*codectypes.Any{any}, txBuilder.GetNonCriticalExtensionOptions())

txBuilder = &builder{}
require.NotPanics(t, func() {
_ = txBuilder.GetMsgs()
Expand Down

0 comments on commit 94b3cc5

Please sign in to comment.