Clean up ibc PostPacket handling
This commit is contained in:
parent
30eced21c5
commit
5da2b75fa0
11
context.go
11
context.go
|
@ -50,6 +50,17 @@ func (a Actor) WithChain(chainID string) (b Actor) {
|
|||
return
|
||||
}
|
||||
|
||||
type Actors []Actor
|
||||
|
||||
func (a Actors) AllHaveChain(chainID string) bool {
|
||||
for _, b := range a {
|
||||
if b.ChainID != chainID {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Context is an interface, so we can implement "secure" variants that
|
||||
// rely on private fields to control the actions
|
||||
type Context interface {
|
||||
|
|
|
@ -11,21 +11,22 @@ import (
|
|||
var (
|
||||
errChainNotRegistered = fmt.Errorf("Chain not registered")
|
||||
errChainAlreadyExists = fmt.Errorf("Chain already exists")
|
||||
errWrongDestChain = fmt.Errorf("This is not the destination")
|
||||
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")
|
||||
// errTooManyMembers = fmt.Errorf("Too many members specified")
|
||||
// errNotEnoughMembers = fmt.Errorf("Not enough members specified")
|
||||
errHeaderNotFound = fmt.Errorf("Header not found")
|
||||
errPacketAlreadyExists = fmt.Errorf("Packet already handled")
|
||||
errPacketOutOfOrder = fmt.Errorf("Packet out of order")
|
||||
errInvalidProof = fmt.Errorf("Invalid merkle proof")
|
||||
|
||||
IBCCodeChainNotRegistered = abci.CodeType(1001)
|
||||
IBCCodeChainAlreadyExists = abci.CodeType(1002)
|
||||
IBCCodePacketAlreadyExists = abci.CodeType(1003)
|
||||
IBCCodeUnknownHeight = abci.CodeType(1004)
|
||||
IBCCodeInvalidCommit = abci.CodeType(1005)
|
||||
IBCCodeInvalidProof = abci.CodeType(1006)
|
||||
IBCCodeInvalidCall = abci.CodeType(1007)
|
||||
IBCCodeChainNotRegistered = abci.CodeType(1001)
|
||||
IBCCodeChainAlreadyExists = abci.CodeType(1002)
|
||||
IBCCodeUnknownChain = abci.CodeType(1003)
|
||||
IBCCodeInvalidPacketSequence = abci.CodeType(1004)
|
||||
IBCCodeUnknownHeight = abci.CodeType(1005)
|
||||
IBCCodeInvalidCommit = abci.CodeType(1006)
|
||||
IBCCodeInvalidProof = abci.CodeType(1007)
|
||||
IBCCodeInvalidCall = abci.CodeType(1008)
|
||||
)
|
||||
|
||||
func ErrNotRegistered(chainID string) error {
|
||||
|
@ -42,6 +43,13 @@ func IsAlreadyRegistetedErr(err error) bool {
|
|||
return errors.IsSameError(errChainAlreadyExists, err)
|
||||
}
|
||||
|
||||
func ErrWrongDestChain(chainID string) error {
|
||||
return errors.WithMessage(chainID, errWrongDestChain, IBCCodeUnknownChain)
|
||||
}
|
||||
func IsWrongDestChainErr(err error) bool {
|
||||
return errors.IsSameError(errWrongDestChain, err)
|
||||
}
|
||||
|
||||
func ErrNeedsIBCPermission() error {
|
||||
return errors.WithCode(errNeedsIBCPermission, IBCCodeInvalidCall)
|
||||
}
|
||||
|
@ -55,3 +63,33 @@ func ErrCannotSetPermission() error {
|
|||
func IsCannotSetPermissionErr(err error) bool {
|
||||
return errors.IsSameError(errCannotSetPermission, err)
|
||||
}
|
||||
|
||||
func ErrHeaderNotFound(h int) error {
|
||||
msg := fmt.Sprintf("height %d", h)
|
||||
return errors.WithMessage(msg, errHeaderNotFound, IBCCodeUnknownHeight)
|
||||
}
|
||||
func IsHeaderNotFoundErr(err error) bool {
|
||||
return errors.IsSameError(errHeaderNotFound, err)
|
||||
}
|
||||
|
||||
func ErrPacketAlreadyExists() error {
|
||||
return errors.WithCode(errPacketAlreadyExists, IBCCodeInvalidPacketSequence)
|
||||
}
|
||||
func IsPacketAlreadyExistsErr(err error) bool {
|
||||
return errors.IsSameError(errPacketAlreadyExists, err)
|
||||
}
|
||||
|
||||
func ErrPacketOutOfOrder(seq uint64) error {
|
||||
msg := fmt.Sprintf("expected %d", seq)
|
||||
return errors.WithMessage(msg, errPacketOutOfOrder, IBCCodeInvalidPacketSequence)
|
||||
}
|
||||
func IsPacketOutOfOrderErr(err error) bool {
|
||||
return errors.IsSameError(errPacketOutOfOrder, err)
|
||||
}
|
||||
|
||||
func ErrInvalidProof() error {
|
||||
return errors.WithCode(errInvalidProof, IBCCodeInvalidProof)
|
||||
}
|
||||
func IsInvalidProofErr(err error) bool {
|
||||
return errors.IsSameError(errInvalidProof, err)
|
||||
}
|
||||
|
|
|
@ -92,6 +92,12 @@ func (h Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoi
|
|||
|
||||
switch t := tx.Unwrap().(type) {
|
||||
case RegisterChainTx:
|
||||
// check permission to attach, do it here, so no permission check
|
||||
// by SetOption
|
||||
info := LoadInfo(store)
|
||||
if !info.Registrar.Empty() && !ctx.HasPermission(info.Registrar) {
|
||||
return res, errors.ErrUnauthorized()
|
||||
}
|
||||
return h.initSeed(ctx, store, t)
|
||||
case UpdateChainTx:
|
||||
return h.updateSeed(ctx, store, t)
|
||||
|
@ -108,13 +114,6 @@ func (h Handler) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoi
|
|||
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
|
||||
info := LoadInfo(store)
|
||||
if !info.Registrar.Empty() && !ctx.HasPermission(info.Registrar) {
|
||||
return res, errors.ErrUnauthorized()
|
||||
}
|
||||
|
||||
chainID := t.ChainID()
|
||||
s := NewChainSet(store)
|
||||
err = s.Register(chainID, ctx.BlockHeight(), t.Seed.Height())
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package ibc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
"github.com/tendermint/basecoin/state"
|
||||
|
@ -68,40 +66,48 @@ func (m Middleware) verifyPost(ctx basecoin.Context, store state.KVStore,
|
|||
// make sure the chain is registered
|
||||
from := tx.FromChainID
|
||||
if !NewChainSet(store).Exists([]byte(from)) {
|
||||
err = ErrNotRegistered(from)
|
||||
return
|
||||
return ictx, itx, ErrNotRegistered(from)
|
||||
}
|
||||
|
||||
// TODO: how to deal with routing/relaying???
|
||||
packet := tx.Packet
|
||||
if packet.DestChain != ctx.ChainID() {
|
||||
return ictx, itx, ErrWrongDestChain(packet.DestChain)
|
||||
}
|
||||
|
||||
// verify packet.Permissions all come from the other chain
|
||||
if !packet.Permissions.AllHaveChain(tx.FromChainID) {
|
||||
return ictx, itx, ErrCannotSetPermission()
|
||||
}
|
||||
|
||||
// make sure this sequence number is the next in the list
|
||||
q := InputQueue(store, from)
|
||||
packet := tx.Packet
|
||||
if q.Tail() != packet.Sequence {
|
||||
err = errors.New("Incorrect sequence number - out of order") // TODO
|
||||
return
|
||||
tail := q.Tail()
|
||||
if packet.Sequence < tail {
|
||||
return ictx, itx, ErrPacketAlreadyExists()
|
||||
}
|
||||
if packet.Sequence > tail {
|
||||
return ictx, itx, ErrPacketOutOfOrder(tail)
|
||||
}
|
||||
|
||||
// look up the referenced header
|
||||
space := stack.PrefixedStore(from, store)
|
||||
provider := newDBProvider(space)
|
||||
// TODO: GetExactHeight helper?
|
||||
seed, err := provider.GetByHeight(int(tx.FromChainHeight))
|
||||
seed, err := provider.GetExactHeight(int(tx.FromChainHeight))
|
||||
if err != nil {
|
||||
return ictx, itx, err
|
||||
}
|
||||
if seed.Height() != int(tx.FromChainHeight) {
|
||||
err = errors.New("no such height") // TODO
|
||||
return
|
||||
}
|
||||
|
||||
// verify the merkle hash....
|
||||
root := seed.Header.AppHash
|
||||
key := []byte("?????") // TODO!
|
||||
tx.Proof.Verify(key, packet.Bytes(), root)
|
||||
|
||||
// TODO: verify packet.Permissions
|
||||
pBytes := packet.Bytes()
|
||||
valid := tx.Proof.Verify(tx.Key, pBytes, root)
|
||||
if !valid {
|
||||
return ictx, itx, ErrInvalidProof()
|
||||
}
|
||||
|
||||
// add to input queue
|
||||
q.Push(packet.Bytes())
|
||||
q.Push(pBytes)
|
||||
|
||||
// return the wrapped tx along with the extra permissions
|
||||
ictx = ictx.WithPermissions(packet.Permissions...)
|
||||
|
|
|
@ -80,3 +80,16 @@ func (d *dbProvider) GetByHash(hash []byte) (seed certifiers.Seed, err error) {
|
|||
err = wire.ReadBinaryBytes(b, &seed)
|
||||
return
|
||||
}
|
||||
|
||||
// GetExactHeight is like GetByHeight, but returns an error instead of
|
||||
// closest match if there is no exact match
|
||||
func (d *dbProvider) GetExactHeight(h int) (seed certifiers.Seed, err error) {
|
||||
seed, err = d.GetByHeight(h)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if seed.Height() != h {
|
||||
err = ErrHeaderNotFound(h)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -80,10 +80,10 @@ func (c ChainSet) Register(chainID string, ourHeight uint64, theirHeight int) er
|
|||
// 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 uint64 `json:"sequence"`
|
||||
Permissions []basecoin.Actor `json:"permissions"`
|
||||
Tx basecoin.Tx `json:"tx"`
|
||||
DestChain string `json:"dest_chain"`
|
||||
Sequence uint64 `json:"sequence"`
|
||||
Permissions basecoin.Actors `json:"permissions"`
|
||||
Tx basecoin.Tx `json:"tx"`
|
||||
}
|
||||
|
||||
// Bytes returns a serialization of the Packet
|
||||
|
|
|
@ -110,6 +110,7 @@ type PostPacketTx struct {
|
|||
FromChainHeight uint64 // The block height in which Packet was committed, to check Proof
|
||||
// this proof must match the header and the packet.Bytes()
|
||||
Proof *merkle.IAVLProof
|
||||
Key []byte
|
||||
Packet Packet
|
||||
}
|
||||
|
||||
|
@ -123,33 +124,3 @@ func (p PostPacketTx) ValidateBasic() error {
|
|||
func (p PostPacketTx) Wrap() basecoin.Tx {
|
||||
return basecoin.Tx{p}
|
||||
}
|
||||
|
||||
// proof := tx.Proof
|
||||
// if proof == nil {
|
||||
// sm.res.Code = IBCCodeInvalidProof
|
||||
// sm.res.Log = "Proof is nil"
|
||||
// return
|
||||
// }
|
||||
// packetBytes := wire.BinaryBytes(packet)
|
||||
|
||||
// // Make sure packet's proof matches given (packet, key, blockhash)
|
||||
// ok := proof.Verify(packetKeyEgress, packetBytes, header.AppHash)
|
||||
// if !ok {
|
||||
// sm.res.Code = IBCCodeInvalidProof
|
||||
// sm.res.Log = fmt.Sprintf("Proof is invalid. key: %s; packetByes %X; header %v; proof %v", packetKeyEgress, packetBytes, header, proof)
|
||||
// return
|
||||
// }
|
||||
|
||||
// // Execute payload
|
||||
// switch payload := packet.Payload.(type) {
|
||||
// case DataPayload:
|
||||
// // do nothing
|
||||
// case CoinsPayload:
|
||||
// // Add coins to destination account
|
||||
// acc := types.GetAccount(sm.store, payload.Address)
|
||||
// if acc == nil {
|
||||
// acc = &types.Account{}
|
||||
// }
|
||||
// acc.Balance = acc.Balance.Plus(payload.Coins)
|
||||
// types.SetAccount(sm.store, payload.Address, acc)
|
||||
// }
|
||||
|
|
Loading…
Reference in New Issue