Add Registrar permission to attaching chains
This commit is contained in:
parent
91eb91b803
commit
485ec80cca
@ -43,6 +43,13 @@ func (a Actor) Empty() bool {
|
||||
return a.ChainID == "" && a.App == "" && len(a.Address) == 0
|
||||
}
|
||||
|
||||
// WithChain creates a copy of the actor with a different chainID
|
||||
func (a Actor) WithChain(chainID string) (b Actor) {
|
||||
b = a
|
||||
b.ChainID = chainID
|
||||
return
|
||||
}
|
||||
|
||||
// Context is an interface, so we can implement "secure" variants that
|
||||
// rely on private fields to control the actions
|
||||
type Context interface {
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
package ibc
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-wire/data"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
@ -10,6 +13,9 @@ import (
|
||||
const (
|
||||
// NameIBC is the name of this module
|
||||
NameIBC = "ibc"
|
||||
// OptionRegistrar is the option name to set the actor
|
||||
// to handle ibc chain registration
|
||||
OptionRegistrar = "registrar"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -23,29 +29,44 @@ func AllowIBC(app string) basecoin.Actor {
|
||||
}
|
||||
|
||||
// Handler allows us to update the chain state or create a packet
|
||||
//
|
||||
// TODO: require auth for registration, the authorized actor (or role)
|
||||
// should be defined in the handler, and set via SetOption
|
||||
type Handler struct {
|
||||
// TODO: add option to set who can permit registration and store it
|
||||
basecoin.NopOption
|
||||
Registrar basecoin.Actor
|
||||
}
|
||||
|
||||
var _ basecoin.Handler = Handler{}
|
||||
var _ basecoin.Handler = &Handler{}
|
||||
|
||||
// NewHandler makes a role handler to create roles
|
||||
func NewHandler() Handler {
|
||||
return Handler{}
|
||||
// NewHandler makes a Handler that allows all chains to connect via IBC.
|
||||
// Set a Registrar via SetOption to restrict it.
|
||||
func NewHandler() *Handler {
|
||||
return new(Handler)
|
||||
}
|
||||
|
||||
// Name - return name space
|
||||
func (Handler) Name() string {
|
||||
func (*Handler) Name() string {
|
||||
return NameIBC
|
||||
}
|
||||
|
||||
// SetOption - sets the registrar for IBC
|
||||
func (h *Handler) SetOption(l log.Logger, store state.KVStore, module, key, value string) (log string, err error) {
|
||||
if module != NameIBC {
|
||||
return "", errors.ErrUnknownModule(module)
|
||||
}
|
||||
if key == OptionRegistrar {
|
||||
var act basecoin.Actor
|
||||
err = data.FromJSON([]byte(value), &act)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
h.Registrar = act
|
||||
// TODO: save/load from disk!
|
||||
return "Success", nil
|
||||
}
|
||||
return "", errors.ErrUnknownKey(key)
|
||||
}
|
||||
|
||||
// CheckTx verifies the packet is formated correctly, and has the proper sequence
|
||||
// for a registered chain
|
||||
func (h Handler) CheckTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||
func (h *Handler) CheckTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||
err = tx.ValidateBasic()
|
||||
if err != nil {
|
||||
return res, err
|
||||
@ -64,7 +85,7 @@ func (h Handler) CheckTx(ctx basecoin.Context, store state.KVStore, tx basecoin.
|
||||
|
||||
// DeliverTx verifies all signatures on the tx and updated the chain state
|
||||
// apropriately
|
||||
func (h Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||
func (h *Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||
err = tx.ValidateBasic()
|
||||
if err != nil {
|
||||
return res, err
|
||||
@ -72,7 +93,6 @@ func (h Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoi
|
||||
|
||||
switch t := tx.Unwrap().(type) {
|
||||
case RegisterChainTx:
|
||||
// TODO: do we want some permissioning for this???
|
||||
return h.initSeed(ctx, store, t)
|
||||
case UpdateChainTx:
|
||||
return h.updateSeed(ctx, store, t)
|
||||
@ -82,10 +102,19 @@ func (h Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoi
|
||||
return res, errors.ErrUnknownTxType(tx.Unwrap())
|
||||
}
|
||||
|
||||
// initSeed imports the first seed for this chain and accepts it as the root of trust
|
||||
func (h Handler) initSeed(ctx basecoin.Context, store state.KVStore,
|
||||
// initSeed imports the first seed for this chain and
|
||||
// accepts it as the root of trust.
|
||||
//
|
||||
// only the registrar, if set, is allowed to do this
|
||||
func (h *Handler) initSeed(ctx basecoin.Context, store state.KVStore,
|
||||
t RegisterChainTx) (res basecoin.Result, err error) {
|
||||
|
||||
// check permission to attach
|
||||
// nothing set, means anyone can connect
|
||||
if !h.Registrar.Empty() && !ctx.HasPermission(h.Registrar) {
|
||||
return res, errors.ErrUnauthorized()
|
||||
}
|
||||
|
||||
chainID := t.ChainID()
|
||||
s := NewChainSet(store)
|
||||
err = s.Register(chainID, ctx.BlockHeight(), t.Seed.Height())
|
||||
@ -101,7 +130,7 @@ func (h Handler) initSeed(ctx basecoin.Context, store state.KVStore,
|
||||
|
||||
// updateSeed checks the seed against the existing chain data and rejects it if it
|
||||
// doesn't fit (or no chain data)
|
||||
func (h Handler) updateSeed(ctx basecoin.Context, store state.KVStore,
|
||||
func (h *Handler) updateSeed(ctx basecoin.Context, store state.KVStore,
|
||||
t UpdateChainTx) (res basecoin.Result, err error) {
|
||||
|
||||
chainID := t.ChainID()
|
||||
@ -124,7 +153,7 @@ func (h Handler) updateSeed(ctx basecoin.Context, store state.KVStore,
|
||||
|
||||
// createPacket makes sure all permissions are good and the destination
|
||||
// chain is registed. If so, it appends it to the outgoing queue
|
||||
func (h Handler) createPacket(ctx basecoin.Context, store state.KVStore,
|
||||
func (h *Handler) createPacket(ctx basecoin.Context, store state.KVStore,
|
||||
t CreatePacketTx) (res basecoin.Result, err error) {
|
||||
|
||||
// make sure the chain is registed
|
||||
@ -134,7 +163,7 @@ func (h Handler) createPacket(ctx basecoin.Context, store state.KVStore,
|
||||
}
|
||||
|
||||
// make sure we have the special IBC permission
|
||||
mod, err := t.Tx.GetKind()
|
||||
mod, err := t.Tx.GetMod()
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@ -155,8 +184,7 @@ func (h Handler) createPacket(ctx basecoin.Context, store state.KVStore,
|
||||
return res, ErrCannotSetPermission()
|
||||
}
|
||||
// add the permission with the current ChainID
|
||||
packet.Permissions[i] = p
|
||||
packet.Permissions[i].ChainID = ctx.ChainID()
|
||||
packet.Permissions[i] = p.WithChain(ctx.ChainID())
|
||||
}
|
||||
|
||||
// now add it to the output queue....
|
||||
|
||||
15
tx.go
15
tx.go
@ -1,6 +1,8 @@
|
||||
package basecoin
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/tendermint/go-wire/data"
|
||||
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
@ -75,3 +77,16 @@ func (t Tx) GetKind() (string, error) {
|
||||
// grab the type we used in json
|
||||
return text.Kind, nil
|
||||
}
|
||||
|
||||
func (t Tx) GetMod() (string, error) {
|
||||
kind, err := t.GetKind()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
parts := strings.SplitN(kind, "/", 2)
|
||||
if len(parts) != 2 {
|
||||
// TODO: return "base"?
|
||||
return "", errors.ErrUnknownTxType(t)
|
||||
}
|
||||
return parts[0], nil
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user