diff --git a/glide.lock b/glide.lock index 00754a8ad8..e14238be1f 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: 3869944d14a8df914ffcad02c2ef3548173daba51c5ea697767f8af77c07b348 -updated: 2017-01-28T09:14:54.898268931-08:00 +updated: 2017-01-29T22:09:11.408245895-08:00 imports: - name: github.com/btcsuite/btcd version: afec1bd1245a4a19e6dfe1306974b733e7cbb9b8 @@ -9,6 +9,8 @@ imports: version: 637e656429416087660c84436a2a035d69d54e2e - name: github.com/BurntSushi/toml version: 99064174e013895bbd9b025c31100bd1d9b590ca +- name: github.com/ebuchman/fail-test + version: c1eddaa09da2b4017351245b0d43234955276798 - name: github.com/go-stack/stack version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82 - name: github.com/golang/protobuf @@ -46,6 +48,8 @@ imports: version: 8df0bc3a40ccad0d2be10e33c62c404e65c92502 subpackages: - client + - example/dummy + - example/nil - server - types - name: github.com/tendermint/ed25519 @@ -53,6 +57,10 @@ imports: subpackages: - edwards25519 - extra25519 +- name: github.com/tendermint/go-autofile + version: 0416e0aa9c68205aa44844096f9f151ada9d0405 +- name: github.com/tendermint/go-clist + version: 3baa390bbaf7634251c42ad69a8682e7e3990552 - name: github.com/tendermint/go-common version: 339e135776142939d82bc8e699db0bf391fd938d - name: github.com/tendermint/go-config @@ -79,23 +87,36 @@ imports: version: 6177eb8398ebd4613fbecb71fd96d7c7d97303ec subpackages: - client + - server - types - name: github.com/tendermint/go-wire - version: 2f3b7aafe21c80b19b6ee3210ecb3e3d07c7a471 + version: 3216ec9d47bbdf8d4fc27d22169ea86a6688bc15 - name: github.com/tendermint/log15 version: 9545b249b3aacafa97f79e0838b02b274adc6f5f subpackages: - term - name: github.com/tendermint/merkleeyes - version: 00d915af3e425cf57c10afe502fd9e0a6a70acd4 + version: 7c1ec0ef86c42b7a461e3967efb6c35bd5652101 subpackages: - app - client - name: github.com/tendermint/tendermint - version: 7c15b54cccac574cfe673c473d4edff01c2503ec + version: 67ab574e9889c0641ae959296d391e3cadec55e3 subpackages: + - blockchain + - config/tendermint + - consensus + - mempool + - node + - proxy + - rpc/core - rpc/core/types + - rpc/grpc + - state - types + - version +- name: github.com/urfave/cli + version: 8ef3805c9de2519805c3f060524b695bba2cd715 - name: golang.org/x/crypto version: aa2481cbfe81d911eb62b642b7a6b5ec58bbea71 subpackages: diff --git a/plugins/ibc/ibc.go b/plugins/ibc/ibc.go index 7662e9ec91..c337538744 100644 --- a/plugins/ibc/ibc.go +++ b/plugins/ibc/ibc.go @@ -121,7 +121,7 @@ type IBCPacketPostTx 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 Packet - Proof merkle.IAVLProof + Proof *merkle.IAVLProof } func (IBCPacketPostTx) ValidateBasic() (res abci.Result) { @@ -298,7 +298,7 @@ func (sm *IBCStateMachine) runPacketCreateTx(tx IBCPacketCreateTx) { return } // Save new Packet - save(sm.store, packetKey, wire.BinaryBytes(packet)) + save(sm.store, packetKey, packet) } func (sm *IBCStateMachine) runPacketPostTx(tx IBCPacketPostTx) { @@ -326,7 +326,7 @@ func (sm *IBCStateMachine) runPacketPostTx(tx IBCPacketPostTx) { } // Save new Packet - save(sm.store, packetKeyIngress, wire.BinaryBytes(packet)) + save(sm.store, packetKeyIngress, packet) // Load Header and make sure it exists var header tm.Header @@ -352,6 +352,11 @@ func (sm *IBCStateMachine) runPacketPostTx(tx IBCPacketPostTx) { } */ 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) diff --git a/plugins/ibc/ibc_test.go b/plugins/ibc/ibc_test.go index b0d9b62d5d..6bc3f0706e 100644 --- a/plugins/ibc/ibc_test.go +++ b/plugins/ibc/ibc_test.go @@ -12,6 +12,7 @@ import ( "github.com/tendermint/basecoin/types" cmn "github.com/tendermint/go-common" crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/go-merkle" "github.com/tendermint/go-wire" eyes "github.com/tendermint/merkleeyes/client" tm "github.com/tendermint/tendermint/types" @@ -66,8 +67,8 @@ func (pas PrivAccountsByAddress) Swap(i, j int) { func TestIBCPlugin(t *testing.T) { - tree := eyes.NewLocalClient("", 0) - store := types.NewKVCache(tree) + eyesClient := eyes.NewLocalClient("", 0) + store := types.NewKVCache(eyesClient) store.SetLogging() // Log all activity ibcPlugin := New() @@ -115,14 +116,15 @@ func TestIBCPlugin(t *testing.T) { 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{ - SrcChainID: "test_chain", - DstChainID: "dst_chain", - Sequence: 0, - Type: "data", - Payload: []byte("hello world"), - }, + Packet: packet, }})) assert.Equal(t, abci.CodeType_OK, res.Code, res.Log) t.Log(">>", strings.Join(store.GetLogLines(), "\n")) @@ -130,13 +132,7 @@ func TestIBCPlugin(t *testing.T) { // Post a duplicate packet res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ - Packet{ - SrcChainID: "test_chain", - DstChainID: "dst_chain", - Sequence: 0, - Type: "data", - Payload: []byte("hello world"), - }, + Packet: packet, }})) assert.Equal(t, IBCCodePacketAlreadyExists, res.Code, res.Log) t.Log(">>", strings.Join(store.GetLogLines(), "\n")) @@ -144,7 +140,7 @@ func TestIBCPlugin(t *testing.T) { // Construct a Header that includes the above packet. store.Sync() - resCommit := tree.CommitSync() + resCommit := eyesClient.CommitSync() appHash := resCommit.Data header := tm.Header{ ChainID: "test_chain", @@ -183,12 +179,39 @@ func TestIBCPlugin(t *testing.T) { assert.Equal(t, abci.CodeType_OK, res.Code, res.Log) 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, + }) + assert.Nil(t, err) + var proof *merkle.IAVLProof + err = wire.ReadBinaryBytes(resQuery.Proof, &proof) + assert.Nil(t, err) + + // Post a packet + res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketPostTx{ + FromChainID: "test_chain", + FromChainHeight: 999, + Packet: packet, + Proof: proof, + }})) + assert.Equal(t, abci.CodeType_OK, res.Code, res.Log) + t.Log(">>", strings.Join(store.GetLogLines(), "\n")) + store.ClearLogLines() } func TestIBCPluginBadCommit(t *testing.T) { - tree := eyes.NewLocalClient("", 0) - store := types.NewKVCache(tree) + eyesClient := eyes.NewLocalClient("", 0) + store := types.NewKVCache(eyesClient) store.SetLogging() // Log all activity ibcPlugin := New() @@ -256,3 +279,119 @@ func TestIBCPluginBadCommit(t *testing.T) { store.ClearLogLines() } + +func TestIBCPluginBadProof(t *testing.T) { + + 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), + }, + }})) + assert.True(t, res.IsOK(), res.Log) + 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, + }})) + assert.Equal(t, abci.CodeType_OK, res.Code, res.Log) + 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, + }})) + assert.Equal(t, abci.CodeType_OK, res.Code, res.Log) + 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, + }) + assert.Nil(t, err) + var proof *merkle.IAVLProof + err = wire.ReadBinaryBytes(resQuery.Proof, &proof) + assert.Nil(t, err) + + // 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, + }})) + assert.Equal(t, IBCCodeInvalidProof, res.Code, res.Log) + t.Log(">>", strings.Join(store.GetLogLines(), "\n")) + store.ClearLogLines() +}