Refactored ibc test packet gen
This commit is contained in:
parent
0c5f0bdf77
commit
a925c8545c
@ -2,7 +2,6 @@ package ibc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -10,7 +9,6 @@ import (
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/light-client/certifiers"
|
||||
"github.com/tendermint/merkleeyes/iavl"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
@ -27,14 +25,6 @@ func noErr(err error) bool {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func genEmptySeed(keys certifiers.ValKeys, chain string, h int,
|
||||
appHash []byte, count int) certifiers.Seed {
|
||||
|
||||
vals := keys.ToValidators(10, 0)
|
||||
cp := keys.GenCheckpoint(chain, h, nil, vals, appHash, 0, count)
|
||||
return certifiers.Seed{cp, vals}
|
||||
}
|
||||
|
||||
// this tests registration without registrar permissions
|
||||
func TestIBCRegister(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
@ -339,73 +329,43 @@ func TestIBCCreatePacket(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func makePostPacket(tree *iavl.IAVLTree, packet Packet, fromID string, fromHeight int) PostPacketTx {
|
||||
key := []byte(fmt.Sprintf("some-long-prefix-%06d", packet.Sequence))
|
||||
tree.Set(key, packet.Bytes())
|
||||
_, proof := tree.ConstructProof(key)
|
||||
if proof == nil {
|
||||
panic("wtf?")
|
||||
}
|
||||
|
||||
return PostPacketTx{
|
||||
FromChainID: fromID,
|
||||
FromChainHeight: uint64(fromHeight),
|
||||
Proof: proof,
|
||||
Key: key,
|
||||
Packet: packet,
|
||||
}
|
||||
}
|
||||
|
||||
func updateChain(app basecoin.Handler, store state.KVStore, keys certifiers.ValKeys,
|
||||
chain string, h int, appHash []byte) error {
|
||||
seed := genEmptySeed(keys, chain, h, appHash, len(keys))
|
||||
tx := UpdateChainTx{seed}.Wrap()
|
||||
ctx := stack.MockContext("foo", 123)
|
||||
_, err := app.DeliverTx(ctx, store, tx)
|
||||
return err
|
||||
}
|
||||
|
||||
func TestIBCPostPacket(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
otherID := "chain-1"
|
||||
ourID := "hub"
|
||||
start := 200
|
||||
|
||||
// this is the root seed, that others are evaluated against
|
||||
keys := certifiers.GenValKeys(7)
|
||||
appHash := []byte("this is just random garbage")
|
||||
start := 100 // initial height
|
||||
root := genEmptySeed(keys, otherID, start, appHash, len(keys))
|
||||
|
||||
// create the app and register the root of trust (for chain-1)
|
||||
ctx := stack.MockContext(ourID, 50)
|
||||
store := state.NewMemKVStore()
|
||||
// create the app and our chain
|
||||
app := stack.New().
|
||||
IBC(NewMiddleware()).
|
||||
Dispatch(
|
||||
stack.WrapHandler(NewHandler()),
|
||||
stack.WrapHandler(coin.NewHandler()),
|
||||
)
|
||||
tx := RegisterChainTx{root}.Wrap()
|
||||
_, err := app.DeliverTx(ctx, store, tx)
|
||||
ourChain := NewAppChain(app, ourID)
|
||||
|
||||
// set up the other chain and register it with us
|
||||
otherChain := NewMockChain(otherID, 7)
|
||||
registerTx := otherChain.GetRegistrationTx(start).Wrap()
|
||||
_, err := ourChain.DeliverTx(registerTx)
|
||||
require.Nil(err, "%+v", err)
|
||||
|
||||
// set up a rich guy on this chain
|
||||
wealth := coin.Coins{{"btc", 300}, {"eth", 2000}, {"ltc", 5000}}
|
||||
rich := coin.NewAccountWithKey(wealth)
|
||||
_, err = app.SetOption(log.NewNopLogger(), store,
|
||||
"coin", "account", rich.MakeOption())
|
||||
_, err = ourChain.SetOption("coin", "account", rich.MakeOption())
|
||||
require.Nil(err, "%+v", err)
|
||||
|
||||
// sends money to another guy on a different chain, now other chain has credit
|
||||
buddy := basecoin.Actor{ChainID: otherID, App: auth.NameSigs, Address: []byte("dude")}
|
||||
outTx := coin.NewSendOneTx(rich.Actor(), buddy, wealth)
|
||||
_, err = app.DeliverTx(ctx.WithPermissions(rich.Actor()), store, outTx)
|
||||
_, err = ourChain.DeliverTx(outTx, rich.Actor())
|
||||
require.Nil(err, "%+v", err)
|
||||
|
||||
// make sure the money moved to the other chain...
|
||||
cstore := stack.PrefixedStore(coin.NameCoin, store)
|
||||
cstore := ourChain.GetStore(coin.NameCoin)
|
||||
acct, err := coin.GetAccount(cstore, coin.ChainAddr(buddy))
|
||||
require.Nil(err, "%+v", err)
|
||||
require.Equal(wealth, acct.Coins)
|
||||
@ -418,53 +378,29 @@ func TestIBCPostPacket(t *testing.T) {
|
||||
recipient,
|
||||
coin.Coins{{"eth", 100}, {"ltc", 300}},
|
||||
)
|
||||
wrongCoin := coin.NewSendOneTx(sender, recipient, coin.Coins{{"missing", 20}})
|
||||
|
||||
// make proofs for some packets....
|
||||
tree := iavl.NewIAVLTree(0, nil)
|
||||
pbad := Packet{
|
||||
DestChain: "something-else",
|
||||
Sequence: 0,
|
||||
Tx: coinTx,
|
||||
}
|
||||
packetBad := makePostPacket(tree, pbad, "something-else", 123)
|
||||
randomChain := NewMockChain("something-else", 4)
|
||||
pbad := NewPacket(coinTx, "something-else", 0)
|
||||
packetBad, _ := randomChain.MakePostPacket(pbad, 123)
|
||||
|
||||
p0 := Packet{
|
||||
DestChain: ourID,
|
||||
Sequence: 0,
|
||||
Permissions: basecoin.Actors{sender},
|
||||
Tx: coinTx,
|
||||
}
|
||||
p1 := Packet{
|
||||
DestChain: ourID,
|
||||
Sequence: 1,
|
||||
Permissions: basecoin.Actors{sender},
|
||||
Tx: coinTx,
|
||||
}
|
||||
// this sends money we don't have registered
|
||||
p2 := Packet{
|
||||
DestChain: ourID,
|
||||
Sequence: 2,
|
||||
Permissions: basecoin.Actors{sender},
|
||||
Tx: coin.NewSendOneTx(sender, recipient, coin.Coins{{"missing", 20}}),
|
||||
}
|
||||
|
||||
packet0 := makePostPacket(tree, p0, otherID, start+5)
|
||||
err = updateChain(app, store, keys, otherID, start+5, tree.Hash())
|
||||
require.Nil(err, "%+v", err)
|
||||
p0 := NewPacket(coinTx, ourID, 0, sender)
|
||||
packet0, update0 := otherChain.MakePostPacket(p0, start+5)
|
||||
require.Nil(ourChain.Update(update0))
|
||||
|
||||
packet0badHeight := packet0
|
||||
packet0badHeight.FromChainHeight -= 2
|
||||
|
||||
packet1 := makePostPacket(tree, p1, otherID, start+25)
|
||||
err = updateChain(app, store, keys, otherID, start+25, tree.Hash())
|
||||
require.Nil(err, "%+v", err)
|
||||
p1 := NewPacket(coinTx, ourID, 1, sender)
|
||||
packet1, update1 := otherChain.MakePostPacket(p1, start+25)
|
||||
require.Nil(ourChain.Update(update1))
|
||||
|
||||
packet1badProof := packet1
|
||||
packet1badProof.Key = []byte("random-data")
|
||||
|
||||
packet2 := makePostPacket(tree, p2, otherID, start+50)
|
||||
err = updateChain(app, store, keys, otherID, start+50, tree.Hash())
|
||||
require.Nil(err, "%+v", err)
|
||||
p2 := NewPacket(wrongCoin, ourID, 2, sender)
|
||||
packet2, update2 := otherChain.MakePostPacket(p2, start+50)
|
||||
require.Nil(ourChain.Update(update2))
|
||||
|
||||
ibcPerm := basecoin.Actors{AllowIBC(coin.NameCoin)}
|
||||
cases := []struct {
|
||||
@ -501,19 +437,7 @@ func TestIBCPostPacket(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
// cache wrap it like an app, so no state change on error...
|
||||
myStore := state.NewKVCache(store)
|
||||
|
||||
myCtx := ctx
|
||||
if len(tc.permissions) > 0 {
|
||||
myCtx = myCtx.WithPermissions(tc.permissions...)
|
||||
}
|
||||
_, err := app.DeliverTx(myCtx, myStore, tc.packet.Wrap())
|
||||
_, err := ourChain.DeliverTx(tc.packet.Wrap(), tc.permissions...)
|
||||
assert.True(tc.checker(err), "%d: %+v", i, err)
|
||||
|
||||
// only commit changes on success
|
||||
if err == nil {
|
||||
myStore.Sync()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,6 +86,16 @@ type Packet struct {
|
||||
Tx basecoin.Tx `json:"tx"`
|
||||
}
|
||||
|
||||
// NewPacket creates a new outgoing packet
|
||||
func NewPacket(tx basecoin.Tx, dest string, seq uint64, perm ...basecoin.Actor) Packet {
|
||||
return Packet{
|
||||
DestChain: dest,
|
||||
Sequence: seq,
|
||||
Permissions: perm,
|
||||
Tx: tx,
|
||||
}
|
||||
}
|
||||
|
||||
// Bytes returns a serialization of the Packet
|
||||
func (p Packet) Bytes() []byte {
|
||||
return wire.BinaryBytes(p)
|
||||
|
||||
129
modules/ibc/test_helpers.go
Normal file
129
modules/ibc/test_helpers.go
Normal file
@ -0,0 +1,129 @@
|
||||
package ibc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/light-client/certifiers"
|
||||
"github.com/tendermint/merkleeyes/iavl"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/stack"
|
||||
"github.com/tendermint/basecoin/state"
|
||||
)
|
||||
|
||||
// MockChain is used to simulate a chain for ibc tests.
|
||||
// It is able to produce ibc packets and all verification for
|
||||
// them, but cannot respond to any responses.
|
||||
type MockChain struct {
|
||||
keys certifiers.ValKeys
|
||||
chainID string
|
||||
tree *iavl.IAVLTree
|
||||
}
|
||||
|
||||
// NewMockChain initializes a teststore and test validators
|
||||
func NewMockChain(chainID string, numKeys int) MockChain {
|
||||
return MockChain{
|
||||
keys: certifiers.GenValKeys(numKeys),
|
||||
chainID: chainID,
|
||||
tree: iavl.NewIAVLTree(0, nil),
|
||||
}
|
||||
}
|
||||
|
||||
// GetRegistrationTx returns a valid tx to register this chain
|
||||
func (m MockChain) GetRegistrationTx(h int) RegisterChainTx {
|
||||
seed := genEmptySeed(m.keys, m.chainID, h, m.tree.Hash(), len(m.keys))
|
||||
return RegisterChainTx{seed}
|
||||
}
|
||||
|
||||
// MakePostPacket commits the packet locally and returns the proof,
|
||||
// in the form of two packets to update the header and prove this packet.
|
||||
func (m MockChain) MakePostPacket(packet Packet, h int) (
|
||||
PostPacketTx, UpdateChainTx) {
|
||||
|
||||
post := makePostPacket(m.tree, packet, m.chainID, h)
|
||||
seed := genEmptySeed(m.keys, m.chainID, h, m.tree.Hash(), len(m.keys))
|
||||
update := UpdateChainTx{seed}
|
||||
|
||||
return post, update
|
||||
}
|
||||
|
||||
func genEmptySeed(keys certifiers.ValKeys, chain string, h int,
|
||||
appHash []byte, count int) certifiers.Seed {
|
||||
|
||||
vals := keys.ToValidators(10, 0)
|
||||
cp := keys.GenCheckpoint(chain, h, nil, vals, appHash, 0, count)
|
||||
return certifiers.Seed{cp, vals}
|
||||
}
|
||||
|
||||
func makePostPacket(tree *iavl.IAVLTree, packet Packet, fromID string, fromHeight int) PostPacketTx {
|
||||
key := []byte(fmt.Sprintf("some-long-prefix-%06d", packet.Sequence))
|
||||
tree.Set(key, packet.Bytes())
|
||||
_, proof := tree.ConstructProof(key)
|
||||
if proof == nil {
|
||||
panic("wtf?")
|
||||
}
|
||||
|
||||
return PostPacketTx{
|
||||
FromChainID: fromID,
|
||||
FromChainHeight: uint64(fromHeight),
|
||||
Proof: proof,
|
||||
Key: key,
|
||||
Packet: packet,
|
||||
}
|
||||
}
|
||||
|
||||
// AppChain is ready to handle tx
|
||||
type AppChain struct {
|
||||
chainID string
|
||||
app basecoin.Handler
|
||||
store state.KVStore
|
||||
height int
|
||||
}
|
||||
|
||||
// NewAppChain returns a chain that is ready to respond to tx
|
||||
func NewAppChain(app basecoin.Handler, chainID string) *AppChain {
|
||||
return &AppChain{
|
||||
chainID: chainID,
|
||||
app: app,
|
||||
store: state.NewMemKVStore(),
|
||||
height: 123,
|
||||
}
|
||||
}
|
||||
|
||||
// IncrementHeight allows us to jump heights, more than the auto-step
|
||||
// of 1. It returns the new height we are at.
|
||||
func (a *AppChain) IncrementHeight(delta int) int {
|
||||
a.height += delta
|
||||
return a.height
|
||||
}
|
||||
|
||||
// DeliverTx runs the tx and commits the new tree, incrementing height
|
||||
// by one.
|
||||
func (a *AppChain) DeliverTx(tx basecoin.Tx, perms ...basecoin.Actor) (basecoin.Result, error) {
|
||||
ctx := stack.MockContext(a.chainID, uint64(a.height)).WithPermissions(perms...)
|
||||
store := state.NewKVCache(a.store)
|
||||
res, err := a.app.DeliverTx(ctx, store, tx)
|
||||
if err == nil {
|
||||
// commit data on success
|
||||
store.Sync()
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Update is a shortcut to DeliverTx with this. Also one return value
|
||||
// to test inline
|
||||
func (a *AppChain) Update(tx UpdateChainTx) error {
|
||||
_, err := a.DeliverTx(tx.Wrap())
|
||||
return err
|
||||
}
|
||||
|
||||
// SetOption sets the option on our app
|
||||
func (a *AppChain) SetOption(mod, key, value string) (string, error) {
|
||||
return a.app.SetOption(log.NewNopLogger(), a.store, mod, key, value)
|
||||
}
|
||||
|
||||
// GetStore is used to get the app-specific sub-store
|
||||
func (a *AppChain) GetStore(app string) state.KVStore {
|
||||
return stack.PrefixedStore(app, a.store)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user