From 697c2f1e049e83630f83b7491bb95a5217a5bfd3 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 13 Jul 2017 19:22:05 +0200 Subject: [PATCH] Started on ibc module tx, types --- modules/ibc/errors.go | 1 + modules/ibc/handler.go | 40 ++++++++++ modules/ibc/middleware.go | 37 ++++++++++ modules/ibc/provider.go | 44 +++++++++++ modules/ibc/store.go | 1 + modules/ibc/tx.go | 152 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 275 insertions(+) create mode 100644 modules/ibc/errors.go create mode 100644 modules/ibc/handler.go create mode 100644 modules/ibc/middleware.go create mode 100644 modules/ibc/provider.go create mode 100644 modules/ibc/store.go create mode 100644 modules/ibc/tx.go diff --git a/modules/ibc/errors.go b/modules/ibc/errors.go new file mode 100644 index 000000000..a81836a9c --- /dev/null +++ b/modules/ibc/errors.go @@ -0,0 +1 @@ +package ibc diff --git a/modules/ibc/handler.go b/modules/ibc/handler.go new file mode 100644 index 000000000..8de36d42d --- /dev/null +++ b/modules/ibc/handler.go @@ -0,0 +1,40 @@ +package ibc + +import ( + "github.com/tendermint/basecoin" + "github.com/tendermint/basecoin/state" +) + +// nolint +const ( + NameIBC = "ibc" +) + +// Handler allows us to update the chain state or create a packet +type Handler struct { + basecoin.NopOption +} + +var _ basecoin.Handler = Handler{} + +// NewHandler makes a role handler to create roles +func NewHandler() Handler { + return Handler{} +} + +// Name - return name space +func (Handler) Name() string { + return NameIBC +} + +// 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) { + return res, nil +} + +// 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) { + return res, nil +} diff --git a/modules/ibc/middleware.go b/modules/ibc/middleware.go new file mode 100644 index 000000000..cb32ea603 --- /dev/null +++ b/modules/ibc/middleware.go @@ -0,0 +1,37 @@ +package ibc + +import ( + "github.com/tendermint/basecoin" + "github.com/tendermint/basecoin/stack" + "github.com/tendermint/basecoin/state" +) + +// Middleware allows us to verify the IBC proof on a packet and +// and if valid, attach this permission to the wrapped packet +type Middleware struct { + stack.PassOption +} + +var _ stack.Middleware = Middleware{} + +// NewMiddleware creates a role-checking middleware +func NewMiddleware() Middleware { + return Middleware{} +} + +// Name - return name space +func (Middleware) Name() string { + return NameIBC +} + +// CheckTx verifies the named chain and height is present, and verifies +// the merkle proof in the packet +func (m Middleware) CheckTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.Checker) (res basecoin.Result, err error) { + return res, nil +} + +// DeliverTx verifies the named chain and height is present, and verifies +// the merkle proof in the packet +func (m Middleware) DeliverTx(ctx basecoin.Context, store state.KVStore, tx basecoin.Tx, next basecoin.Deliver) (res basecoin.Result, err error) { + return res, nil +} diff --git a/modules/ibc/provider.go b/modules/ibc/provider.go new file mode 100644 index 000000000..a28e6af95 --- /dev/null +++ b/modules/ibc/provider.go @@ -0,0 +1,44 @@ +package ibc + +import ( + "github.com/tendermint/light-client/certifiers" + + "github.com/tendermint/basecoin/stack" + "github.com/tendermint/basecoin/state" +) + +// newCertifier loads up the current state of this chain to make a proper +func newCertifier(chainID string, store state.KVStore) (*certifiers.InquiringCertifier, error) { + // each chain has their own prefixed subspace + space := stack.PrefixedStore(chainID, store) + p := dbProvider{space} + + // this gets the most recent verified seed + seed, err := certifiers.LatestSeed(p) + if err != nil { + return nil, err + } + + // we have no source for untrusted keys, but use the db to load trusted history + cert := certifiers.NewInquiring(chainID, seed.Validators, p, + certifiers.MissingProvider{}) + return cert, nil +} + +// dbProvider wraps our kv store so it integrates with light-client verification +type dbProvider struct { + store state.KVStore +} + +var _ certifiers.Provider = dbProvider{} + +func (d dbProvider) StoreSeed(seed certifiers.Seed) error { + return nil +} + +func (d dbProvider) GetByHeight(h int) (certifiers.Seed, error) { + return certifiers.Seed{}, certifiers.ErrSeedNotFound() +} +func (d dbProvider) GetByHash(hash []byte) (certifiers.Seed, error) { + return certifiers.Seed{}, certifiers.ErrSeedNotFound() +} diff --git a/modules/ibc/store.go b/modules/ibc/store.go new file mode 100644 index 000000000..a81836a9c --- /dev/null +++ b/modules/ibc/store.go @@ -0,0 +1 @@ +package ibc diff --git a/modules/ibc/tx.go b/modules/ibc/tx.go new file mode 100644 index 000000000..682758663 --- /dev/null +++ b/modules/ibc/tx.go @@ -0,0 +1,152 @@ +package ibc + +import ( + abci "github.com/tendermint/abci/types" + "github.com/tendermint/light-client/certifiers" + merkle "github.com/tendermint/merkleeyes/iavl" + + "github.com/tendermint/basecoin" + "github.com/tendermint/basecoin/errors" +) + +// nolint +const ( + // 0x3? series for ibc + ByteRegisterChain = byte(0x30) + ByteUpdateChain = byte(0x31) + BytePacketCreate = byte(0x32) + BytePacketPost = byte(0x33) + + TypeRegisterChain = NameIBC + "/register" + TypeUpdateChain = NameIBC + "/update" + TypePacketCreate = NameIBC + "/create" + TypePacketPost = NameIBC + "/post" + + IBCCodeEncodingError = abci.CodeType(1001) + IBCCodeChainAlreadyExists = abci.CodeType(1002) + IBCCodePacketAlreadyExists = abci.CodeType(1003) + IBCCodeUnknownHeight = abci.CodeType(1004) + IBCCodeInvalidCommit = abci.CodeType(1005) + IBCCodeInvalidProof = abci.CodeType(1006) +) + +func init() { + basecoin.TxMapper. + RegisterImplementation(RegisterChainTx{}, TypeRegisterChain, ByteRegisterChain). + RegisterImplementation(UpdateChainTx{}, TypeUpdateChain, ByteUpdateChain). + RegisterImplementation(PacketCreateTx{}, TypePacketCreate, BytePacketCreate). + RegisterImplementation(PacketPostTx{}, TypePacketPost, BytePacketPost) +} + +// RegisterChainTx allows you to register a new chain on this blockchain +type RegisterChainTx struct { + Seed certifiers.Seed `json:"seed"` +} + +// ChainID helps get the chain this tx refers to +func (r RegisterChainTx) ChainID() string { + return r.Seed.Header.ChainID +} + +// ValidateBasic makes sure this is consistent, without checking the sigs +func (r RegisterChainTx) ValidateBasic() error { + return r.Seed.ValidateBasic(r.ChainID()) +} + +// Wrap - used to satisfy TxInner +func (r RegisterChainTx) Wrap() basecoin.Tx { + return basecoin.Tx{r} +} + +// UpdateChainTx updates the state of this chain +type UpdateChainTx struct { + Seed certifiers.Seed `json:"seed"` +} + +// ChainID helps get the chain this tx refers to +func (u UpdateChainTx) ChainID() string { + return u.Seed.Header.ChainID +} + +// ValidateBasic makes sure this is consistent, without checking the sigs +func (u UpdateChainTx) ValidateBasic() error { + return u.Seed.ValidateBasic(u.ChainID()) +} + +// PacketCreateTx 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 { + 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 { + if p.DestChain == "" { + return errors.ErrNoChain() + } + // if len(p.Permissions) == 0 { + // return ErrNoPermissions() + // } + return nil +} + +// Wrap - used to satisfy TxInner +func (p PacketCreateTx) Wrap() basecoin.Tx { + return basecoin.Tx{p} +} + +// PacketPostTx takes a wrapped packet from another chain and +// TODO!!! +type PacketPostTx struct { + 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 +} + +// ValidateBasic makes sure this is consistent - used to satisfy TxInner +func (p PacketPostTx) ValidateBasic() error { + // TODO + return nil +} + +// Wrap - used to satisfy TxInner +func (p PacketPostTx) 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) +// }