-
Notifications
You must be signed in to change notification settings - Fork 103
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: Add genesis support for new modules and group genesis #270
Conversation
Codecov Report
@@ Coverage Diff @@
## master #270 +/- ##
==========================================
- Coverage 62.66% 62.25% -0.41%
==========================================
Files 46 47 +1
Lines 2954 2994 +40
==========================================
+ Hits 1851 1864 +13
- Misses 892 911 +19
- Partials 211 219 +8 |
testutil/fixture.go
Outdated
// InitGenesisHandler is a function to get a module InitGenesisHandler. | ||
InitGenesisHandler(moduleName string) module.InitGenesisHandler | ||
|
||
// ExportGenesisHandler is a function to get a module ExportGenesisHandler. | ||
ExportGenesisHandler(moduleName string) module.ExportGenesisHandler | ||
|
||
// Codec is the app ProtoCodec. | ||
Codec() *codec.ProtoCodec |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need all this here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To use them in tests, see in x/group/server/testsuite/
but happy to discuss any other solutions that would look better to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about we simply have InitGenesis()
and ExportGenesis()
methods? Rather than being able to look up the handler by module. Also consider we want to use these same Fixture
s for Network
based tests in the future (#246).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing is that we can register multiple modules as part of FixtureFactory
Setup()
which is why I added them as look up methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that approach will work using a Network
fixture. Would InitGenesis
and ExportGenesis
also work for the tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you say InitGenesis()
and ExportGenesis()
methods, could you elaborate on the params and return values?
Do you see them as being similar to the manager InitGenesis()
and ExportGenesis()
, ie they would actually execute init or export genesis (instead of simply returning a function)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Aaron has a good point - hiding the app details, and only have InitGenesis
to initialize genesis for all modules would simplify the usage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated it so we have InitGenesis
and ExportGenesis
methods instead.
I'm planning to review this soon. In the meantime can anyone else review? |
@AmauryM said he'll have a look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall. Would like to avoid panics, and after that for me we can merge.
I also added a bunch of questions, mostly me getting up to speed with the groups module.
@@ -165,4 +165,5 @@ func RegisterServices(configurator servermodule.Configurator, accountKeeper Acco | |||
impl := newServer(configurator.ModuleKey(), configurator.Router(), accountKeeper, configurator.Marshaler()) | |||
group.RegisterMsgServer(configurator.MsgServer(), impl) | |||
group.RegisterQueryServer(configurator.QueryServer(), impl) | |||
configurator.RegisterGenesisHandlers(impl.InitGenesis, impl.ExportGenesis) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a big fan of these custom Register*
functions.
In the SDK, there's AppModule interface, and it's clear what the module developer needs to implement.
With this impl, we would have RegisterGenesisHandlers
, RegisterInvariants
, RegisterBeginBlocker
etc... right? I feel it's easier to forget one register, whereas in AppModule the skipped ones were clearly marked (with an empty implementation).
One idea could be:
type ModuleConfig interface {
RegisterMsgServer()
RegisterQueryServer()
InitGenesis()
ExportGenesis()
BeginBlocker()
}
and then var _ ModuleConfig = impl{}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point, I'll try to improve that, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though we can't really add RegisterMsgServer
and RegisterQueryServer
as part of the interface, these are proto-generated standalone functions, serverImpl
rather implements MsgServer
and QueryServer
interfaces, which are module specific. So I'd prefer to have separate interfaces for different concerns, and create a separate interface for genesis which would look like this (not really sure about the naming here):
type GenesisServer interface {
InitGenesis() ...
ExportGenesis() ...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or we could also have a single interface as you suggested such as:
type Server interface {
InitGenesis()
ExportGenesis()
RegisterInvariants()
...
}
And then we could also have one single entry method for the configurator
to register genesis handlers, invariants, etc.
func (c *configurator) RegisterServer(s Server) {
c.initGenesisHandler = s.InitGenesis
c.exportGenesisHandler = s.ExportGenesis
c.registerInvariantsHandler = s.RegisterInvariants
...
}
But maybe that can be done as part of a separate PR, once we have more functions to register, wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But maybe that can be done as part of a separate PR, once we have more functions to register, wdyt?
Yes, good idea. #301
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this things at all in a configurator
? In comment's above I'm trying to find out if we could reuse module.Manager
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see my previous comment #270:
This server manager is used for the new modules (ecocredit, data, group) which are not registered with the usual sdk manager (see module wiring in app.go and experimental_appconfig.go). These new modules don't implement AppModule and don't have a direct access to the server implementation which is private (contrary to sdk modules with a reference to a keeper). So we pass relevant methods (init/export genesis in this case) to the configurator on RegisterServices so they can be passed in turn to the server manager on RegisterModules, then the server manager can use them to perform init/export genesis when needed.
This is needed in this context:
regen-ledger/types/module/server/manager.go
Lines 106 to 108 in 789f363
serverMod.RegisterServices(cfg) | |
mm.initGenesisHandlers[name] = cfg.initGenesisHandler | |
mm.exportGenesisHandlers[name] = cfg.exportGenesisHandler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All my questions were addressed, thanks @blushi
router *router | ||
requiredServices map[reflect.Type]bool | ||
initGenesisHandlers map[string]module.InitGenesisHandler | ||
exportGenesisHandlers map[string]module.ExportGenesisHandler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need to put this here? Can't types/module.Manager
be used? It has InitGenesis
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the manager InitGenesis
and ExportGenesis
methods use those handlers.
return abci.ResponseInitChain{ | ||
Validators: validatorUpdates, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is almost a copy of types/module.Manager.InitGenesis
- why we do that? Why we can't reuse the modules.Manager
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This server manager is used for the new modules (ecocredit, data, group) which are not registered with the usual sdk manager (see module wiring in app.go
and experimental_appconfig.go
). These new modules don't implement AppModule
and don't have a direct access to the server implementation which is private (contrary to sdk modules with a reference to a keeper). So we pass relevant methods (init/export genesis in this case) to the configurator
on RegisterServices
so they can be passed in turn to the server manager on RegisterModules
, then the server manager can use them to perform init/export genesis when needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a doc string explaining that (to the Manager.Init/Export Genesis
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this mechanism looks tricky. Instead of calling interface, we pass a manager and ask the module to register itself. I don't think that extending the Registration pattern is a good approach. Not going to block on that. Let me know wht do you think. If we find that it's good to rethink it then maybe we can continue in a new issue?
@aaronc - do you have any comments on that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should try something like I'm describing here which is a hybrid between the ADR 033 approach and the existing approach: #301 (comment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's follow up on that as part of this issue #301
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, let's roll this PR and think about better approach in the issue.
@@ -165,4 +165,5 @@ func RegisterServices(configurator servermodule.Configurator, accountKeeper Acco | |||
impl := newServer(configurator.ModuleKey(), configurator.Router(), accountKeeper, configurator.Marshaler()) | |||
group.RegisterMsgServer(configurator.MsgServer(), impl) | |||
group.RegisterQueryServer(configurator.QueryServer(), impl) | |||
configurator.RegisterGenesisHandlers(impl.InitGenesis, impl.ExportGenesis) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this things at all in a configurator
? In comment's above I'm trying to find out if we could reuse module.Manager
.
…gen-ledger into marie/214-group-genesis
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's think what to do with types/module.Manager
vs initGenesisHandlers
and exportGenesisHandlers
Not going to block on it, but let's see if this is a right approach we want to use towards SDKv1 before merging. (we can expand on this in an issue).
} | ||
|
||
// ImportTableData initializes a table and attached indexers from the given json encoded `[]Model`s. | ||
// ImportTableData initializes a table and attaches indexers from the given data interface{}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think copying indexes (first approach) is not bad. It won't take much more memory since we are only copying pointers.
If you like we can do it (or consider 2nd approach or even something else) later in a new issue?
return abci.ResponseInitChain{ | ||
Validators: validatorUpdates, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a doc string explaining that (to the Manager.Init/Export Genesis
return abci.ResponseInitChain{ | ||
Validators: validatorUpdates, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this mechanism looks tricky. Instead of calling interface, we pass a manager and ask the module to register itself. I don't think that extending the Registration pattern is a good approach. Not going to block on that. Let me know wht do you think. If we find that it's good to rethink it then maybe we can continue in a new issue?
@aaronc - do you have any comments on that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please recheck if we have documentation for attributes updated.
closes: #214