cosmos-sdk/plugins/ibc/ibc_test.go

400 lines
11 KiB
Go
Raw Normal View History

2017-01-29 18:42:25 -08:00
package ibc
import (
"bytes"
"sort"
2017-01-29 18:42:25 -08:00
"strings"
"testing"
"github.com/stretchr/testify/assert"
2017-01-29 19:54:38 -08:00
abci "github.com/tendermint/abci/types"
2017-01-29 18:42:25 -08:00
"github.com/tendermint/basecoin/types"
cmn "github.com/tendermint/go-common"
2017-01-29 21:16:51 -08:00
crypto "github.com/tendermint/go-crypto"
2017-01-29 22:31:05 -08:00
"github.com/tendermint/go-merkle"
2017-01-29 18:42:25 -08:00
"github.com/tendermint/go-wire"
2017-01-29 19:54:38 -08:00
eyes "github.com/tendermint/merkleeyes/client"
2017-01-29 18:42:25 -08:00
tm "github.com/tendermint/tendermint/types"
)
// NOTE: PrivAccounts are sorted by Address,
// GenesisDoc, not necessarily.
2017-01-29 20:46:01 -08:00
func genGenesisDoc(chainID string, numVals int) (*tm.GenesisDoc, []types.PrivAccount) {
var privAccs []types.PrivAccount
2017-01-29 18:42:25 -08:00
genDoc := &tm.GenesisDoc{
ChainID: chainID,
Validators: nil,
}
for i := 0; i < numVals; i++ {
name := cmn.Fmt("%v_val_%v", chainID, i)
privAcc := types.PrivAccountFromSecret(name)
2017-01-29 18:42:25 -08:00
genDoc.Validators = append(genDoc.Validators, tm.GenesisValidator{
PubKey: privAcc.PubKey.PubKey,
2017-01-29 18:42:25 -08:00
Amount: 1,
Name: name,
})
2017-01-29 20:46:01 -08:00
privAccs = append(privAccs, privAcc)
2017-01-29 18:42:25 -08:00
}
// Sort PrivAccounts
sort.Sort(PrivAccountsByAddress(privAccs))
2017-01-29 20:46:01 -08:00
return genDoc, privAccs
2017-01-29 18:42:25 -08:00
}
//-------------------------------------
// Implements sort for sorting PrivAccount by address.
type PrivAccountsByAddress []types.PrivAccount
func (pas PrivAccountsByAddress) Len() int {
return len(pas)
}
func (pas PrivAccountsByAddress) Less(i, j int) bool {
return bytes.Compare(pas[i].Account.PubKey.Address(), pas[j].Account.PubKey.Address()) == -1
}
func (pas PrivAccountsByAddress) Swap(i, j int) {
it := pas[i]
pas[i] = pas[j]
pas[j] = it
}
//--------------------------------------------------------------------------------
2017-01-29 18:42:25 -08:00
func TestIBCPlugin(t *testing.T) {
2017-03-23 17:51:50 -07:00
assert := assert.New(t)
2017-01-29 18:42:25 -08:00
2017-01-29 22:31:05 -08:00
eyesClient := eyes.NewLocalClient("", 0)
store := types.NewKVCache(eyesClient)
2017-01-29 18:42:25 -08:00
store.SetLogging() // Log all activity
ibcPlugin := New()
ctx := types.CallContext{
CallerAddress: nil,
CallerAccount: nil,
Coins: types.Coins{},
}
chainID_1 := "test_chain"
2017-01-29 20:46:01 -08:00
genDoc_1, privAccs_1 := genGenesisDoc(chainID_1, 4)
2017-01-29 18:42:25 -08:00
genDocJSON_1 := wire.JSONBytesPretty(genDoc_1)
// Register a malformed chain
res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCRegisterChainTx{
BlockchainGenesis{
ChainID: "test_chain",
Genesis: "<THIS IS NOT JSON>",
},
}}))
2017-03-23 17:51:50 -07:00
assert.Equal(IBCCodeEncodingError, res.Code)
2017-01-29 18:42:25 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
// Successfully register a chain
res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCRegisterChainTx{
BlockchainGenesis{
ChainID: "test_chain",
Genesis: string(genDocJSON_1),
},
}}))
2017-03-23 17:51:50 -07:00
assert.True(res.IsOK(), res.Log)
2017-01-29 18:42:25 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
// Duplicate request fails
res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCRegisterChainTx{
BlockchainGenesis{
ChainID: "test_chain",
Genesis: string(genDocJSON_1),
},
}}))
2017-03-23 17:51:50 -07:00
assert.Equal(IBCCodeChainAlreadyExists, res.Code, res.Log)
2017-01-29 18:42:25 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
2017-01-29 19:54:38 -08:00
// Create a new packet (for testing)
2017-01-29 22:31:05 -08:00
packet := Packet{
SrcChainID: "test_chain",
DstChainID: "dst_chain",
Sequence: 0,
Type: "data",
Payload: []byte("hello world"),
}
2017-01-29 19:54:38 -08:00
res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{
2017-01-29 22:31:05 -08:00
Packet: packet,
2017-01-29 19:54:38 -08:00
}}))
2017-03-23 17:51:50 -07:00
assert.Equal(abci.CodeType_OK, res.Code, res.Log)
2017-01-29 19:54:38 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
// Post a duplicate packet
res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{
2017-01-29 22:31:05 -08:00
Packet: packet,
2017-01-29 19:54:38 -08:00
}}))
2017-03-23 17:51:50 -07:00
assert.Equal(IBCCodePacketAlreadyExists, res.Code, res.Log)
2017-01-29 19:54:38 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
2017-01-29 20:46:01 -08:00
// Construct a Header that includes the above packet.
2017-01-29 19:54:38 -08:00
store.Sync()
2017-01-29 22:31:05 -08:00
resCommit := eyesClient.CommitSync()
2017-01-29 20:46:01 -08:00
appHash := resCommit.Data
header := tm.Header{
ChainID: "test_chain",
Height: 999,
AppHash: appHash,
ValidatorsHash: []byte("must_exist"), // TODO make optional
2017-01-29 20:46:01 -08:00
}
// Construct a Commit that signs above header
blockHash := header.Hash()
blockID := tm.BlockID{Hash: blockHash}
commit := tm.Commit{
BlockID: blockID,
Precommits: make([]*tm.Vote, len(privAccs_1)),
}
for i, privAcc := range privAccs_1 {
vote := &tm.Vote{
ValidatorAddress: privAcc.Account.PubKey.Address(),
ValidatorIndex: i,
Height: 999,
Round: 0,
Type: tm.VoteTypePrecommit,
BlockID: tm.BlockID{Hash: blockHash},
2017-01-29 20:46:01 -08:00
}
vote.Signature = privAcc.PrivKey.Sign(
tm.SignBytes("test_chain", vote),
)
commit.Precommits[i] = vote
}
// Update a chain
res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCUpdateChainTx{
Header: header,
Commit: commit,
}}))
2017-03-23 17:51:50 -07:00
assert.Equal(abci.CodeType_OK, res.Code, res.Log)
2017-01-29 21:16:51 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
2017-01-29 22:31:05 -08:00
// Get proof for the packet
packetKey := toKey(_IBC, _EGRESS,
packet.SrcChainID,
packet.DstChainID,
cmn.Fmt("%v", packet.Sequence),
)
resQuery, err := eyesClient.QuerySync(abci.RequestQuery{
Path: "/store",
Data: packetKey,
Prove: true,
})
2017-03-23 17:51:50 -07:00
assert.Nil(err)
2017-01-29 22:31:05 -08:00
var proof *merkle.IAVLProof
err = wire.ReadBinaryBytes(resQuery.Proof, &proof)
2017-03-23 17:51:50 -07:00
assert.Nil(err)
2017-01-29 22:31:05 -08:00
// Post a packet
res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketPostTx{
FromChainID: "test_chain",
FromChainHeight: 999,
Packet: packet,
Proof: proof,
}}))
2017-03-23 17:51:50 -07:00
assert.Equal(abci.CodeType_OK, res.Code, res.Log)
2017-01-29 22:31:05 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
2017-01-29 21:52:26 -08:00
}
func TestIBCPluginBadCommit(t *testing.T) {
2017-03-23 17:51:50 -07:00
assert := assert.New(t)
2017-01-29 21:52:26 -08:00
2017-01-29 22:31:05 -08:00
eyesClient := eyes.NewLocalClient("", 0)
store := types.NewKVCache(eyesClient)
2017-01-29 21:52:26 -08:00
store.SetLogging() // Log all activity
ibcPlugin := New()
ctx := types.CallContext{
CallerAddress: nil,
CallerAccount: nil,
Coins: types.Coins{},
}
chainID_1 := "test_chain"
genDoc_1, privAccs_1 := genGenesisDoc(chainID_1, 4)
genDocJSON_1 := wire.JSONBytesPretty(genDoc_1)
// Successfully register a chain
res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCRegisterChainTx{
BlockchainGenesis{
ChainID: "test_chain",
Genesis: string(genDocJSON_1),
},
}}))
2017-03-23 17:51:50 -07:00
assert.True(res.IsOK(), res.Log)
2017-01-29 21:52:26 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
// Construct a Header
header := tm.Header{
ChainID: "test_chain",
Height: 999,
ValidatorsHash: []byte("must_exist"), // TODO make optional
}
// Construct a Commit that signs above header
blockHash := header.Hash()
blockID := tm.BlockID{Hash: blockHash}
commit := tm.Commit{
BlockID: blockID,
Precommits: make([]*tm.Vote, len(privAccs_1)),
}
for i, privAcc := range privAccs_1 {
vote := &tm.Vote{
ValidatorAddress: privAcc.Account.PubKey.Address(),
ValidatorIndex: i,
Height: 999,
Round: 0,
Type: tm.VoteTypePrecommit,
BlockID: tm.BlockID{Hash: blockHash},
}
vote.Signature = privAcc.PrivKey.Sign(
tm.SignBytes("test_chain", vote),
)
commit.Precommits[i] = vote
}
2017-01-29 21:16:51 -08:00
// Update a chain with a broken commit
// Modify the first byte of the first signature
sig := commit.Precommits[0].Signature.(crypto.SignatureEd25519)
sig[0] += 1
commit.Precommits[0].Signature = sig
res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCUpdateChainTx{
Header: header,
Commit: commit,
}}))
2017-03-23 17:51:50 -07:00
assert.Equal(IBCCodeInvalidCommit, res.Code, res.Log)
2017-01-29 20:46:01 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
2017-01-29 21:52:26 -08:00
2017-01-29 18:42:25 -08:00
}
2017-01-29 22:31:05 -08:00
func TestIBCPluginBadProof(t *testing.T) {
2017-03-23 17:51:50 -07:00
assert := assert.New(t)
2017-01-29 22:31:05 -08:00
eyesClient := eyes.NewLocalClient("", 0)
store := types.NewKVCache(eyesClient)
store.SetLogging() // Log all activity
ibcPlugin := New()
ctx := types.CallContext{
CallerAddress: nil,
CallerAccount: nil,
Coins: types.Coins{},
}
chainID_1 := "test_chain"
genDoc_1, privAccs_1 := genGenesisDoc(chainID_1, 4)
genDocJSON_1 := wire.JSONBytesPretty(genDoc_1)
// Successfully register a chain
res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCRegisterChainTx{
BlockchainGenesis{
ChainID: "test_chain",
Genesis: string(genDocJSON_1),
},
}}))
2017-03-23 17:51:50 -07:00
assert.True(res.IsOK(), res.Log)
2017-01-29 22:31:05 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
// Create a new packet (for testing)
packet := Packet{
SrcChainID: "test_chain",
DstChainID: "dst_chain",
Sequence: 0,
Type: "data",
Payload: []byte("hello world"),
}
res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{
Packet: packet,
}}))
2017-03-23 17:51:50 -07:00
assert.Equal(abci.CodeType_OK, res.Code, res.Log)
2017-01-29 22:31:05 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
// Construct a Header that includes the above packet.
store.Sync()
resCommit := eyesClient.CommitSync()
appHash := resCommit.Data
header := tm.Header{
ChainID: "test_chain",
Height: 999,
AppHash: appHash,
ValidatorsHash: []byte("must_exist"), // TODO make optional
}
// Construct a Commit that signs above header
blockHash := header.Hash()
blockID := tm.BlockID{Hash: blockHash}
commit := tm.Commit{
BlockID: blockID,
Precommits: make([]*tm.Vote, len(privAccs_1)),
}
for i, privAcc := range privAccs_1 {
vote := &tm.Vote{
ValidatorAddress: privAcc.Account.PubKey.Address(),
ValidatorIndex: i,
Height: 999,
Round: 0,
Type: tm.VoteTypePrecommit,
BlockID: tm.BlockID{Hash: blockHash},
}
vote.Signature = privAcc.PrivKey.Sign(
tm.SignBytes("test_chain", vote),
)
commit.Precommits[i] = vote
}
// Update a chain
res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCUpdateChainTx{
Header: header,
Commit: commit,
}}))
2017-03-23 17:51:50 -07:00
assert.Equal(abci.CodeType_OK, res.Code, res.Log)
2017-01-29 22:31:05 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
// Get proof for the packet
packetKey := toKey(_IBC, _EGRESS,
packet.SrcChainID,
packet.DstChainID,
cmn.Fmt("%v", packet.Sequence),
)
resQuery, err := eyesClient.QuerySync(abci.RequestQuery{
Path: "/store",
Data: packetKey,
Prove: true,
})
2017-03-23 17:51:50 -07:00
assert.Nil(err)
2017-01-29 22:31:05 -08:00
var proof *merkle.IAVLProof
err = wire.ReadBinaryBytes(resQuery.Proof, &proof)
2017-03-23 17:51:50 -07:00
assert.Nil(err)
2017-01-29 22:31:05 -08:00
// Mutate the proof
proof.InnerNodes[0].Height += 1
// Post a packet
res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketPostTx{
FromChainID: "test_chain",
FromChainHeight: 999,
Packet: packet,
Proof: proof,
}}))
2017-03-23 17:51:50 -07:00
assert.Equal(IBCCodeInvalidProof, res.Code, res.Log)
2017-01-29 22:31:05 -08:00
t.Log(">>", strings.Join(store.GetLogLines(), "\n"))
store.ClearLogLines()
}