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

Blue account #1033

Merged
merged 16 commits into from
Oct 31, 2019
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Changelog

## HEAD
- `gconf`: allow to provide an optional authentication address that will be
used to authenticate a configuration creation message. This solves a
chicken-egg problem of when the confgiuration was not created via genesis.
- `migrations`: when upgrading the schema version an explicit version must be
provided. This is required to ensure at most one delivery.
- `cmd/bnscli` can create a schema upgrade transaction.
Expand Down
2 changes: 1 addition & 1 deletion cmd/bnsd/x/blueaccount/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func RegisterRoutes(r weave.Registry, auth x.Authenticator) {
})

r.Handle(&UpdateConfigurationMsg{}, gconf.NewUpdateConfigurationHandler(
"blueaccount", &Configuration{}, auth))
"blueaccount", &Configuration{}, auth, migration.CurrentAdmin))
}

type registerDomainHandler struct {
Expand Down
2 changes: 1 addition & 1 deletion cmd/bnsd/x/username/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,5 +180,5 @@ func (h *changeTokenTargetsHandler) validate(ctx weave.Context, db weave.KVStore

func NewConfigHandler(auth x.Authenticator) weave.Handler {
var conf Configuration
return gconf.NewUpdateConfigurationHandler("username", &conf, auth)
return gconf.NewUpdateConfigurationHandler("username", &conf, auth, migration.CurrentAdmin)
}
49 changes: 41 additions & 8 deletions gconf/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,42 @@ type OwnedConfig interface {
type UpdateConfigurationHandler struct {
pkg string
// We require this type to load the data.
config OwnedConfig
auth x.Authenticator
config OwnedConfig
auth x.Authenticator
initAdmin func(weave.ReadOnlyKVStore) (weave.Address, error)
}

var _ weave.Handler = (*UpdateConfigurationHandler)(nil)

func NewUpdateConfigurationHandler(pkg string, config OwnedConfig, auth x.Authenticator) UpdateConfigurationHandler {
// NewUpdateConfigurationHandler returns a message handler that process
// configuration patch message.
//
// To pass authentication step, each message must be signed by the current
// configuration owner.
//
// A special chicken-egg problem appears when the configuration does not exist
// (it was not created via genesis). This is an issue, because without
// configuration we cannot configure configuration owner that can update the
// configuration. This means that the configuration cannot be created as well.
// A configuration is needed to create a configuration.
// To address the above issue, an optional `initConfAdmin` argument can be
// given to provide a creation only admin address. A good deafult is to use
// `migration.CurrentAdmin` function.
// `initConfAdmin` is used to authenticate the tranaction only when no
// configuration exist. Once a configuration is created, `initConfAdmin` is not
// used anymore and the autentication relies only on configuration's owner
// declaration.
func NewUpdateConfigurationHandler(
pkg string,
config OwnedConfig,
auth x.Authenticator,
initConfAdmin func(weave.ReadOnlyKVStore) (weave.Address, error),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ethanfrey @alpe Please have a look if you have a moment. I think this is a rather big change to weave configuration patterns.

This is solving the problem I have described in the comment above - I want to create a configuration and cannot authenticate, because configuration entity defines who can authenticate 🐣

Usually configuration is created via genesis. This is not possible if you add an extension to an existing state.

It is not possible to do this via migrations as Ethan suggested for two reasons:

  • migrations do not have access to the context. This is on purpose as the code that runs them might not have access to the context as well (i.e. bucket),
  • migrations are given only weave.ReadOnlyKVStore. This is also on purpose, so that they are not able to modify the database state (!). They are supposed to migrate the in memory entity representation.

I require explicit passing of an admin address function instead of directly importing migration.loadConf in gconf because of import cycle. I think it is also nice that initConfAdmin is optional.

What do you guys think?

) UpdateConfigurationHandler {
return UpdateConfigurationHandler{
pkg: pkg,
config: config,
auth: auth,
pkg: pkg,
config: config,
auth: auth,
initAdmin: initConfAdmin,
}
}

Expand Down Expand Up @@ -64,8 +89,16 @@ func (h UpdateConfigurationHandler) applyTx(ctx weave.Context, store weave.KVSto
// Configuration entity does not exist. It was not initialized
// during via the genesis and will be created for the first
// time now.

// TODO - because of lack of a better idea, anyone can do this right now
if h.initAdmin == nil {
return errors.Wrap(errors.ErrUnauthorized, "configuration does not exist and cannot be initialized")
}
admin, err := h.initAdmin(store)
if err != nil {
return errors.Wrap(err, "get init admin")
}
if !h.auth.HasAddress(ctx, admin) {
return errors.Wrap(errors.ErrUnauthorized, "initialization admin signature required")
}
default:
return errors.Wrap(err, "load current configuration")
}
Expand Down
22 changes: 18 additions & 4 deletions migration/configuration.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package migration

import (
weave "github.com/iov-one/weave"
"github.com/iov-one/weave/errors"
"github.com/iov-one/weave/gconf"
)
Expand All @@ -12,11 +13,24 @@ func (c *Configuration) Validate() error {
return nil
}

func mustLoadConf(db gconf.Store) Configuration {
func loadConf(db gconf.ReadStore) (*Configuration, error) {
var conf Configuration
if err := gconf.Load(db, "migration", &conf); err != nil {
err = errors.Wrap(err, "load configuration")
panic(err)
return nil, errors.Wrap(err, "gconf")
}
return conf
return &conf, nil
}

// CurrentAdmin returns migration extension admin address as currently
// configured.
//
// This function is useful for the `gconf` package users to provide a one time
// authentication address during configuration initialization. See
// `gconf.NewUpdateConfigurationHandler` for more details.
func CurrentAdmin(db weave.ReadOnlyKVStore) (weave.Address, error) {
conf, err := loadConf(db)
if err != nil {
return nil, errors.Wrap(err, "load configuration")
}
return conf.Admin, nil
}
5 changes: 4 additions & 1 deletion migration/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ func (h *upgradeSchemaHandler) validate(ctx weave.Context, db weave.KVStore, tx
return nil, errors.Wrap(err, "load msg")
}

conf := mustLoadConf(db)
conf, err := loadConf(db)
if err != nil {
return nil, errors.Wrap(err, "load configuration")
}
if !h.auth.HasAddress(ctx, conf.Admin) {
return nil, errors.Wrap(errors.ErrUnauthorized, "admin signature required")
}
Expand Down
2 changes: 1 addition & 1 deletion x/cash/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,5 @@ func (h SendHandler) Deliver(ctx weave.Context, store weave.KVStore, tx weave.Tx

func NewConfigHandler(auth x.Authenticator) weave.Handler {
var conf Configuration
return gconf.NewUpdateConfigurationHandler("cash", &conf, auth)
return gconf.NewUpdateConfigurationHandler("cash", &conf, auth, migration.CurrentAdmin)
}
2 changes: 1 addition & 1 deletion x/msgfee/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,5 @@ func (h *setMsgFeeHandler) validate(ctx weave.Context, db weave.KVStore, tx weav

func NewConfigHandler(auth x.Authenticator) weave.Handler {
var conf Configuration
return gconf.NewUpdateConfigurationHandler("cash", &conf, auth)
return gconf.NewUpdateConfigurationHandler("cash", &conf, auth, migration.CurrentAdmin)
}