Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rate limiter #94

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ $(BIN)/%: | $(BIN) ; $(info $(M) installing $(REPOSITORY)…)

GOLANGCILINT = $(BIN)/golangci-lint
$(BIN)/golangci-lint:
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin v1.53.3
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin v1.55.2

GENTOOL = $(BIN)/gentool
$(BIN)/gentool: REPOSITORY=gorm.io/gen/tools/gentool@latest
Expand Down
36 changes: 35 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ import (
sequencerproposal "github.com/warp-contracts/sequencer/x/sequencer/proposal"
sequencermoduletypes "github.com/warp-contracts/sequencer/x/sequencer/types"

limitermodule "github.com/warp-contracts/sequencer/x/limiter"
limitermodulekeeper "github.com/warp-contracts/sequencer/x/limiter/keeper"
limitermoduletypes "github.com/warp-contracts/sequencer/x/limiter/types"

appconfig "github.com/warp-contracts/sequencer/app/config"
// this line is used by starport scaffolding # stargate/app/moduleImport

appparams "github.com/warp-contracts/sequencer/app/params"
Expand Down Expand Up @@ -152,6 +157,7 @@ var (
vesting.AppModuleBasic{},
consensus.AppModuleBasic{},
sequencermodule.AppModuleBasic{},
limitermodule.AppModuleBasic{},
// this line is used by starport scaffolding # stargate/app/moduleBasic
)

Expand Down Expand Up @@ -217,6 +223,7 @@ type App struct {
GroupKeeper groupkeeper.Keeper
ConsensusParamsKeeper consensusparamkeeper.Keeper
SequencerKeeper sequencermodulekeeper.Keeper
LimiterKeeper limitermodulekeeper.Keeper

// Tasks
ArweaveBlocksController controller.ArweaveBlocksController
Expand All @@ -233,6 +240,9 @@ type App struct {
configurator module.Configurator

BlockInteractions *sequencerante.BlockInteractions

// Custom app configuration
Config *appconfig.Config
}

// New returns a reference to an initialized blockchain app
Expand Down Expand Up @@ -272,6 +282,7 @@ func New(
govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey,
feegrant.StoreKey, evidencetypes.StoreKey, capabilitytypes.StoreKey, group.StoreKey,
consensusparamtypes.StoreKey, sequencermoduletypes.StoreKey,
limitermoduletypes.StoreKey,
// this line is used by starport scaffolding # stargate/app/storeKey
)
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey)
Expand All @@ -289,6 +300,12 @@ func New(
memKeys: memKeys,
}

// Custom App configuration
app.Config, err = appconfig.Load(homePath + "/config.json")
if err != nil {
panic(err)
}

app.ParamsKeeper = initParamsKeeper(
appCodec,
cdc,
Expand Down Expand Up @@ -445,11 +462,22 @@ func New(
),
)

app.LimiterKeeper = *limitermodulekeeper.NewKeeper(
appCodec,
keys[limitermoduletypes.StoreKey],
keys[limitermoduletypes.MemStoreKey],
app.GetSubspace(limitermoduletypes.ModuleName),
1, /* Number of limiters, indexed from 0 */
int64(app.Config.RateLimiter.NumberOfMonitoredBlocks), /* Number of blocks to keep in the cache */
)
limiterModule := limitermodule.NewAppModule(appCodec, app.LimiterKeeper, app.AccountKeeper, app.BankKeeper)

app.SequencerKeeper = *sequencermodulekeeper.NewKeeper(
appCodec,
keys[sequencermoduletypes.StoreKey],
keys[sequencermoduletypes.MemStoreKey],
app.GetSubspace(sequencermoduletypes.ModuleName),
app.LimiterKeeper,
)

genesisLoader := sequencermodule.NewGenesisLoader(logger, homePath)
Expand Down Expand Up @@ -521,6 +549,7 @@ func New(
consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper),
params.NewAppModule(app.ParamsKeeper),
sequencerModule,
limiterModule,
// this line is used by starport scaffolding # stargate/app/appModule

crisis.NewAppModule(app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), // always be last to make sure that it checks for all invariants and not only part of them
Expand Down Expand Up @@ -551,6 +580,7 @@ func New(
vestingtypes.ModuleName,
consensusparamtypes.ModuleName,
sequencermoduletypes.ModuleName,
limitermoduletypes.ModuleName,
// this line is used by starport scaffolding # stargate/app/beginBlockers
)

Expand All @@ -574,6 +604,7 @@ func New(
vestingtypes.ModuleName,
consensusparamtypes.ModuleName,
sequencermoduletypes.ModuleName,
limitermoduletypes.ModuleName,
// this line is used by starport scaffolding # stargate/app/endBlockers
)

Expand Down Expand Up @@ -602,6 +633,7 @@ func New(
vestingtypes.ModuleName,
consensusparamtypes.ModuleName,
sequencermoduletypes.ModuleName,
limitermoduletypes.ModuleName,
// this line is used by starport scaffolding # stargate/app/initGenesis
}
app.mm.SetOrderInitGenesis(genesisModuleOrder...)
Expand Down Expand Up @@ -794,7 +826,7 @@ func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig
docs.RegisterOpenAPIService(Name, apiSvr.Router)

// Register the route for sending data items
sequencerapi.RegisterDataItemAPIRoute(clientCtx, apiSvr.Router)
sequencerapi.RegisterDataItemAPIRoute(clientCtx, apiSvr.Router, &app.LimiterKeeper, app.Config.RateLimiter.WhiteListArweaveWalletOwners)
// Register the route for retrieving nonce
sequencerapi.RegisterNonceAPIRoute(app, apiSvr.Router)
// Register the route for retrieving tx by sender and nonce
Expand Down Expand Up @@ -836,6 +868,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino
paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govv1.ParamKeyTable()) //nolint:staticcheck
paramsKeeper.Subspace(crisistypes.ModuleName)
paramsKeeper.Subspace(sequencermoduletypes.ModuleName)
paramsKeeper.Subspace(limitermoduletypes.ModuleName)
// this line is used by starport scaffolding # stargate/app/paramSubspace

return paramsKeeper
Expand All @@ -855,6 +888,7 @@ func (app *App) ModuleManager() *module.Manager {
func (app *App) Close() (err error) {
app.ArweaveBlocksController.StopWait()
app.BlockValidator.StopWait()
app.LimiterKeeper.StopWait()
return nil
}

Expand Down
104 changes: 104 additions & 0 deletions app/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package config

import (
"bytes"
"os"
"reflect"
"strings"

"github.com/iancoleman/strcase"
"github.com/spf13/viper"
)

const (
envPrefix = "WARP_SEQUENCER_"
)

type Config struct {
RateLimiter RateLimiter
}

func setDefaults() {
setRateLimiterDefaults()
}

func IsIndex(s string) bool {
for _, c := range s {
if c < '0' || c > '9' {
return false
}
}
return true
}

func BindEnv(path []string, val reflect.Value) {
if val.Kind() == reflect.Slice {
// Slice of base types
key := strings.ToLower(strings.Join(path, "."))
env := envPrefix + strcase.ToScreamingSnake(strings.Join(path, "_"))
err := viper.BindEnv(key, env)
if err != nil {
panic(err)
}
} else if val.Kind() != reflect.Struct {
// Base types
// key := strings.ToLower(strings.Join(path, "."))
key := path[0]
for _, p := range path[1:] {
if IsIndex(p) {
key += "[" + p + "]"
// key += "." + p
} else {
key += "." + p
}
}

env := envPrefix + strcase.ToScreamingSnake(strings.Join(path, "_"))
err := viper.BindEnv(key, env)
if err != nil {
panic(err)
}
} else {
// Iterates over struct fields
for i := 0; i < val.NumField(); i++ {
newPath := make([]string, len(path))
copy(newPath, path)
newPath = append(newPath, val.Type().Field(i).Name)
BindEnv(newPath, val.Field(i))
}
}
}

// Load configuration from file and env
func Load(filename string) (config *Config, err error) {
viper.SetConfigType("json")

setDefaults()

// Visits every field and registers upper snake case ENV name for it
// Works with embedded structs
BindEnv([]string{}, reflect.ValueOf(Config{}))

// Empty filename means we use default values
if filename != "" {
var content []byte
/* #nosec */
content, err = os.ReadFile(filename)
if err != nil {
return nil, err
}

err = viper.ReadConfig(bytes.NewBuffer(content))
if err != nil {
return nil, err
}
}

config = new(Config)
err = viper.Unmarshal(&config)
if err != nil {
return nil, err
}

return
}
19 changes: 19 additions & 0 deletions app/config/rate-limiter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package config

import (
mapset "github.com/deckarep/golang-set/v2"
"github.com/spf13/viper"
)

type RateLimiter struct {
// Arweave wallet owners that aren't impacted by the rate limiter
WhiteListArweaveWalletOwners mapset.Set[string]

// Number of monitored blocks
NumberOfMonitoredBlocks int
}

func setRateLimiterDefaults() {
viper.SetDefault("RateLimiter.WhiteListArweaveWalletOwners", mapset.NewSet[string]())
viper.SetDefault("RateLimiter.NumberOfMonitoredBlocks", 100)
}
1 change: 1 addition & 0 deletions cmd/sequencerd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/spf13/cast"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

// this line is used by starport scaffolding # root/moduleImport

"github.com/warp-contracts/sequencer/app"
Expand Down
46 changes: 46 additions & 0 deletions docs/static/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34923,6 +34923,42 @@ paths:
format: int64
tags:
- Query
/warp-contracts/sequencer/limiter/params:
get:
summary: Parameters queries the parameters of the module.
operationId: SequencerLimiterParams
responses:
'200':
description: A successful response.
schema:
type: object
properties:
params:
description: params holds all the parameters of this module.
type: object
description: >-
QueryParamsResponse is response type for the Query/Params RPC
method.
default:
description: An unexpected error response.
schema:
type: object
properties:
code:
type: integer
format: int32
message:
type: string
details:
type: array
items:
type: object
properties:
'@type':
type: string
additionalProperties: {}
tags:
- Query
/warp-contracts/sequencer/sequencer/last_arweave_block:
get:
summary: Queries a LastArweaveBlock by index.
Expand Down Expand Up @@ -59269,6 +59305,16 @@ definitions:
NOTE: The amount field is an Int which implements the custom method
signatures required by gogoproto.
description: Period defines a length of time and amount of coins that will vest.
sequencer.limiter.Params:
type: object
description: Params defines the parameters for the module.
sequencer.limiter.QueryParamsResponse:
type: object
properties:
params:
description: params holds all the parameters of this module.
type: object
description: QueryParamsResponse is response type for the Query/Params RPC method.
sequencer.sequencer.ArweaveBlockInfo:
type: object
properties:
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@ require (
github.com/cosmos/cosmos-proto v1.0.0-beta.2
github.com/cosmos/cosmos-sdk v0.47.5
github.com/cosmos/gogoproto v1.4.10
github.com/deckarep/golang-set/v2 v2.6.0
github.com/ethereum/go-ethereum v1.11.6
github.com/gammazero/deque v0.2.1
github.com/go-playground/validator/v10 v10.14.1
github.com/golang/protobuf v1.5.3
github.com/gorilla/mux v1.8.0
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2
github.com/iancoleman/strcase v0.2.0
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cast v1.5.0
github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.15.0
github.com/stretchr/testify v1.8.4
github.com/warp-contracts/syncer v0.2.104
golang.org/x/crypto v0.13.0
Expand Down Expand Up @@ -127,7 +130,6 @@ require (
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect
github.com/huandu/skiplist v1.2.0 // indirect
github.com/iancoleman/strcase v0.2.0 // indirect
github.com/improbable-eng/grpc-web v0.15.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
Expand Down Expand Up @@ -185,7 +187,6 @@ require (
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/viper v1.15.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnG
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
Expand Down
12 changes: 12 additions & 0 deletions proto/sequencer/limiter/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
syntax = "proto3";
package sequencer.limiter;

import "gogoproto/gogo.proto";
import "sequencer/limiter/params.proto";

option go_package = "github.com/warp-contracts/sequencer/x/limiter/types";

// GenesisState defines the limiter module's genesis state.
message GenesisState {
Params params = 1 [(gogoproto.nullable) = false];
}
Loading
Loading