Start defining CreatePacket

This commit is contained in:
Ethan Frey 2017-07-16 22:46:21 +02:00
parent 715d573e1a
commit 91eb91b803
4 changed files with 116 additions and 21 deletions

View File

@ -9,8 +9,10 @@ import (
// nolint
var (
errChainNotRegistered = fmt.Errorf("Chain not registered")
errChainAlreadyExists = fmt.Errorf("Chain already exists")
errChainNotRegistered = fmt.Errorf("Chain not registered")
errChainAlreadyExists = fmt.Errorf("Chain already exists")
errNeedsIBCPermission = fmt.Errorf("Needs app-permission to send IBC")
errCannotSetPermission = fmt.Errorf("Requesting invalid permission on IBC")
// errNotMember = fmt.Errorf("Not a member")
// errInsufficientSigs = fmt.Errorf("Not enough signatures")
// errNoMembers = fmt.Errorf("No members specified")
@ -23,12 +25,13 @@ var (
IBCCodeUnknownHeight = abci.CodeType(1004)
IBCCodeInvalidCommit = abci.CodeType(1005)
IBCCodeInvalidProof = abci.CodeType(1006)
IBCCodeInvalidCall = abci.CodeType(1007)
)
func ErrNotRegistered(chainID string) error {
return errors.WithMessage(chainID, errChainNotRegistered, IBCCodeChainNotRegistered)
}
func IsNotRegistetedErr(err error) bool {
func IsNotRegisteredErr(err error) bool {
return errors.IsSameError(errChainNotRegistered, err)
}
@ -38,3 +41,17 @@ func ErrAlreadyRegistered(chainID string) error {
func IsAlreadyRegistetedErr(err error) bool {
return errors.IsSameError(errChainAlreadyExists, err)
}
func ErrNeedsIBCPermission() error {
return errors.WithCode(errNeedsIBCPermission, IBCCodeInvalidCall)
}
func IsNeedsIBCPermissionErr(err error) bool {
return errors.IsSameError(errNeedsIBCPermission, err)
}
func ErrCannotSetPermission() error {
return errors.WithCode(errCannotSetPermission, IBCCodeInvalidCall)
}
func IsCannotSetPermissionErr(err error) bool {
return errors.IsSameError(errCannotSetPermission, err)
}

View File

@ -7,16 +7,27 @@ import (
"github.com/tendermint/basecoin/state"
)
// nolint
const (
// NameIBC is the name of this module
NameIBC = "ibc"
)
var (
allowIBC = []byte{0x42, 0xbe, 0xef, 0x1}
)
// AllowIBC is the special code that an app must set to
// enable sending IBC packets for this app-type
func AllowIBC(app string) basecoin.Actor {
return basecoin.Actor{App: app, Address: allowIBC}
}
// 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
}
@ -45,6 +56,8 @@ func (h Handler) CheckTx(ctx basecoin.Context, store state.KVStore, tx basecoin.
return h.initSeed(ctx, store, t)
case UpdateChainTx:
return h.updateSeed(ctx, store, t)
case CreatePacketTx:
return h.createPacket(ctx, store, t)
}
return res, errors.ErrUnknownTxType(tx.Unwrap())
}
@ -63,6 +76,8 @@ func (h Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoi
return h.initSeed(ctx, store, t)
case UpdateChainTx:
return h.updateSeed(ctx, store, t)
case CreatePacketTx:
return h.createPacket(ctx, store, t)
}
return res, errors.ErrUnknownTxType(tx.Unwrap())
}
@ -106,3 +121,45 @@ func (h Handler) updateSeed(ctx basecoin.Context, store state.KVStore,
err = cert.Update(seed.Checkpoint, seed.Validators)
return res, err
}
// 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,
t CreatePacketTx) (res basecoin.Result, err error) {
// make sure the chain is registed
dest := t.DestChain
if !NewChainSet(store).Exists([]byte(dest)) {
return res, ErrNotRegistered(dest)
}
// make sure we have the special IBC permission
mod, err := t.Tx.GetKind()
if err != nil {
return res, err
}
if !ctx.HasPermission(AllowIBC(mod)) {
return res, ErrNeedsIBCPermission()
}
// start making the packet to send
packet := Packet{
DestChain: t.DestChain,
Tx: t.Tx,
Permissions: make([]basecoin.Actor, len(t.Permissions)),
}
// make sure we have all the permissions we want to send
for i, p := range t.Permissions {
if !ctx.HasPermission(p) {
return res, ErrCannotSetPermission()
}
// add the permission with the current ChainID
packet.Permissions[i] = p
packet.Permissions[i].ChainID = ctx.ChainID()
}
// now add it to the output queue....
// TODO: where to store, also set the sequence....
return res, nil
}

View File

@ -1,6 +1,7 @@
package ibc
import (
"github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/stack"
"github.com/tendermint/basecoin/state"
wire "github.com/tendermint/go-wire"
@ -47,3 +48,17 @@ func (c ChainSet) Register(chainID string, ourHeight uint64, theirHeight int) er
c.Set.Set([]byte(chainID), data)
return nil
}
// Packet is a wrapped transaction and permission that we want to
// send off to another chain.
type Packet struct {
DestChain string `json:"dest_chain"`
Sequence int `json:"sequence"`
Permissions []basecoin.Actor `json:"permissions"`
Tx basecoin.Tx `json:"tx"`
}
// Bytes returns a serialization of the Packet
func (p Packet) Bytes() []byte {
return wire.BinaryBytes(p)
}

View File

@ -13,21 +13,21 @@ const (
// 0x3? series for ibc
ByteRegisterChain = byte(0x30)
ByteUpdateChain = byte(0x31)
BytePacketCreate = byte(0x32)
BytePacketPost = byte(0x33)
ByteCreatePacket = byte(0x32)
BytePostPacket = byte(0x33)
TypeRegisterChain = NameIBC + "/register"
TypeUpdateChain = NameIBC + "/update"
TypePacketCreate = NameIBC + "/create"
TypePacketPost = NameIBC + "/post"
TypeCreatePacket = NameIBC + "/create"
TypePostPacket = NameIBC + "/post"
)
func init() {
basecoin.TxMapper.
RegisterImplementation(RegisterChainTx{}, TypeRegisterChain, ByteRegisterChain).
RegisterImplementation(UpdateChainTx{}, TypeUpdateChain, ByteUpdateChain).
RegisterImplementation(PacketCreateTx{}, TypePacketCreate, BytePacketCreate).
RegisterImplementation(PacketPostTx{}, TypePacketPost, BytePacketPost)
RegisterImplementation(CreatePacketTx{}, TypeCreatePacket, ByteCreatePacket).
RegisterImplementation(PostPacketTx{}, TypePostPacket, BytePostPacket)
}
// RegisterChainTx allows you to register a new chain on this blockchain
@ -70,20 +70,21 @@ func (u UpdateChainTx) Wrap() basecoin.Tx {
return basecoin.Tx{u}
}
// PacketCreateTx is meant to be called by IPC, another module...
// CreatePacketTx is meant to be called by IPC, another module...
//
// this is the tx that will be sent to another app and the permissions it
// comes with (which must be a subset of the permissions on the current tx)
//
// TODO: how to control who can create packets (can I just signed create packet?)
type PacketCreateTx struct {
// If must have the special `AllowIBC` permission from the app
// that can send this packet (so only coins can request SendTx packet)
type CreatePacketTx struct {
DestChain string `json:"dest_chain"`
Permissions []basecoin.Actor `json:"permissions"`
Tx basecoin.Tx `json:"tx"`
}
// ValidateBasic makes sure this is consistent - used to satisfy TxInner
func (p PacketCreateTx) ValidateBasic() error {
func (p CreatePacketTx) ValidateBasic() error {
if p.DestChain == "" {
return errors.ErrNoChain()
}
@ -94,27 +95,32 @@ func (p PacketCreateTx) ValidateBasic() error {
}
// Wrap - used to satisfy TxInner
func (p PacketCreateTx) Wrap() basecoin.Tx {
func (p CreatePacketTx) Wrap() basecoin.Tx {
return basecoin.Tx{p}
}
// PacketPostTx takes a wrapped packet from another chain and
// PostPacketTx takes a wrapped packet from another chain and
// TODO!!!
type PacketPostTx struct {
// also think... which chains can relay packets???
// right now, enforce that these packets are only sent directly,
// not routed over the hub. add routing later.
type PostPacketTx struct {
// make sure we have this header...
FromChainID string // The immediate source of the packet, not always Packet.SrcChainID
FromChainHeight uint64 // The block height in which Packet was committed, to check Proof
Proof *merkle.IAVLProof
// Packet
// this proof must match the header and the packet.Bytes()
Proof *merkle.IAVLProof
Packet Packet
}
// ValidateBasic makes sure this is consistent - used to satisfy TxInner
func (p PacketPostTx) ValidateBasic() error {
func (p PostPacketTx) ValidateBasic() error {
// TODO
return nil
}
// Wrap - used to satisfy TxInner
func (p PacketPostTx) Wrap() basecoin.Tx {
func (p PostPacketTx) Wrap() basecoin.Tx {
return basecoin.Tx{p}
}