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

feat: servicer module implementation #19

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
61 changes: 50 additions & 11 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import (
"github.com/cometbft/cometbft/libs/log"
tmos "github.com/cometbft/cometbft/libs/os"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
cosmosClient "github.com/cosmos/cosmos-sdk/client"
nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node"
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/runtime"
Expand Down Expand Up @@ -113,6 +114,7 @@ import (
applicationmodule "poktroll/x/application"
applicationmodulekeeper "poktroll/x/application/keeper"
applicationmoduletypes "poktroll/x/application/types"
"poktroll/x/poktroll"
poktrollmodule "poktroll/x/poktroll"
poktrollmodulekeeper "poktroll/x/poktroll/keeper"
poktrollmoduletypes "poktroll/x/poktroll/types"
Expand Down Expand Up @@ -234,7 +236,7 @@ type App struct {
cdc *codec.LegacyAmino
appCodec codec.Codec
interfaceRegistry types.InterfaceRegistry
txConfig client.TxConfig
txConfig cosmosClient.TxConfig

invCheckPeriod uint

Expand Down Expand Up @@ -556,7 +558,7 @@ func New(
keys[poktrollmoduletypes.StoreKey],
keys[poktrollmoduletypes.MemStoreKey],
app.GetSubspace(poktrollmoduletypes.ModuleName),
)
) // TECHDEBT: Do something with the error
poktrollModule := poktrollmodule.NewAppModule(appCodec, app.PoktrollKeeper, app.AccountKeeper, app.BankKeeper)

app.PortalKeeper = *portalmodulekeeper.NewKeeper(
Expand All @@ -583,7 +585,34 @@ func New(
app.GetSubspace(servicermoduletypes.ModuleName),
app.BankKeeper,
)
servicerModule := servicermodule.NewAppModule(appCodec, app.ServicerKeeper, app.AccountKeeper, app.BankKeeper)

servicerEnabled := appOpts.Get(poktroll.FlagEnableServicerMode).(bool)
applicationEnabled := appOpts.Get(poktroll.FlagEnableApplicationMode).(bool)
portalEnabled := appOpts.Get(poktroll.FlagEnablePortalMode).(bool)

factory := appOpts.Get("factory").(tx.Factory)
clientCtx := appOpts.Get("clientCtx").(cosmosClient.Context)

var actorModule module.AppModule
if servicerEnabled && !applicationEnabled && !portalEnabled {
actorModule = servicermodule.NewAppModule(
appCodec,
app.ServicerKeeper,
app.AccountKeeper,
app.BankKeeper,
// TODO_THIS_COMMIT: refactor & de-dup key to a constant
clientCtx,
factory,
)
} else if applicationEnabled && !servicerEnabled && !portalEnabled {
// actorModule = applicationmodule.NewAppModule(appCodec, app.ApplicationKeeper, app.AccountKeeper, app.BankKeeper)
} else if portalEnabled && !applicationEnabled && !servicerEnabled {
// actorModule = portalmodule.NewAppModule(appCodec, app.PortalKeeper, app.AccountKeeper, app.BankKeeper)
} else if !portalEnabled && !applicationEnabled && !servicerEnabled {
// No actor module
} else {
panic("only one of the following flags can be set: --servicer, --application, --portal")
}

app.SessionKeeper = *sessionmodulekeeper.NewKeeper(
appCodec,
Expand Down Expand Up @@ -628,7 +657,7 @@ func New(
// NOTE: Any module instantiated in the module manager that is later modified
// must be passed by reference here.

app.mm = module.NewManager(
modules := []module.AppModule{
genutil.NewAppModule(
app.AccountKeeper,
app.StakingKeeper,
Expand Down Expand Up @@ -657,13 +686,23 @@ func New(
poktrollModule,
portalModule,
applicationModule,
servicerModule,
sessionModule,
// 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
}

if servicerEnabled || applicationEnabled || portalEnabled {
modules = append(modules, actorModule)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, I was thinking each service can act as multiple actors. I think it would also simplify the logic by initializing all of them (none of the if else statements) and it would just be a noop inside the actual module if the flagis off.

}

// always be last to make sure that it checks for all invariants and not only part of them
modules = append(
modules,
crisis.NewAppModule(app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)),
)

app.mm = module.NewManager(modules...)

// During begin block slashing happens after distr.BeginBlocker so that
// there is nothing left over in the validator fee pool, so as to keep the
// CanWithdrawInvariant invariant.
Expand Down Expand Up @@ -898,7 +937,7 @@ func (app *App) InterfaceRegistry() types.InterfaceRegistry {
}

// TxConfig returns SimApp's TxConfig
func (app *App) TxConfig() client.TxConfig {
func (app *App) TxConfig() cosmosClient.TxConfig {
return app.txConfig
}

Expand Down Expand Up @@ -950,12 +989,12 @@ func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig
}

// RegisterTxService implements the Application.RegisterTxService method.
func (app *App) RegisterTxService(clientCtx client.Context) {
func (app *App) RegisterTxService(clientCtx cosmosClient.Context) {
authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry)
}

// RegisterTendermintService implements the Application.RegisterTendermintService method.
func (app *App) RegisterTendermintService(clientCtx client.Context) {
func (app *App) RegisterTendermintService(clientCtx cosmosClient.Context) {
tmservice.RegisterTendermintService(
clientCtx,
app.BaseApp.GRPCQueryRouter(),
Expand All @@ -965,7 +1004,7 @@ func (app *App) RegisterTendermintService(clientCtx client.Context) {
}

// RegisterNodeService implements the Application.RegisterNodeService method.
func (app *App) RegisterNodeService(clientCtx client.Context) {
func (app *App) RegisterNodeService(clientCtx cosmosClient.Context) {
nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter())
}

Expand Down
33 changes: 27 additions & 6 deletions cmd/poktrolld/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/server"
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
Expand All @@ -41,6 +42,7 @@ import (

"poktroll/app"
appparams "poktroll/app/params"
"poktroll/x/poktroll"
)

// NewRootCmd creates a new root command for a Cosmos SDK application
Expand Down Expand Up @@ -72,15 +74,32 @@ func NewRootCmd() (*cobra.Command, appparams.EncodingConfig) {
return err
}

if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil {
return err
}

customAppTemplate, customAppConfig := initAppConfig()
customTMConfig := initTendermintConfig()
return server.InterceptConfigsPreRunHandler(
if err := server.InterceptConfigsPreRunHandler(
cmd, customAppTemplate, customAppConfig, customTMConfig,
)
); err != nil {
return err
}

factory, err := tx.NewFactoryCLI(initClientCtx, cmd.Flags())
if err != nil {
return err
}

serverCtx := server.GetServerContextFromCmd(cmd)
// TODO_THIS_COMMIT: factor out keys to constants.
serverCtx.Viper.Set("actorMode", "servicer")
serverCtx.Viper.Set("clientCtx", initClientCtx)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you're doing here and seems like a good first approach (assuming we clean up the code), but I do want to try to avoid using viper for it.

An idea (I don' know if it works) is to potentially leverage app.go:

func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
	clientCtx := apiSvr.ClientCtx
	// Register new tx routes from grpc-gateway.
	authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
	// Register new tendermint queries routes from grpc-gateway.
	tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
	// Register node gRPC service for grpc-gateway.
	nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)

	// Register grpc-gateway routes for all modules.
	ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)

	// register app's OpenAPI routes.
	docs.RegisterOpenAPIService(Name, apiSvr.Router)
}

What if we add a customservicerService.RegisterRelayRoutes(clientCtx, cmdContext), and have it idiometically manage things under the hood?

This isn't a very well formed idea yet, so I'm still thinking through things...

serverCtx.Viper.Set("factory", factory)
if err := server.SetCmdServerContext(cmd, serverCtx); err != nil {
return err
}

if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil {
return err
}
return nil
},
}

Expand Down Expand Up @@ -201,6 +220,8 @@ func txCommand() *cobra.Command {
}

func addModuleInitFlags(startCmd *cobra.Command) {
poktroll.AddModuleInitFlags(startCmd)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we add this to every module (portal, servicer, app) and have each one manage its own flag (independently of the other)?


crisis.AddModuleInitFlags(startCmd)
// this line is used by starport scaffolding # root/arguments
}
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,5 @@ replace github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.2021
replace github.com/cosmos/cosmos-sdk => github.com/rollkit/cosmos-sdk v0.47.3-rollkit-v0.10.2-no-fraud-proofs

replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1

replace github.com/pokt-network/smt => github.com/pokt-network/smt v0.6.2-0.20230907101623-9d2e4983c5f1
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1576,8 +1576,8 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pokt-network/smt v0.6.2-0.20230906162127-ef2341c474a0 h1:EFkH0qu/MrmDgz0i9FiHRFTGQAx6fkqlYRnlg7NgKpY=
github.com/pokt-network/smt v0.6.2-0.20230906162127-ef2341c474a0/go.mod h1:IhNcYL5XOHTfagy8GBKM23Xhd2uvhgbTtsGSMQtCxR8=
github.com/pokt-network/smt v0.6.2-0.20230907101623-9d2e4983c5f1 h1:ABPxZMZSGFqCbOXyEuGys1k4hLp0yORTrhPFr3676h4=
github.com/pokt-network/smt v0.6.2-0.20230907101623-9d2e4983c5f1/go.mod h1:IhNcYL5XOHTfagy8GBKM23Xhd2uvhgbTtsGSMQtCxR8=
github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4=
github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
github.com/polyfloyd/go-errorlint v1.0.0/go.mod h1:KZy4xxPJyy88/gldCe5OdW6OQRtNO3EZE7hXzmnebgA=
Expand Down
2 changes: 1 addition & 1 deletion localnet/kubernetes/poktrolld.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ data:

# start the node
# You can attach to this process with delve (dlv) for debugging purpose with `dlv attach $(pgrep poktrolld) --listen :40004 --headless --api-version=2 --accept-multiclient` - run inside the container!
poktrolld start --rollkit.aggregator true --rollkit.da_layer celestia --rollkit.da_config='{"base_url":"http://celestia-rollkit:26658","timeout":60000000000,"fee":600000,"gas_limit":6000000,"auth_token":"'$AUTH_TOKEN'"}' --rollkit.namespace_id $NAMESPACE_ID --rollkit.da_start_height $DA_BLOCK_HEIGHT --rpc.laddr tcp://127.0.0.1:36657 --p2p.laddr "0.0.0.0:36656"
poktrolld start --servicer --rollkit.aggregator true --rollkit.da_layer celestia --rollkit.da_config='{"base_url":"http://celestia-rollkit:26658","timeout":60000000000,"fee":600000,"gas_limit":6000000,"auth_token":"'$AUTH_TOKEN'"}' --rollkit.namespace_id $NAMESPACE_ID --rollkit.da_start_height $DA_BLOCK_HEIGHT --rpc.laddr tcp://127.0.0.1:36657 --p2p.laddr "0.0.0.0:36656"

# OR debug the node (uncomment this line but comment previous line)
# dlv exec /usr/local/bin/poktrolld --listen :40004 --headless --api-version=2 --accept-multiclient -- poktrolld start --rollkit.aggregator true --rollkit.da_layer celestia --rollkit.da_config='{"base_url":"http://celestia-rollkit:26658","timeout":60000000000,"fee":600000,"gas_limit":6000000,"auth_token":"'$AUTH_TOKEN'"}' --rollkit.namespace_id $NAMESPACE_ID --rollkit.da_start_height $DA_BLOCK_HEIGHT --rpc.laddr tcp://127.0.0.1:36657 --p2p.laddr "0.0.0.0:36656"
Expand Down
23 changes: 23 additions & 0 deletions proto/poktroll/servicer/relay_request.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
syntax = "proto3";
package poktroll.servicer;

option go_package = "poktroll/x/servicer/types";

message Relay {
RelayRequest req = 1;
RelayResponse res = 2;
}

message RelayRequest {
string method = 1;
string url = 2;
map<string, string> headers = 3;
bytes payload = 4;
}

message RelayResponse {
bytes payload = 1;
int32 status_code = 2;
map<string, string> headers = 3;
bytes signature = 4;
}
22 changes: 22 additions & 0 deletions proto/poktroll/servicer/session.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
syntax = "proto3";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this and import from the session module

package poktroll.servicer;

option go_package = "poktroll/x/servicer/types";

message Session {
string id = 1; // a universally unique ID for the session
int64 session_number = 2; // a monotonically increasing number representing the # on the chain
int64 session_height = 3; // the height at which the session starts
bytes block_hash = 4; // the hash of the block at which the session starts
int64 num_session_blocks = 5; // the number of blocks the session is valid from
// CONSIDERATION: Should we add a `RelayChain` enum and use it across the board?
// CONSIDERATION: Should a single session support multiple relay chains?
// TECHDEBT: Do we need backwards with v0? https://docs.pokt.network/supported-blockchains/
string relay_chain = 6; // the relay chain the session is valid for
// CONSIDERATION: Should a single session support multiple geo zones?
string geo_zone = 7; // the target geographic region where the actors are present
// core.Actor application = 7; // the application that is being served
// IMPROVE: `map<string, core.Actor>` with the address as the key can simplify and optimize the logic on the clients
// repeated core.Actor servicers = 8; // the set of servicers that are serving the application
// repeated core.Actor fishermen = 9; // the set of fishermen that are fishing for servicers
}
101 changes: 101 additions & 0 deletions utils/observable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package utils

import "sync"

// Observable is a generic interface that allows multiple subscribers to read from a single channel
type Observable[V any] interface {
Subscribe() Subscription[V]
}

type ObservableImpl[V any] struct {
mu sync.RWMutex
ch <-chan V // private channel that is used to emit values to subscribers
subscribers []chan V // subscribers is a list of channels that are subscribed to the observable
closed bool
}

// Creates a new observable which emissions are controlled by the emitter channel
func NewControlledObservable[V any](emitter chan V) (Observable[V], chan V) {
// If the caller does not provide an emitter, create a new one and return it
e := make(chan V)
if emitter != nil {
e = emitter
}
o := &ObservableImpl[V]{sync.RWMutex{}, e, []chan V{}, false}

// Start listening to the emitter and emit values to subscribers
go o.listen(emitter)

return o, emitter
}

// Get a subscription to the observable
func (o *ObservableImpl[V]) Subscribe() Subscription[V] {
o.mu.Lock()
defer o.mu.Unlock()

// Create a channel for the subscriber and append it to the subscribers list
ch := make(chan V, 1)
o.subscribers = append(o.subscribers, ch)

// Removal function used when unsubscribing from the observable
removeFromObservable := func() {
o.mu.Lock()
defer o.mu.Unlock()

for i, s := range o.subscribers {
if ch == s {
o.subscribers = append(o.subscribers[:i], o.subscribers[i+1:]...)
break
}
}
}

// Subscription gets its closed state from the observable
return &SubscriptionImpl[V]{ch, o.closed, removeFromObservable}
}

// Listen to the emitter and emit values to subscribers
// This function is blocking and should be run in a goroutine
func (o *ObservableImpl[V]) listen(emitter <-chan V) {
for v := range emitter {
// Lock for o.subscribers slice as it can be modified by subscribers
o.mu.RLock()
for _, ch := range o.subscribers {
ch <- v
}
o.mu.RUnlock()
}

// Here we know that the emitter has been closed, all subscribers should be closed as well
o.mu.Lock()
o.closed = true
for _, ch := range o.subscribers {
close(ch)
o.subscribers = []chan V{}
}
o.mu.Lock()
}

// Subscription is a generic interface that provide access to the underlying channel
// and allows unsubscribing from an observable
type Subscription[V any] interface {
Unsubscribe()
Ch() <-chan V
}

type SubscriptionImpl[V any] struct {
ch chan V
closed bool
removeFromObservable func()
}

func (s *SubscriptionImpl[V]) Unsubscribe() {
close(s.ch)
s.closed = true
s.removeFromObservable()
}

func (s *SubscriptionImpl[V]) Ch() <-chan V {
return s.ch
}
Loading