diff --git a/manager/eris-mint/eris-mint_test.go b/manager/eris-mint/eris-mint_test.go index 98a03d2ff4b5abf6df26a2550dbd57e28192ad50..294c34e233db0c260c3a0b3fd5993ad789d56231 100644 --- a/manager/eris-mint/eris-mint_test.go +++ b/manager/eris-mint/eris-mint_test.go @@ -23,7 +23,7 @@ import ( ) func TestCompatibleConsensus(t *testing.T) { - // TODO: [ben] expand by constructing and elemetary testing for each listed + // TODO: [ben] expand by constructing and elementary testing for each listed // compatible consensus engine for _, listedConsensus := range compatibleConsensus { diff --git a/manager/eris-mint/pipe.go b/manager/eris-mint/pipe.go index 3783a5720ecb21f1341f6593d8c4436ad3c2cb16..265a16fa7c385d670fda67026cd96bb152e3d989 100644 --- a/manager/eris-mint/pipe.go +++ b/manager/eris-mint/pipe.go @@ -550,12 +550,12 @@ func (pipe *erisMintPipe) BroadcastTxSync(tx txs.Tx) (*rpc_tm_types.ResultBroadc func (pipe *erisMintPipe) BlockchainInfo(minHeight, maxHeight, maxBlockLookback int) (*rpc_tm_types.ResultBlockchainInfo, error) { - height := pipe.consensusEngine.Height() + latestHeight := pipe.consensusEngine.Height() if maxHeight < 1 { - maxHeight = height + maxHeight = latestHeight } else { - maxHeight = imath.MinInt(height, maxHeight) + maxHeight = imath.MinInt(latestHeight, maxHeight) } if minHeight < 1 { minHeight = imath.MaxInt(1, maxHeight-maxBlockLookback) @@ -567,5 +567,5 @@ func (pipe *erisMintPipe) BlockchainInfo(minHeight, maxHeight, blockMetas = append(blockMetas, blockMeta) } - return &rpc_tm_types.ResultBlockchainInfo{height, blockMetas}, nil + return &rpc_tm_types.ResultBlockchainInfo{latestHeight, blockMetas}, nil } diff --git a/rpc/tendermint/test/client_rpc_test.go b/rpc/tendermint/test/client_rpc_test.go index 1bb84efc2d4e2b94beb4c60fc23a115f1803bd00..1a0a725df29d089b1180435a74e9df380f243a96 100644 --- a/rpc/tendermint/test/client_rpc_test.go +++ b/rpc/tendermint/test/client_rpc_test.go @@ -57,6 +57,13 @@ func TestHTTPNameReg(t *testing.T) { testNameReg(t, "HTTP") } +func TestHTTPBlockchainInfo(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + testBlockchainInfo(t, "HTTP") +} + //-------------------------------------------------------------------------------- // Test the JSONRPC client @@ -102,3 +109,10 @@ func TestJSONNameReg(t *testing.T) { } testNameReg(t, "JSONRPC") } + +func TestJSONBlockchainInfo(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + testBlockchainInfo(t, "JSONRPC") +} diff --git a/rpc/tendermint/test/tests.go b/rpc/tendermint/test/tests.go index c8fac0d627b5e60c18dad3b6b3e997893994a2b1..43769b4b0f6f972c151b41c35ed2269ab9ad7a40 100644 --- a/rpc/tendermint/test/tests.go +++ b/rpc/tendermint/test/tests.go @@ -153,12 +153,12 @@ func testCall(t *testing.T, typ string) { t.Fatalf("Problem broadcasting transaction: %v", err) } assert.Equal(t, uint8(1), receipt.CreatesContract, "This transaction should"+ - " create a contract") + " create a contract") assert.NotEqual(t, 0, len(receipt.TxHash), "Receipt should contain a"+ - " transaction hash") + " transaction hash") contractAddr := receipt.ContractAddr assert.NotEqual(t, 0, len(contractAddr), "Transactions claims to have"+ - " created a contract but the contract address is empty") + " created a contract but the contract address is empty") // run a call through the contract data := []byte{} @@ -202,7 +202,7 @@ func testNameReg(t *testing.T, typ string) { assert.Equal(t, user[0].Address, entry.Owner) // update the data as the owner, make sure still there - numDesiredBlocks = int64(3) + numDesiredBlocks = int64(5) const updatedData = "these are amongst the things I wish to bestow upon the youth of generations come: a safe supply of honey, and a better money. For what else shall they need" amt = fee + numDesiredBlocks*txs.NameByteCostMultiplier*txs.NameBlockCostMultiplier*txs.NameBaseCost(name, updatedData) tx = makeDefaultNameTx(t, typ, name, updatedData, amt, fee) @@ -220,9 +220,11 @@ func testNameReg(t *testing.T, typ string) { _, err := broadcastTxAndWaitForBlock(t, typ, wsc, tx) assert.Error(t, err, "Expected error when updating someone else's unexpired"+ " name registry entry") + assert.Contains(t, err.Error(), "permission denied", "Error should be " + + "permission denied") // Wait a couple of blocks to make sure name registration expires - waitNBlocks(t, wsc, 2) + waitNBlocks(t, wsc, 3) //now the entry should be expired, so we can update as non owner const data2 = "this is not my beautiful house" @@ -303,3 +305,38 @@ Subscribe: } } } + +func testBlockchainInfo(t *testing.T, typ string) { + client := clients[typ] + wsc := newWSClient(t) + nBlocks := 4 + waitNBlocks(t, wsc, nBlocks) + + resp, err := edbcli.BlockchainInfo(client, 0, 0) + if err != nil { + t.Fatalf("Failed to get blockchain info: %v", err) + } + //TODO: [Silas] reintroduce this when Tendermint changes logic to fire + // NewBlock after saving a block + // see https://github.com/tendermint/tendermint/issues/273 + //assert.Equal(t, 4, resp.LastHeight, "Last height should be 4 after waiting for first 4 blocks") + assert.True(t, nBlocks <= len(resp.BlockMetas), + "Should see at least 4 BlockMetas after waiting for first 4 blocks") + + lastBlockHash := resp.BlockMetas[nBlocks-1].Hash + for i := nBlocks - 2; i >= 0; i-- { + assert.Equal(t, lastBlockHash, resp.BlockMetas[i].Header.LastBlockHash, + "Blockchain should be a hash tree!") + lastBlockHash = resp.BlockMetas[i].Hash + } + + resp, err = edbcli.BlockchainInfo(client, 1, 2) + if err != nil { + t.Fatalf("Failed to get blockchain info: %v", err) + } + + assert.Equal(t, 2, len(resp.BlockMetas), + "Should see 2 BlockMetas after extracting 2 blocks") + + fmt.Printf("%v\n", resp) +} diff --git a/rpc/tendermint/test/ws_helpers.go b/rpc/tendermint/test/ws_helpers.go index ed92bca14d5414cfb024895c69ff2a27577b1b05..1c71a72b812193f75004e8886e562b090c2f6d83 100644 --- a/rpc/tendermint/test/ws_helpers.go +++ b/rpc/tendermint/test/ws_helpers.go @@ -81,7 +81,12 @@ func broadcastTxAndWaitForBlock(t *testing.T, typ string, wsc *client.WSClient, initialHeight = block.Height return false } else { - return block.Height > initialHeight + // TODO: [Silas] remove the + 1 here. It is a workaround for the fact + // that tendermint fires the NewBlock event before it has finalised its + // state updates, so we have to wait for the block after the block we + // want in order for the Tx to be genuinely final. + // This should be addressed by: https://github.com/tendermint/tendermint/pull/265 + return block.Height > initialHeight + 1 } }, func() { @@ -96,7 +101,7 @@ func waitNBlocks(t *testing.T, wsc *client.WSClient, n int) { runThenWaitForBlock(t, wsc, func(block *tm_types.Block) bool { i++ - return i <= n + return i >= n }, func() {}) } @@ -131,10 +136,11 @@ func subscribeAndWaitForNext(t *testing.T, wsc *client.WSClient, event string, // waitForEvent will fail the test. func waitForEvent(t *testing.T, wsc *client.WSClient, eventid string, runner func(), - eventDataChecker func(string, txs.EventData) (bool, error)) waitForEventError { + eventDataChecker func(string, txs.EventData) (bool, error)) waitForEventResult { // go routine to wait for websocket msg - goodCh := make(chan txs.EventData) + eventsCh := make(chan txs.EventData) + shutdownEventsCh := make(chan bool, 1) errCh := make(chan error) // do stuff (transactions) @@ -146,6 +152,8 @@ func waitForEvent(t *testing.T, wsc *client.WSClient, eventid string, LOOP: for { select { + case <-shutdownEventsCh: + break LOOP case r := <-wsc.ResultsCh: result := new(ctypes.ErisDBResult) wire.ReadJSONPtr(result, r, &err) @@ -155,8 +163,8 @@ func waitForEvent(t *testing.T, wsc *client.WSClient, eventid string, } event, ok := (*result).(*ctypes.ResultEvent) if ok && event.Event == eventid { - goodCh <- event.Data - break LOOP + // Keep feeding events + eventsCh <- event.Data } case err := <-wsc.ErrorsCh: errCh <- err @@ -167,20 +175,22 @@ func waitForEvent(t *testing.T, wsc *client.WSClient, eventid string, } }() - // wait for an event or timeout - timeout := time.NewTimer(timeoutSeconds * time.Second) + // Don't block up WSClient + defer func() { shutdownEventsCh <- true }() + for { select { - case <-timeout.C: - return waitForEventError{timeout: true} - case eventData := <-goodCh: + // wait for an event or timeout + case <-time.After(timeoutSeconds * time.Second): + return waitForEventResult{timeout: true} + case eventData := <-eventsCh: // run the check stopWaiting, err := eventDataChecker(eventid, eventData) if err != nil { t.Fatal(err) // Show the stack trace. } if stopWaiting { - return waitForEventError{} + return waitForEventResult{} } case err := <-errCh: t.Fatal(err) @@ -188,12 +198,12 @@ func waitForEvent(t *testing.T, wsc *client.WSClient, eventid string, } } -type waitForEventError struct { +type waitForEventResult struct { error timeout bool } -func (err waitForEventError) Timeout() bool { +func (err waitForEventResult) Timeout() bool { return err.timeout }