Skip to content

Commit

Permalink
feat: module circuit breaker (#14521)
Browse files Browse the repository at this point in the history
Co-authored-by: Aaron Craelius <aaron@regen.network>
Co-authored-by: Julien Robert <julien@rbrt.fr>
Co-authored-by: Sam Ricotta <samanthalricotta@gmail.com>
Co-authored-by: samricotta <37125168+samricotta@users.noreply.github.com>
Co-authored-by: Facundo Medica <14063057+facundomedica@users.noreply.github.com>
  • Loading branch information
6 people authored May 15, 2023
1 parent d818a62 commit b8e15a7
Show file tree
Hide file tree
Showing 42 changed files with 2,744 additions and 541 deletions.
127 changes: 62 additions & 65 deletions api/cosmos/circuit/v1/query.pulsar.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,12 @@ func (app *BaseApp) setState(mode runTxMode, header cmtproto.Header) {
}
}

// SetCircuitBreaker sets the circuit breaker for the BaseApp.
// The circuit breaker is checked on every message execution to verify if a transaction should be executed or not.
func (app *BaseApp) SetCircuitBreaker(cb CircuitBreaker) {
app.msgServiceRouter.SetCircuit(cb)
}

// GetConsensusParams returns the current consensus parameters from the BaseApp's
// ParamStore. If the BaseApp has no ParamStore defined, nil is returned.
func (app *BaseApp) GetConsensusParams(ctx sdk.Context) cmtproto.ConsensusParams {
Expand Down
10 changes: 10 additions & 0 deletions baseapp/circuit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package baseapp

import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

// CircuitBreaker is an interface that defines the methods for a circuit breaker.
type CircuitBreaker interface {
IsAllowed(ctx sdk.Context, typeURL string) bool
}
12 changes: 12 additions & 0 deletions baseapp/msg_service_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type MessageRouter interface {
type MsgServiceRouter struct {
interfaceRegistry codectypes.InterfaceRegistry
routes map[string]MsgServiceHandler
circuitBreaker CircuitBreaker
}

var _ gogogrpc.Server = &MsgServiceRouter{}
Expand All @@ -37,6 +38,10 @@ func NewMsgServiceRouter() *MsgServiceRouter {
}
}

func (msr *MsgServiceRouter) SetCircuit(cb CircuitBreaker) {
msr.circuitBreaker = cb
}

// MsgServiceHandler defines a function type which handles Msg service message.
type MsgServiceHandler = func(ctx sdk.Context, req sdk.Msg) (*sdk.Result, error)

Expand Down Expand Up @@ -128,6 +133,13 @@ func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler inter
}
}

if msr.circuitBreaker != nil {
msgURL := sdk.MsgTypeURL(msg)
if !msr.circuitBreaker.IsAllowed(ctx, msgURL) {
return nil, fmt.Errorf("circuit breaker disables execution of this message: %s", msgURL)
}
}

// Call the method handler from the service description with the handler object.
// We don't do any decoding here because the decoding was already done.
res, err := methodHandler(handler, ctx, noopDecoder, interceptor)
Expand Down
3 changes: 0 additions & 3 deletions proto/cosmos/circuit/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@ package cosmos.circuit.v1;
option go_package = "cosmossdk.io/x/circuit/types";

import "cosmos/base/query/v1beta1/pagination.proto";
import "cosmos/msg/v1/msg.proto";
import "cosmos/circuit/v1/types.proto";
import "google/api/annotations.proto";
import "cosmos/query/v1/query.proto";

// Msg defines the crisis Msg service.
service Query {
option (cosmos.msg.v1.service) = true;

// Account returns account permissions.
rpc Account(QueryAccountRequest) returns (AccountResponse) {
option (cosmos.query.v1.module_query_safe) = true;
Expand Down
50 changes: 50 additions & 0 deletions simapp/ante.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package simapp

import (
"errors"

circuitante "cosmossdk.io/x/circuit/ante"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
)

// HandlerOptions are the options required for constructing a default SDK AnteHandler.
type HandlerOptions struct {
ante.HandlerOptions
CircuitKeeper circuitante.CircuitBreaker
}

// 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, errors.New("account keeper is required for ante builder")
}

if options.BankKeeper == nil {
return nil, errors.New("bank keeper is required for ante builder")
}

if options.SignModeHandler == nil {
return nil, errors.New("sign mode handler is required for ante builder")
}

anteDecorators := []sdk.AnteDecorator{
ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
circuitante.NewCircuitBreakerDecorator(options.CircuitKeeper),
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
ante.NewValidateBasicDecorator(),
ante.NewTxTimeoutHeightDecorator(),
ante.NewValidateMemoDecorator(options.AccountKeeper),
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
}
Loading

0 comments on commit b8e15a7

Please sign in to comment.