service: remove stop method and use contexts (#7292)

This commit is contained in:
Sam Kleinman
2021-11-18 17:56:21 -05:00
committed by GitHub
parent 1c34d17240
commit 6ab62fe7b6
115 changed files with 3613 additions and 2271 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ func dialerFunc(ctx context.Context, addr string) (net.Conn, error) {
return tmnet.Connect(addr)
}
func (cli *grpcClient) OnStart() error {
func (cli *grpcClient) OnStart(ctx context.Context) error {
// This processes asynchronous request/response messages and dispatches
// them to callbacks.
go func() {
+5 -73
View File
@@ -7,8 +7,6 @@ import (
abciclient "github.com/tendermint/tendermint/abci/client"
log "github.com/tendermint/tendermint/libs/log"
mock "github.com/stretchr/testify/mock"
types "github.com/tendermint/tendermint/abci/types"
@@ -636,39 +634,6 @@ func (_m *Client) OfferSnapshotSync(_a0 context.Context, _a1 types.RequestOfferS
return r0, r1
}
// OnReset provides a mock function with given fields:
func (_m *Client) OnReset() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// OnStart provides a mock function with given fields:
func (_m *Client) OnStart() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// OnStop provides a mock function with given fields:
func (_m *Client) OnStop() {
_m.Called()
}
// QueryAsync provides a mock function with given fields: _a0, _a1
func (_m *Client) QueryAsync(_a0 context.Context, _a1 types.RequestQuery) (*abciclient.ReqRes, error) {
ret := _m.Called(_a0, _a1)
@@ -731,51 +696,18 @@ func (_m *Client) Quit() <-chan struct{} {
return r0
}
// Reset provides a mock function with given fields:
func (_m *Client) Reset() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// SetLogger provides a mock function with given fields: _a0
func (_m *Client) SetLogger(_a0 log.Logger) {
_m.Called(_a0)
}
// SetResponseCallback provides a mock function with given fields: _a0
func (_m *Client) SetResponseCallback(_a0 abciclient.Callback) {
_m.Called(_a0)
}
// Start provides a mock function with given fields:
func (_m *Client) Start() error {
ret := _m.Called()
// Start provides a mock function with given fields: _a0
func (_m *Client) Start(_a0 context.Context) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// Stop provides a mock function with given fields:
func (_m *Client) Stop() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
+17 -9
View File
@@ -66,7 +66,7 @@ func NewSocketClient(logger log.Logger, addr string, mustConnect bool) Client {
// OnStart implements Service by connecting to the server and spawning reading
// and writing goroutines.
func (cli *socketClient) OnStart() error {
func (cli *socketClient) OnStart(ctx context.Context) error {
var (
err error
conn net.Conn
@@ -85,8 +85,8 @@ func (cli *socketClient) OnStart() error {
}
cli.conn = conn
go cli.sendRequestsRoutine(conn)
go cli.recvResponseRoutine(conn)
go cli.sendRequestsRoutine(ctx, conn)
go cli.recvResponseRoutine(ctx, conn)
return nil
}
@@ -114,17 +114,25 @@ func (cli *socketClient) Error() error {
// NOTE: callback may get internally generated flush responses.
func (cli *socketClient) SetResponseCallback(resCb Callback) {
cli.mtx.Lock()
defer cli.mtx.Unlock()
cli.resCb = resCb
cli.mtx.Unlock()
}
//----------------------------------------
func (cli *socketClient) sendRequestsRoutine(conn io.Writer) {
func (cli *socketClient) sendRequestsRoutine(ctx context.Context, conn io.Writer) {
bw := bufio.NewWriter(conn)
for {
select {
case <-ctx.Done():
return
case <-cli.Quit():
return
case reqres := <-cli.reqQueue:
if ctx.Err() != nil {
return
}
if reqres.C.Err() != nil {
cli.Logger.Debug("Request's context is done", "req", reqres.R, "err", reqres.C.Err())
continue
@@ -139,16 +147,16 @@ func (cli *socketClient) sendRequestsRoutine(conn io.Writer) {
cli.stopForError(fmt.Errorf("flush buffer: %w", err))
return
}
case <-cli.Quit():
return
}
}
}
func (cli *socketClient) recvResponseRoutine(conn io.Reader) {
func (cli *socketClient) recvResponseRoutine(ctx context.Context, conn io.Reader) {
r := bufio.NewReader(conn)
for {
if ctx.Err() != nil {
return
}
var res = &types.Response{}
err := types.ReadMessage(r, res)
if err != nil {
+13 -63
View File
@@ -18,30 +18,21 @@ import (
"github.com/tendermint/tendermint/libs/service"
)
var ctx = context.Background()
func TestProperSyncCalls(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
app := slowApp{}
logger := log.TestingLogger()
s, c := setupClientServer(t, logger, app)
t.Cleanup(func() {
if err := s.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() {
if err := c.Stop(); err != nil {
t.Error(err)
}
})
_, c := setupClientServer(ctx, t, logger, app)
resp := make(chan error, 1)
go func() {
// This is BeginBlockSync unrolled....
reqres, err := c.BeginBlockAsync(ctx, types.RequestBeginBlock{})
assert.NoError(t, err)
err = c.FlushSync(context.Background())
err = c.FlushSync(ctx)
assert.NoError(t, err)
res := reqres.Response.GetBeginBlock()
assert.NotNil(t, res)
@@ -57,52 +48,8 @@ func TestProperSyncCalls(t *testing.T) {
}
}
func TestHangingSyncCalls(t *testing.T) {
app := slowApp{}
logger := log.TestingLogger()
s, c := setupClientServer(t, logger, app)
t.Cleanup(func() {
if err := s.Stop(); err != nil {
t.Log(err)
}
})
t.Cleanup(func() {
if err := c.Stop(); err != nil {
t.Log(err)
}
})
resp := make(chan error, 1)
go func() {
// Start BeginBlock and flush it
reqres, err := c.BeginBlockAsync(ctx, types.RequestBeginBlock{})
assert.NoError(t, err)
flush, err := c.FlushAsync(ctx)
assert.NoError(t, err)
// wait 20 ms for all events to travel socket, but
// no response yet from server
time.Sleep(20 * time.Millisecond)
// kill the server, so the connections break
err = s.Stop()
assert.NoError(t, err)
// wait for the response from BeginBlock
reqres.Wait()
flush.Wait()
resp <- c.Error()
}()
select {
case <-time.After(time.Second):
require.Fail(t, "No response arrived")
case err, ok := <-resp:
require.True(t, ok, "Must not close channel")
assert.Error(t, err, "We should get EOF error")
}
}
func setupClientServer(
ctx context.Context,
t *testing.T,
logger log.Logger,
app types.Application,
@@ -115,12 +62,15 @@ func setupClientServer(
s, err := server.NewServer(logger, addr, "socket", app)
require.NoError(t, err)
err = s.Start()
require.NoError(t, err)
require.NoError(t, s.Start(ctx))
t.Cleanup(s.Wait)
c := abciclient.NewSocketClient(logger, addr, true)
err = c.Start()
require.NoError(t, err)
require.NoError(t, c.Start(ctx))
t.Cleanup(c.Wait)
require.True(t, s.IsRunning())
require.True(t, c.IsRunning())
return s, c
}
+32 -34
View File
@@ -2,18 +2,18 @@ package main
import (
"bufio"
"context"
"encoding/hex"
"errors"
"fmt"
"io"
"os"
"os/signal"
"strings"
"syscall"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
abciclient "github.com/tendermint/tendermint/abci/client"
"github.com/tendermint/tendermint/abci/example/code"
@@ -29,8 +29,6 @@ import (
var (
client abciclient.Client
logger log.Logger
ctx = context.Background()
)
// flags
@@ -71,7 +69,8 @@ var RootCmd = &cobra.Command{
if err != nil {
return err
}
if err := client.Start(); err != nil {
if err := client.Start(cmd.Context()); err != nil {
return err
}
}
@@ -291,23 +290,24 @@ func compose(fs []func() error) error {
}
func cmdTest(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
return compose(
[]func() error{
func() error { return servertest.InitChain(client) },
func() error { return servertest.Commit(client, nil) },
func() error { return servertest.DeliverTx(client, []byte("abc"), code.CodeTypeBadNonce, nil) },
func() error { return servertest.Commit(client, nil) },
func() error { return servertest.DeliverTx(client, []byte{0x00}, code.CodeTypeOK, nil) },
func() error { return servertest.Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 1}) },
func() error { return servertest.DeliverTx(client, []byte{0x00}, code.CodeTypeBadNonce, nil) },
func() error { return servertest.DeliverTx(client, []byte{0x01}, code.CodeTypeOK, nil) },
func() error { return servertest.DeliverTx(client, []byte{0x00, 0x02}, code.CodeTypeOK, nil) },
func() error { return servertest.DeliverTx(client, []byte{0x00, 0x03}, code.CodeTypeOK, nil) },
func() error { return servertest.DeliverTx(client, []byte{0x00, 0x00, 0x04}, code.CodeTypeOK, nil) },
func() error { return servertest.InitChain(ctx, client) },
func() error { return servertest.Commit(ctx, client, nil) },
func() error { return servertest.DeliverTx(ctx, client, []byte("abc"), code.CodeTypeBadNonce, nil) },
func() error { return servertest.Commit(ctx, client, nil) },
func() error { return servertest.DeliverTx(ctx, client, []byte{0x00}, code.CodeTypeOK, nil) },
func() error { return servertest.Commit(ctx, client, []byte{0, 0, 0, 0, 0, 0, 0, 1}) },
func() error { return servertest.DeliverTx(ctx, client, []byte{0x00}, code.CodeTypeBadNonce, nil) },
func() error { return servertest.DeliverTx(ctx, client, []byte{0x01}, code.CodeTypeOK, nil) },
func() error { return servertest.DeliverTx(ctx, client, []byte{0x00, 0x02}, code.CodeTypeOK, nil) },
func() error { return servertest.DeliverTx(ctx, client, []byte{0x00, 0x03}, code.CodeTypeOK, nil) },
func() error { return servertest.DeliverTx(ctx, client, []byte{0x00, 0x00, 0x04}, code.CodeTypeOK, nil) },
func() error {
return servertest.DeliverTx(client, []byte{0x00, 0x00, 0x06}, code.CodeTypeBadNonce, nil)
return servertest.DeliverTx(ctx, client, []byte{0x00, 0x00, 0x06}, code.CodeTypeBadNonce, nil)
},
func() error { return servertest.Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 5}) },
func() error { return servertest.Commit(ctx, client, []byte{0, 0, 0, 0, 0, 0, 0, 5}) },
})
}
@@ -442,13 +442,15 @@ func cmdEcho(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
msg = args[0]
}
res, err := client.EchoSync(ctx, msg)
res, err := client.EchoSync(cmd.Context(), msg)
if err != nil {
return err
}
printResponse(cmd, args, response{
Data: []byte(res.Message),
})
return nil
}
@@ -458,7 +460,7 @@ func cmdInfo(cmd *cobra.Command, args []string) error {
if len(args) == 1 {
version = args[0]
}
res, err := client.InfoSync(ctx, types.RequestInfo{Version: version})
res, err := client.InfoSync(cmd.Context(), types.RequestInfo{Version: version})
if err != nil {
return err
}
@@ -483,7 +485,7 @@ func cmdDeliverTx(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
res, err := client.DeliverTxSync(ctx, types.RequestDeliverTx{Tx: txBytes})
res, err := client.DeliverTxSync(cmd.Context(), types.RequestDeliverTx{Tx: txBytes})
if err != nil {
return err
}
@@ -509,7 +511,7 @@ func cmdCheckTx(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
res, err := client.CheckTxSync(ctx, types.RequestCheckTx{Tx: txBytes})
res, err := client.CheckTxSync(cmd.Context(), types.RequestCheckTx{Tx: txBytes})
if err != nil {
return err
}
@@ -524,7 +526,7 @@ func cmdCheckTx(cmd *cobra.Command, args []string) error {
// Get application Merkle root hash
func cmdCommit(cmd *cobra.Command, args []string) error {
res, err := client.CommitSync(ctx)
res, err := client.CommitSync(cmd.Context())
if err != nil {
return err
}
@@ -549,7 +551,7 @@ func cmdQuery(cmd *cobra.Command, args []string) error {
return err
}
resQuery, err := client.QuerySync(ctx, types.RequestQuery{
resQuery, err := client.QuerySync(cmd.Context(), types.RequestQuery{
Data: queryBytes,
Path: flagPath,
Height: int64(flagHeight),
@@ -590,20 +592,16 @@ func cmdKVStore(cmd *cobra.Command, args []string) error {
return err
}
if err := srv.Start(); err != nil {
ctx, cancel := signal.NotifyContext(cmd.Context(), syscall.SIGTERM)
defer cancel()
if err := srv.Start(ctx); err != nil {
return err
}
// Stop upon receiving SIGTERM or CTRL-C.
tmos.TrapSignal(logger, func() {
// Cleanup
if err := srv.Stop(); err != nil {
logger.Error("Error while stopping server", "err", err)
}
})
// Run forever.
select {}
<-ctx.Done()
return nil
}
//--------------------------------------------------------------------------------
+19 -26
View File
@@ -29,21 +29,29 @@ func init() {
}
func TestKVStore(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fmt.Println("### Testing KVStore")
testStream(t, kvstore.NewApplication())
testStream(ctx, t, kvstore.NewApplication())
}
func TestBaseApp(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fmt.Println("### Testing BaseApp")
testStream(t, types.NewBaseApplication())
testStream(ctx, t, types.NewBaseApplication())
}
func TestGRPC(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fmt.Println("### Testing GRPC")
testGRPCSync(t, types.NewGRPCApplication(types.NewBaseApplication()))
testGRPCSync(ctx, t, types.NewGRPCApplication(types.NewBaseApplication()))
}
func testStream(t *testing.T, app types.Application) {
func testStream(ctx context.Context, t *testing.T, app types.Application) {
t.Helper()
const numDeliverTxs = 20000
@@ -53,25 +61,16 @@ func testStream(t *testing.T, app types.Application) {
logger := log.TestingLogger()
// Start the listener
server := abciserver.NewSocketServer(logger.With("module", "abci-server"), socket, app)
err := server.Start()
t.Cleanup(server.Wait)
err := server.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := server.Stop(); err != nil {
t.Error(err)
}
})
// Connect to the socket
client := abciclient.NewSocketClient(log.TestingLogger().With("module", "abci-client"), socket, false)
t.Cleanup(client.Wait)
err = client.Start()
err = client.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := client.Stop(); err != nil {
t.Error(err)
}
})
done := make(chan struct{})
counter := 0
@@ -100,8 +99,6 @@ func testStream(t *testing.T, app types.Application) {
}
})
ctx := context.Background()
// Write requests
for counter := 0; counter < numDeliverTxs; counter++ {
// Send request
@@ -129,7 +126,7 @@ func dialerFunc(ctx context.Context, addr string) (net.Conn, error) {
return tmnet.Connect(addr)
}
func testGRPCSync(t *testing.T, app types.ABCIApplicationServer) {
func testGRPCSync(ctx context.Context, t *testing.T, app types.ABCIApplicationServer) {
numDeliverTxs := 2000
socketFile := fmt.Sprintf("/tmp/test-%08x.sock", rand.Int31n(1<<30))
defer os.Remove(socketFile)
@@ -138,15 +135,11 @@ func testGRPCSync(t *testing.T, app types.ABCIApplicationServer) {
// Start the listener
server := abciserver.NewGRPCServer(logger.With("module", "abci-server"), socket, app)
if err := server.Start(); err != nil {
if err := server.Start(ctx); err != nil {
t.Fatalf("Error starting GRPC server: %v", err.Error())
}
t.Cleanup(func() {
if err := server.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { server.Wait() })
// Connect to the socket
conn, err := grpc.Dial(socket, grpc.WithInsecure(), grpc.WithContextDialer(dialerFunc))
+44 -44
View File
@@ -24,8 +24,6 @@ const (
testValue = "def"
)
var ctx = context.Background()
func testKVStore(t *testing.T, app types.Application, tx []byte, key, value string) {
req := types.RequestDeliverTx{Tx: tx}
ar := app.DeliverTx(req)
@@ -229,101 +227,103 @@ func valsEqual(t *testing.T, vals1, vals2 []types.ValidatorUpdate) {
}
}
func makeSocketClientServer(app types.Application, name string) (abciclient.Client, service.Service, error) {
func makeSocketClientServer(
ctx context.Context,
t *testing.T,
logger log.Logger,
app types.Application,
name string,
) (abciclient.Client, service.Service, error) {
ctx, cancel := context.WithCancel(ctx)
t.Cleanup(cancel)
// Start the listener
socket := fmt.Sprintf("unix://%s.sock", name)
logger := log.TestingLogger()
server := abciserver.NewSocketServer(logger.With("module", "abci-server"), socket, app)
if err := server.Start(); err != nil {
if err := server.Start(ctx); err != nil {
cancel()
return nil, nil, err
}
// Connect to the socket
client := abciclient.NewSocketClient(logger.With("module", "abci-client"), socket, false)
if err := client.Start(); err != nil {
if err = server.Stop(); err != nil {
return nil, nil, err
}
if err := client.Start(ctx); err != nil {
cancel()
return nil, nil, err
}
return client, server, nil
}
func makeGRPCClientServer(app types.Application, name string) (abciclient.Client, service.Service, error) {
func makeGRPCClientServer(
ctx context.Context,
t *testing.T,
logger log.Logger,
app types.Application,
name string,
) (abciclient.Client, service.Service, error) {
ctx, cancel := context.WithCancel(ctx)
t.Cleanup(cancel)
// Start the listener
socket := fmt.Sprintf("unix://%s.sock", name)
logger := log.TestingLogger()
gapp := types.NewGRPCApplication(app)
server := abciserver.NewGRPCServer(logger.With("module", "abci-server"), socket, gapp)
if err := server.Start(); err != nil {
if err := server.Start(ctx); err != nil {
cancel()
return nil, nil, err
}
client := abciclient.NewGRPCClient(logger.With("module", "abci-client"), socket, true)
if err := client.Start(); err != nil {
if err := server.Stop(); err != nil {
return nil, nil, err
}
if err := client.Start(ctx); err != nil {
cancel()
return nil, nil, err
}
return client, server, nil
}
func TestClientServer(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger := log.TestingLogger()
// set up socket app
kvstore := NewApplication()
client, server, err := makeSocketClientServer(kvstore, "kvstore-socket")
client, server, err := makeSocketClientServer(ctx, t, logger, kvstore, "kvstore-socket")
require.NoError(t, err)
t.Cleanup(func() {
if err := server.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() {
if err := client.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); server.Wait() })
t.Cleanup(func() { cancel(); client.Wait() })
runClientTests(t, client)
runClientTests(ctx, t, client)
// set up grpc app
kvstore = NewApplication()
gclient, gserver, err := makeGRPCClientServer(kvstore, "/tmp/kvstore-grpc")
gclient, gserver, err := makeGRPCClientServer(ctx, t, logger, kvstore, "/tmp/kvstore-grpc")
require.NoError(t, err)
t.Cleanup(func() {
if err := gserver.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() {
if err := gclient.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); gserver.Wait() })
t.Cleanup(func() { cancel(); gclient.Wait() })
runClientTests(t, gclient)
runClientTests(ctx, t, gclient)
}
func runClientTests(t *testing.T, client abciclient.Client) {
func runClientTests(ctx context.Context, t *testing.T, client abciclient.Client) {
// run some tests....
key := testKey
value := key
tx := []byte(key)
testClient(t, client, tx, key, value)
testClient(ctx, t, client, tx, key, value)
value = testValue
tx = []byte(key + "=" + value)
testClient(t, client, tx, key, value)
testClient(ctx, t, client, tx, key, value)
}
func testClient(t *testing.T, app abciclient.Client, tx []byte, key, value string) {
func testClient(ctx context.Context, t *testing.T, app abciclient.Client, tx []byte, key, value string) {
ar, err := app.DeliverTxSync(ctx, types.RequestDeliverTx{Tx: tx})
require.NoError(t, err)
require.False(t, ar.IsErr(), ar)
+2 -1
View File
@@ -1,6 +1,7 @@
package server
import (
"context"
"net"
"google.golang.org/grpc"
@@ -36,7 +37,7 @@ func NewGRPCServer(logger log.Logger, protoAddr string, app types.ABCIApplicatio
}
// OnStart starts the gRPC service.
func (s *GRPCServer) OnStart() error {
func (s *GRPCServer) OnStart(ctx context.Context) error {
ln, err := net.Listen(s.proto, s.addr)
if err != nil {
+48 -22
View File
@@ -2,6 +2,7 @@ package server
import (
"bufio"
"context"
"fmt"
"io"
"net"
@@ -44,14 +45,14 @@ func NewSocketServer(logger tmlog.Logger, protoAddr string, app types.Applicatio
return s
}
func (s *SocketServer) OnStart() error {
func (s *SocketServer) OnStart(ctx context.Context) error {
ln, err := net.Listen(s.proto, s.addr)
if err != nil {
return err
}
s.listener = ln
go s.acceptConnectionsRoutine()
go s.acceptConnectionsRoutine(ctx)
return nil
}
@@ -63,6 +64,7 @@ func (s *SocketServer) OnStop() {
s.connsMtx.Lock()
defer s.connsMtx.Unlock()
for id, conn := range s.conns {
delete(s.conns, id)
if err := conn.Close(); err != nil {
@@ -96,8 +98,13 @@ func (s *SocketServer) rmConn(connID int) error {
return conn.Close()
}
func (s *SocketServer) acceptConnectionsRoutine() {
func (s *SocketServer) acceptConnectionsRoutine(ctx context.Context) {
for {
if ctx.Err() != nil {
return
}
// Accept a connection
s.Logger.Info("Waiting for new connection...")
conn, err := s.listener.Accept()
@@ -117,35 +124,46 @@ func (s *SocketServer) acceptConnectionsRoutine() {
responses := make(chan *types.Response, 1000) // A channel to buffer responses
// Read requests from conn and deal with them
go s.handleRequests(closeConn, conn, responses)
go s.handleRequests(ctx, closeConn, conn, responses)
// Pull responses from 'responses' and write them to conn.
go s.handleResponses(closeConn, conn, responses)
go s.handleResponses(ctx, closeConn, conn, responses)
// Wait until signal to close connection
go s.waitForClose(closeConn, connID)
go s.waitForClose(ctx, closeConn, connID)
}
}
func (s *SocketServer) waitForClose(closeConn chan error, connID int) {
err := <-closeConn
switch {
case err == io.EOF:
s.Logger.Error("Connection was closed by client")
case err != nil:
s.Logger.Error("Connection error", "err", err)
default:
// never happens
s.Logger.Error("Connection was closed")
}
func (s *SocketServer) waitForClose(ctx context.Context, closeConn chan error, connID int) {
defer func() {
// Close the connection
if err := s.rmConn(connID); err != nil {
s.Logger.Error("Error closing connection", "err", err)
}
}()
// Close the connection
if err := s.rmConn(connID); err != nil {
s.Logger.Error("Error closing connection", "err", err)
select {
case <-ctx.Done():
return
case err := <-closeConn:
switch {
case err == io.EOF:
s.Logger.Error("Connection was closed by client")
case err != nil:
s.Logger.Error("Connection error", "err", err)
default:
// never happens
s.Logger.Error("Connection was closed")
}
}
}
// Read requests from conn and deal with them
func (s *SocketServer) handleRequests(closeConn chan error, conn io.Reader, responses chan<- *types.Response) {
func (s *SocketServer) handleRequests(
ctx context.Context,
closeConn chan error,
conn io.Reader,
responses chan<- *types.Response,
) {
var count int
var bufReader = bufio.NewReader(conn)
@@ -163,6 +181,9 @@ func (s *SocketServer) handleRequests(closeConn chan error, conn io.Reader, resp
}()
for {
if ctx.Err() != nil {
return
}
var req = &types.Request{}
err := types.ReadMessage(bufReader, req)
@@ -229,7 +250,12 @@ func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types
}
// Pull responses from 'responses' and write them to conn.
func (s *SocketServer) handleResponses(closeConn chan error, conn io.Writer, responses <-chan *types.Response) {
func (s *SocketServer) handleResponses(
ctx context.Context,
closeConn chan error,
conn io.Writer,
responses <-chan *types.Response,
) {
bw := bufio.NewWriter(conn)
for res := range responses {
if err := types.WriteMessage(res, bw); err != nil {
+10 -5
View File
@@ -1,6 +1,7 @@
package tests
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
@@ -12,19 +13,23 @@ import (
)
func TestClientServerNoAddrPrefix(t *testing.T) {
addr := "localhost:26658"
transport := "socket"
app := kvstore.NewApplication()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
const (
addr = "localhost:26658"
transport = "socket"
)
app := kvstore.NewApplication()
logger := log.TestingLogger()
server, err := abciserver.NewServer(logger, addr, transport, app)
assert.NoError(t, err, "expected no error on NewServer")
err = server.Start()
err = server.Start(ctx)
assert.NoError(t, err, "expected no error on server.Start")
client, err := abciclientent.NewClient(logger, addr, transport, true)
assert.NoError(t, err, "expected no error on NewClient")
err = client.Start()
err = client.Start(ctx)
assert.NoError(t, err, "expected no error on client.Start")
}
+4 -6
View File
@@ -12,9 +12,7 @@ import (
tmrand "github.com/tendermint/tendermint/libs/rand"
)
var ctx = context.Background()
func InitChain(client abciclient.Client) error {
func InitChain(ctx context.Context, client abciclient.Client) error {
total := 10
vals := make([]types.ValidatorUpdate, total)
for i := 0; i < total; i++ {
@@ -34,7 +32,7 @@ func InitChain(client abciclient.Client) error {
return nil
}
func Commit(client abciclient.Client, hashExp []byte) error {
func Commit(ctx context.Context, client abciclient.Client, hashExp []byte) error {
res, err := client.CommitSync(ctx)
data := res.Data
if err != nil {
@@ -51,7 +49,7 @@ func Commit(client abciclient.Client, hashExp []byte) error {
return nil
}
func DeliverTx(client abciclient.Client, txBytes []byte, codeExp uint32, dataExp []byte) error {
func DeliverTx(ctx context.Context, client abciclient.Client, txBytes []byte, codeExp uint32, dataExp []byte) error {
res, _ := client.DeliverTxSync(ctx, types.RequestDeliverTx{Tx: txBytes})
code, data, log := res.Code, res.Data, res.Log
if code != codeExp {
@@ -70,7 +68,7 @@ func DeliverTx(client abciclient.Client, txBytes []byte, codeExp uint32, dataExp
return nil
}
func CheckTx(client abciclient.Client, txBytes []byte, codeExp uint32, dataExp []byte) error {
func CheckTx(ctx context.Context, client abciclient.Client, txBytes []byte, codeExp uint32, dataExp []byte) error {
res, _ := client.CheckTxSync(ctx, types.RequestCheckTx{Tx: txBytes})
code, data, log := res.Code, res.Data, res.Log
if code != codeExp {
+7 -1
View File
@@ -6,8 +6,10 @@ import (
"fmt"
"net/http"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
"github.com/spf13/cobra"
@@ -191,8 +193,12 @@ func runProxy(cmd *cobra.Command, args []string) error {
p.Listener.Close()
})
// this might be redundant to the above, eventually.
ctx, cancel := signal.NotifyContext(cmd.Context(), syscall.SIGTERM)
defer cancel()
logger.Info("Starting proxy...", "laddr", listenAddr)
if err := p.ListenAndServe(); err != http.ErrServerClosed {
if err := p.ListenAndServe(ctx); err != http.ErrServerClosed {
// Error starting or closing listener:
logger.Error("proxy ListenAndServe", "err", err)
}
+2 -3
View File
@@ -10,8 +10,7 @@ var ReplayCmd = &cobra.Command{
Use: "replay",
Short: "Replay messages from WAL",
RunE: func(cmd *cobra.Command, args []string) error {
return consensus.RunReplayFile(logger, config.BaseConfig, config.Consensus, false)
return consensus.RunReplayFile(cmd.Context(), logger, config.BaseConfig, config.Consensus, false)
},
}
@@ -21,6 +20,6 @@ var ReplayConsoleCmd = &cobra.Command{
Use: "replay-console",
Short: "Replay messages from WAL in a console",
RunE: func(cmd *cobra.Command, args []string) error {
return consensus.RunReplayFile(logger, config.BaseConfig, config.Consensus, true)
return consensus.RunReplayFile(cmd.Context(), logger, config.BaseConfig, config.Consensus, true)
},
}
+9 -14
View File
@@ -6,11 +6,12 @@ import (
"fmt"
"io"
"os"
"os/signal"
"syscall"
"github.com/spf13/cobra"
cfg "github.com/tendermint/tendermint/config"
tmos "github.com/tendermint/tendermint/libs/os"
)
var (
@@ -103,28 +104,22 @@ func NewRunNodeCmd(nodeProvider cfg.ServiceProvider) *cobra.Command {
return err
}
n, err := nodeProvider(config, logger)
ctx, cancel := signal.NotifyContext(cmd.Context(), syscall.SIGTERM)
defer cancel()
n, err := nodeProvider(ctx, config, logger)
if err != nil {
return fmt.Errorf("failed to create node: %w", err)
}
if err := n.Start(); err != nil {
if err := n.Start(ctx); err != nil {
return fmt.Errorf("failed to start node: %w", err)
}
logger.Info("started node", "node", n.String())
// Stop upon receiving SIGTERM or CTRL-C.
tmos.TrapSignal(logger, func() {
if n.IsRunning() {
if err := n.Stop(); err != nil {
logger.Error("unable to stop the node", "error", err)
}
}
})
// Run forever.
select {}
<-ctx.Done()
return nil
},
}
+3 -1
View File
@@ -1,6 +1,8 @@
package config
import (
"context"
dbm "github.com/tendermint/tm-db"
"github.com/tendermint/tendermint/libs/log"
@@ -8,7 +10,7 @@ import (
)
// ServiceProvider takes a config and a logger and returns a ready to go Node.
type ServiceProvider func(*Config, log.Logger) (service.Service, error)
type ServiceProvider func(context.Context, *Config, log.Logger) (service.Service, error)
// DBContext specifies config information for loading a new DB.
type DBContext struct {
+1 -1
View File
@@ -178,7 +178,7 @@ type TrustMetricStore struct {
}
// OnStart implements Service
func (tms *TrustMetricStore) OnStart() error {}
func (tms *TrustMetricStore) OnStart(context.Context) error { return nil }
// OnStop implements Service
func (tms *TrustMetricStore) OnStop() {}
+8 -7
View File
@@ -1,6 +1,7 @@
package blocksync
import (
"context"
"errors"
"fmt"
"math"
@@ -116,15 +117,15 @@ func NewBlockPool(
// OnStart implements service.Service by spawning requesters routine and recording
// pool's start time.
func (pool *BlockPool) OnStart() error {
func (pool *BlockPool) OnStart(ctx context.Context) error {
pool.lastAdvance = time.Now()
pool.lastHundredBlockTimeStamp = pool.lastAdvance
go pool.makeRequestersRoutine()
go pool.makeRequestersRoutine(ctx)
return nil
}
// spawns requesters as needed
func (pool *BlockPool) makeRequestersRoutine() {
func (pool *BlockPool) makeRequestersRoutine(ctx context.Context) {
for {
if !pool.IsRunning() {
break
@@ -144,7 +145,7 @@ func (pool *BlockPool) makeRequestersRoutine() {
pool.removeTimedoutPeers()
default:
// request for more blocks.
pool.makeNextRequester()
pool.makeNextRequester(ctx)
}
}
}
@@ -397,7 +398,7 @@ func (pool *BlockPool) pickIncrAvailablePeer(height int64) *bpPeer {
return nil
}
func (pool *BlockPool) makeNextRequester() {
func (pool *BlockPool) makeNextRequester(ctx context.Context) {
pool.mtx.Lock()
defer pool.mtx.Unlock()
@@ -411,7 +412,7 @@ func (pool *BlockPool) makeNextRequester() {
pool.requesters[nextHeight] = request
atomic.AddInt32(&pool.numPending, 1)
err := request.Start()
err := request.Start(ctx)
if err != nil {
request.Logger.Error("Error starting request", "err", err)
}
@@ -570,7 +571,7 @@ func newBPRequester(pool *BlockPool, height int64) *bpRequester {
return bpr
}
func (bpr *bpRequester) OnStart() error {
func (bpr *bpRequester) OnStart(ctx context.Context) error {
go bpr.requestRoutine()
return nil
}
+16 -19
View File
@@ -1,6 +1,7 @@
package blocksync
import (
"context"
"fmt"
mrand "math/rand"
"testing"
@@ -78,22 +79,20 @@ func makePeers(numPeers int, minHeight, maxHeight int64) testPeers {
}
func TestBlockPoolBasic(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
start := int64(42)
peers := makePeers(10, start+1, 1000)
errorsCh := make(chan peerError, 1000)
requestsCh := make(chan BlockRequest, 1000)
pool := NewBlockPool(log.TestingLogger(), start, requestsCh, errorsCh)
err := pool.Start()
if err != nil {
if err := pool.Start(ctx); err != nil {
t.Error(err)
}
t.Cleanup(func() {
if err := pool.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); pool.Wait() })
peers.start()
defer peers.stop()
@@ -137,20 +136,19 @@ func TestBlockPoolBasic(t *testing.T) {
}
func TestBlockPoolTimeout(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
start := int64(42)
peers := makePeers(10, start+1, 1000)
errorsCh := make(chan peerError, 1000)
requestsCh := make(chan BlockRequest, 1000)
pool := NewBlockPool(log.TestingLogger(), start, requestsCh, errorsCh)
err := pool.Start()
err := pool.Start(ctx)
if err != nil {
t.Error(err)
}
t.Cleanup(func() {
if err := pool.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); pool.Wait() })
for _, peer := range peers {
t.Logf("Peer %v", peer.id)
@@ -199,6 +197,9 @@ func TestBlockPoolTimeout(t *testing.T) {
}
func TestBlockPoolRemovePeer(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
peers := make(testPeers, 10)
for i := 0; i < 10; i++ {
peerID := types.NodeID(fmt.Sprintf("%d", i+1))
@@ -209,13 +210,9 @@ func TestBlockPoolRemovePeer(t *testing.T) {
errorsCh := make(chan peerError)
pool := NewBlockPool(log.TestingLogger(), 1, requestsCh, errorsCh)
err := pool.Start()
err := pool.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := pool.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); pool.Wait() })
// add peers
for peerID, peer := range peers {
+19 -6
View File
@@ -1,6 +1,7 @@
package blocksync
import (
"context"
"fmt"
"runtime/debug"
"sync"
@@ -49,7 +50,7 @@ func GetChannelDescriptor() *p2p.ChannelDescriptor {
type consensusReactor interface {
// For when we switch from block sync reactor to the consensus
// machine.
SwitchToConsensus(state sm.State, skipWAL bool)
SwitchToConsensus(ctx context.Context, state sm.State, skipWAL bool)
}
type peerError struct {
@@ -151,9 +152,9 @@ func NewReactor(
//
// If blockSync is enabled, we also start the pool and the pool processing
// goroutine. If the pool fails to start, an error is returned.
func (r *Reactor) OnStart() error {
func (r *Reactor) OnStart(ctx context.Context) error {
if r.blockSync.IsSet() {
if err := r.pool.Start(); err != nil {
if err := r.pool.Start(ctx); err != nil {
return err
}
r.poolWG.Add(1)
@@ -362,12 +363,12 @@ func (r *Reactor) processPeerUpdates() {
// SwitchToBlockSync is called by the state sync reactor when switching to fast
// sync.
func (r *Reactor) SwitchToBlockSync(state sm.State) error {
func (r *Reactor) SwitchToBlockSync(ctx context.Context, state sm.State) error {
r.blockSync.Set()
r.initialState = state
r.pool.height = state.LastBlockHeight + 1
if err := r.pool.Start(); err != nil {
if err := r.pool.Start(ctx); err != nil {
return err
}
@@ -423,6 +424,17 @@ func (r *Reactor) requestRoutine() {
}
}
func (r *Reactor) stopCtx() context.Context {
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-r.closeCh
cancel()
}()
return ctx
}
// poolRoutine handles messages from the poolReactor telling the reactor what to
// do.
//
@@ -441,6 +453,7 @@ func (r *Reactor) poolRoutine(stateSynced bool) {
lastRate = 0.0
didProcessCh = make(chan struct{}, 1)
ctx = r.stopCtx()
)
defer trySyncTicker.Stop()
@@ -488,7 +501,7 @@ FOR_LOOP:
r.blockSync.UnSet()
if r.consReactor != nil {
r.consReactor.SwitchToConsensus(state, blocksSynced > 0 || stateSynced)
r.consReactor.SwitchToConsensus(ctx, state, blocksSynced > 0 || stateSynced)
}
break FOR_LOOP
+34 -13
View File
@@ -1,6 +1,7 @@
package blocksync
import (
"context"
"os"
"testing"
"time"
@@ -41,6 +42,7 @@ type reactorTestSuite struct {
}
func setup(
ctx context.Context,
t *testing.T,
genDoc *types.GenesisDoc,
privVal types.PrivValidator,
@@ -49,13 +51,16 @@ func setup(
) *reactorTestSuite {
t.Helper()
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
numNodes := len(maxBlockHeights)
require.True(t, numNodes >= 1,
"must specify at least one block height (nodes)")
rts := &reactorTestSuite{
logger: log.TestingLogger().With("module", "block_sync", "testCase", t.Name()),
network: p2ptest.MakeNetwork(t, p2ptest.NetworkOptions{NumNodes: numNodes}),
network: p2ptest.MakeNetwork(ctx, t, p2ptest.NetworkOptions{NumNodes: numNodes}),
nodes: make([]types.NodeID, 0, numNodes),
reactors: make(map[types.NodeID]*Reactor, numNodes),
app: make(map[types.NodeID]proxy.AppConns, numNodes),
@@ -70,17 +75,19 @@ func setup(
i := 0
for nodeID := range rts.network.Nodes {
rts.addNode(t, nodeID, genDoc, privVal, maxBlockHeights[i])
rts.addNode(ctx, t, nodeID, genDoc, privVal, maxBlockHeights[i])
i++
}
t.Cleanup(func() {
cancel()
for _, nodeID := range rts.nodes {
rts.peerUpdates[nodeID].Close()
if rts.reactors[nodeID].IsRunning() {
require.NoError(t, rts.reactors[nodeID].Stop())
require.NoError(t, rts.app[nodeID].Stop())
rts.reactors[nodeID].Wait()
rts.app[nodeID].Wait()
require.False(t, rts.reactors[nodeID].IsRunning())
}
}
@@ -89,7 +96,9 @@ func setup(
return rts
}
func (rts *reactorTestSuite) addNode(t *testing.T,
func (rts *reactorTestSuite) addNode(
ctx context.Context,
t *testing.T,
nodeID types.NodeID,
genDoc *types.GenesisDoc,
privVal types.PrivValidator,
@@ -101,7 +110,7 @@ func (rts *reactorTestSuite) addNode(t *testing.T,
rts.nodes = append(rts.nodes, nodeID)
rts.app[nodeID] = proxy.NewAppConns(abciclient.NewLocalCreator(&abci.BaseApplication{}), logger, proxy.NopMetrics())
require.NoError(t, rts.app[nodeID].Start())
require.NoError(t, rts.app[nodeID].Start(ctx))
blockDB := dbm.NewMemDB()
stateDB := dbm.NewMemDB()
@@ -170,7 +179,7 @@ func (rts *reactorTestSuite) addNode(t *testing.T,
consensus.NopMetrics())
require.NoError(t, err)
require.NoError(t, rts.reactors[nodeID].Start())
require.NoError(t, rts.reactors[nodeID].Start(ctx))
require.True(t, rts.reactors[nodeID].IsRunning())
}
@@ -184,6 +193,9 @@ func (rts *reactorTestSuite) start(t *testing.T) {
}
func TestReactor_AbruptDisconnect(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg, err := config.ResetTestRoot("block_sync_reactor_test")
require.NoError(t, err)
defer os.RemoveAll(cfg.RootDir)
@@ -191,7 +203,7 @@ func TestReactor_AbruptDisconnect(t *testing.T) {
genDoc, privVals := factory.RandGenesisDoc(cfg, 1, false, 30)
maxBlockHeight := int64(64)
rts := setup(t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0)
rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0)
require.Equal(t, maxBlockHeight, rts.reactors[rts.nodes[0]].store.Height())
@@ -220,6 +232,9 @@ func TestReactor_AbruptDisconnect(t *testing.T) {
}
func TestReactor_SyncTime(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg, err := config.ResetTestRoot("block_sync_reactor_test")
require.NoError(t, err)
defer os.RemoveAll(cfg.RootDir)
@@ -227,7 +242,7 @@ func TestReactor_SyncTime(t *testing.T) {
genDoc, privVals := factory.RandGenesisDoc(cfg, 1, false, 30)
maxBlockHeight := int64(101)
rts := setup(t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0)
rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0)
require.Equal(t, maxBlockHeight, rts.reactors[rts.nodes[0]].store.Height())
rts.start(t)
@@ -244,6 +259,9 @@ func TestReactor_SyncTime(t *testing.T) {
}
func TestReactor_NoBlockResponse(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg, err := config.ResetTestRoot("block_sync_reactor_test")
require.NoError(t, err)
@@ -252,7 +270,7 @@ func TestReactor_NoBlockResponse(t *testing.T) {
genDoc, privVals := factory.RandGenesisDoc(cfg, 1, false, 30)
maxBlockHeight := int64(65)
rts := setup(t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0)
rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0)
require.Equal(t, maxBlockHeight, rts.reactors[rts.nodes[0]].store.Height())
@@ -293,6 +311,9 @@ func TestReactor_BadBlockStopsPeer(t *testing.T) {
// See: https://github.com/tendermint/tendermint/issues/6005
t.SkipNow()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg, err := config.ResetTestRoot("block_sync_reactor_test")
require.NoError(t, err)
defer os.RemoveAll(cfg.RootDir)
@@ -300,7 +321,7 @@ func TestReactor_BadBlockStopsPeer(t *testing.T) {
maxBlockHeight := int64(48)
genDoc, privVals := factory.RandGenesisDoc(cfg, 1, false, 30)
rts := setup(t, genDoc, privVals[0], []int64{maxBlockHeight, 0, 0, 0, 0}, 1000)
rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0, 0, 0, 0}, 1000)
require.Equal(t, maxBlockHeight, rts.reactors[rts.nodes[0]].store.Height())
@@ -333,11 +354,11 @@ func TestReactor_BadBlockStopsPeer(t *testing.T) {
// XXX: This causes a potential race condition.
// See: https://github.com/tendermint/tendermint/issues/6005
otherGenDoc, otherPrivVals := factory.RandGenesisDoc(cfg, 1, false, 30)
newNode := rts.network.MakeNode(t, p2ptest.NodeOptions{
newNode := rts.network.MakeNode(ctx, t, p2ptest.NodeOptions{
MaxPeers: uint16(len(rts.nodes) + 1),
MaxConnected: uint16(len(rts.nodes) + 1),
})
rts.addNode(t, newNode.NodeID, otherGenDoc, otherPrivVals[0], maxBlockHeight)
rts.addNode(ctx, t, newNode.NodeID, otherGenDoc, otherPrivVals[0], maxBlockHeight)
// add a fake peer just so we do not wait for the consensus ticker to timeout
rts.reactors[newNode.NodeID].pool.SetPeerRange("00ff", 10, 10)
+13 -8
View File
@@ -31,6 +31,9 @@ import (
// Byzantine node sends two different prevotes (nil and blockID) to the same
// validator.
func TestByzantinePrevoteEquivocation(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
config := configSetup(t)
nValidators := 4
@@ -93,7 +96,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
cs.SetPrivValidator(pv)
eventBus := eventbus.NewDefault(log.TestingLogger().With("module", "events"))
err = eventBus.Start()
err = eventBus.Start(ctx)
require.NoError(t, err)
cs.SetEventBus(eventBus)
@@ -103,7 +106,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
}()
}
rts := setup(t, nValidators, states, 100) // buffer must be large enough to not deadlock
rts := setup(ctx, t, nValidators, states, 100) // buffer must be large enough to not deadlock
var bzNodeID types.NodeID
@@ -211,7 +214,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
propBlockID := types.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()}
proposal := types.NewProposal(height, round, lazyNodeState.ValidRound, propBlockID)
p := proposal.ToProto()
if err := lazyNodeState.privValidator.SignProposal(context.Background(), lazyNodeState.state.ChainID, p); err == nil {
if err := lazyNodeState.privValidator.SignProposal(ctx, lazyNodeState.state.ChainID, p); err == nil {
proposal.Signature = p.Signature
// send proposal and block parts on internal msg queue
@@ -229,15 +232,13 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
for _, reactor := range rts.reactors {
state := reactor.state.GetState()
reactor.SwitchToConsensus(state, false)
reactor.SwitchToConsensus(ctx, state, false)
}
// Evidence should be submitted and committed at the third height but
// we will check the first six just in case
evidenceFromEachValidator := make([]types.Evidence, nValidators)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
i := 0
for _, sub := range rts.subs {
@@ -246,6 +247,10 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
go func(j int, s eventbus.Subscription) {
defer wg.Done()
for {
if ctx.Err() != nil {
return
}
msg, err := s.Next(ctx)
if !assert.NoError(t, err) {
cancel()
@@ -265,7 +270,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
wg.Wait()
pubkey, err := bzNodeState.privValidator.GetPubKey(context.Background())
pubkey, err := bzNodeState.privValidator.GetPubKey(ctx)
require.NoError(t, err)
for idx, ev := range evidenceFromEachValidator {
@@ -311,7 +316,7 @@ func TestByzantineConflictingProposalsWithPartition(t *testing.T) {
// eventBus.SetLogger(logger.With("module", "events", "validator", i))
// var err error
// blocksSubs[i], err = eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock)
// blocksSubs[i], err = eventBus.Subscribe(ctx, testSubscriber, types.EventQueryNewBlock)
// require.NoError(t, err)
// conR := NewReactor(states[i], true) // so we don't start the consensus states
+62 -33
View File
@@ -106,12 +106,14 @@ func newValidatorStub(privValidator types.PrivValidator, valIndex int32) *valida
}
func (vs *validatorStub) signVote(
ctx context.Context,
cfg *config.Config,
voteType tmproto.SignedMsgType,
hash []byte,
header types.PartSetHeader) (*types.Vote, error) {
header types.PartSetHeader,
) (*types.Vote, error) {
pubKey, err := vs.PrivValidator.GetPubKey(context.Background())
pubKey, err := vs.PrivValidator.GetPubKey(ctx)
if err != nil {
return nil, fmt.Errorf("can't get pubkey: %w", err)
}
@@ -126,7 +128,7 @@ func (vs *validatorStub) signVote(
BlockID: types.BlockID{Hash: hash, PartSetHeader: header},
}
v := vote.ToProto()
if err := vs.PrivValidator.SignVote(context.Background(), cfg.ChainID(), v); err != nil {
if err := vs.PrivValidator.SignVote(ctx, cfg.ChainID(), v); err != nil {
return nil, fmt.Errorf("sign vote failed: %w", err)
}
@@ -144,13 +146,15 @@ func (vs *validatorStub) signVote(
// Sign vote for type/hash/header
func signVote(
ctx context.Context,
vs *validatorStub,
cfg *config.Config,
voteType tmproto.SignedMsgType,
hash []byte,
header types.PartSetHeader) *types.Vote {
header types.PartSetHeader,
) *types.Vote {
v, err := vs.signVote(cfg, voteType, hash, header)
v, err := vs.signVote(ctx, cfg, voteType, hash, header)
if err != nil {
panic(fmt.Errorf("failed to sign vote: %v", err))
}
@@ -161,6 +165,7 @@ func signVote(
}
func signVotes(
ctx context.Context,
cfg *config.Config,
voteType tmproto.SignedMsgType,
hash []byte,
@@ -168,7 +173,7 @@ func signVotes(
vss ...*validatorStub) []*types.Vote {
votes := make([]*types.Vote, len(vss))
for i, vs := range vss {
votes[i] = signVote(vs, cfg, voteType, hash, header)
votes[i] = signVote(ctx, vs, cfg, voteType, hash, header)
}
return votes
}
@@ -192,11 +197,11 @@ func (vss ValidatorStubsByPower) Len() int {
}
func (vss ValidatorStubsByPower) Less(i, j int) bool {
vssi, err := vss[i].GetPubKey(context.Background())
vssi, err := vss[i].GetPubKey(context.TODO())
if err != nil {
panic(err)
}
vssj, err := vss[j].GetPubKey(context.Background())
vssj, err := vss[j].GetPubKey(context.TODO())
if err != nil {
panic(err)
}
@@ -218,13 +223,14 @@ func (vss ValidatorStubsByPower) Swap(i, j int) {
//-------------------------------------------------------------------------------
// Functions for transitioning the consensus state
func startTestRound(cs *State, height int64, round int32) {
func startTestRound(ctx context.Context, cs *State, height int64, round int32) {
cs.enterNewRound(height, round)
cs.startRoutines(0)
cs.startRoutines(ctx, 0)
}
// Create proposal block from cs1 but sign it with vs.
func decideProposal(
ctx context.Context,
cs1 *State,
vs *validatorStub,
height int64,
@@ -243,7 +249,7 @@ func decideProposal(
polRound, propBlockID := validRound, types.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()}
proposal = types.NewProposal(height, round, polRound, propBlockID)
p := proposal.ToProto()
if err := vs.SignProposal(context.Background(), chainID, p); err != nil {
if err := vs.SignProposal(ctx, chainID, p); err != nil {
panic(err)
}
@@ -259,6 +265,7 @@ func addVotes(to *State, votes ...*types.Vote) {
}
func signAddVotes(
ctx context.Context,
cfg *config.Config,
to *State,
voteType tmproto.SignedMsgType,
@@ -266,13 +273,19 @@ func signAddVotes(
header types.PartSetHeader,
vss ...*validatorStub,
) {
votes := signVotes(cfg, voteType, hash, header, vss...)
addVotes(to, votes...)
addVotes(to, signVotes(ctx, cfg, voteType, hash, header, vss...)...)
}
func validatePrevote(t *testing.T, cs *State, round int32, privVal *validatorStub, blockHash []byte) {
func validatePrevote(
ctx context.Context,
t *testing.T,
cs *State,
round int32,
privVal *validatorStub,
blockHash []byte,
) {
prevotes := cs.Votes.Prevotes(round)
pubKey, err := privVal.GetPubKey(context.Background())
pubKey, err := privVal.GetPubKey(ctx)
require.NoError(t, err)
address := pubKey.Address()
var vote *types.Vote
@@ -290,9 +303,9 @@ func validatePrevote(t *testing.T, cs *State, round int32, privVal *validatorStu
}
}
func validateLastPrecommit(t *testing.T, cs *State, privVal *validatorStub, blockHash []byte) {
func validateLastPrecommit(ctx context.Context, t *testing.T, cs *State, privVal *validatorStub, blockHash []byte) {
votes := cs.LastCommit
pv, err := privVal.GetPubKey(context.Background())
pv, err := privVal.GetPubKey(ctx)
require.NoError(t, err)
address := pv.Address()
var vote *types.Vote
@@ -305,6 +318,7 @@ func validateLastPrecommit(t *testing.T, cs *State, privVal *validatorStub, bloc
}
func validatePrecommit(
ctx context.Context,
t *testing.T,
cs *State,
thisRound,
@@ -314,7 +328,7 @@ func validatePrecommit(
lockedBlockHash []byte,
) {
precommits := cs.Votes.Precommits(thisRound)
pv, err := privVal.GetPubKey(context.Background())
pv, err := privVal.GetPubKey(ctx)
require.NoError(t, err)
address := pv.Address()
var vote *types.Vote
@@ -353,6 +367,7 @@ func validatePrecommit(
}
func validatePrevoteAndPrecommit(
ctx context.Context,
t *testing.T,
cs *State,
thisRound,
@@ -362,18 +377,18 @@ func validatePrevoteAndPrecommit(
lockedBlockHash []byte,
) {
// verify the prevote
validatePrevote(t, cs, thisRound, privVal, votedBlockHash)
validatePrevote(ctx, t, cs, thisRound, privVal, votedBlockHash)
// verify precommit
cs.mtx.Lock()
validatePrecommit(t, cs, thisRound, lockRound, privVal, votedBlockHash, lockedBlockHash)
cs.mtx.Unlock()
defer cs.mtx.Unlock()
validatePrecommit(ctx, t, cs, thisRound, lockRound, privVal, votedBlockHash, lockedBlockHash)
}
func subscribeToVoter(t *testing.T, cs *State, addr []byte) <-chan tmpubsub.Message {
func subscribeToVoter(ctx context.Context, t *testing.T, cs *State, addr []byte) <-chan tmpubsub.Message {
t.Helper()
ch := make(chan tmpubsub.Message, 1)
if err := cs.eventBus.Observe(context.Background(), func(msg tmpubsub.Message) error {
if err := cs.eventBus.Observe(ctx, func(msg tmpubsub.Message) error {
vote := msg.Data().(types.EventDataVote)
// we only fire for our own votes
if bytes.Equal(addr, vote.Vote.ValidatorAddress) {
@@ -389,27 +404,34 @@ func subscribeToVoter(t *testing.T, cs *State, addr []byte) <-chan tmpubsub.Mess
//-------------------------------------------------------------------------------
// consensus states
func newState(logger log.Logger, state sm.State, pv types.PrivValidator, app abci.Application) (*State, error) {
func newState(
ctx context.Context,
logger log.Logger,
state sm.State,
pv types.PrivValidator,
app abci.Application,
) (*State, error) {
cfg, err := config.ResetTestRoot("consensus_state_test")
if err != nil {
return nil, err
}
return newStateWithConfig(logger, cfg, state, pv, app), nil
return newStateWithConfig(ctx, logger, cfg, state, pv, app), nil
}
func newStateWithConfig(
ctx context.Context,
logger log.Logger,
thisConfig *config.Config,
state sm.State,
pv types.PrivValidator,
app abci.Application,
) *State {
blockStore := store.NewBlockStore(dbm.NewMemDB())
return newStateWithConfigAndBlockStore(logger, thisConfig, state, pv, app, blockStore)
return newStateWithConfigAndBlockStore(ctx, logger, thisConfig, state, pv, app, store.NewBlockStore(dbm.NewMemDB()))
}
func newStateWithConfigAndBlockStore(
ctx context.Context,
logger log.Logger,
thisConfig *config.Config,
state sm.State,
@@ -449,7 +471,7 @@ func newStateWithConfigAndBlockStore(
cs.SetPrivValidator(pv)
eventBus := eventbus.NewDefault(logger.With("module", "events"))
err := eventBus.Start()
err := eventBus.Start(ctx)
if err != nil {
panic(err)
}
@@ -469,13 +491,18 @@ func loadPrivValidator(cfg *config.Config) *privval.FilePV {
return privValidator
}
func randState(cfg *config.Config, logger log.Logger, nValidators int) (*State, []*validatorStub, error) {
func randState(
ctx context.Context,
cfg *config.Config,
logger log.Logger,
nValidators int,
) (*State, []*validatorStub, error) {
// Get State
state, privVals := randGenesisState(cfg, nValidators, false, 10)
vss := make([]*validatorStub, nValidators)
cs, err := newState(logger, state, privVals[0], kvstore.NewApplication())
cs, err := newState(ctx, logger, state, privVals[0], kvstore.NewApplication())
if err != nil {
return nil, nil, err
}
@@ -719,6 +746,7 @@ func consensusLogger() log.Logger {
}
func randConsensusState(
ctx context.Context,
t *testing.T,
cfg *config.Config,
nValidators int,
@@ -761,7 +789,7 @@ func randConsensusState(
app.InitChain(abci.RequestInitChain{Validators: vals})
l := logger.With("validator", i, "module", "consensus")
css[i] = newStateWithConfigAndBlockStore(l, thisConfig, state, privVals[i], app, blockStore)
css[i] = newStateWithConfigAndBlockStore(ctx, l, thisConfig, state, privVals[i], app, blockStore)
css[i].SetTimeoutTicker(tickerFunc())
}
@@ -777,6 +805,7 @@ func randConsensusState(
// nPeers = nValidators + nNotValidator
func randConsensusNetWithPeers(
ctx context.Context,
cfg *config.Config,
nValidators,
nPeers int,
@@ -830,7 +859,7 @@ func randConsensusNetWithPeers(
app.InitChain(abci.RequestInitChain{Validators: vals})
// sm.SaveState(stateDB,state) //height 1's validatorsInfo already saved in LoadStateFromDBOrGenesisDoc above
css[i] = newStateWithConfig(logger.With("validator", i, "module", "consensus"), thisConfig, state, privVal, app)
css[i] = newStateWithConfig(ctx, logger.With("validator", i, "module", "consensus"), thisConfig, state, privVal, app)
css[i].SetTimeoutTicker(tickerFunc())
}
return css, genDoc, peer0Config, func() {
@@ -870,7 +899,7 @@ type mockTicker struct {
fired bool
}
func (m *mockTicker) Start() error {
func (m *mockTicker) Start(context.Context) error {
return nil
}
+19 -9
View File
@@ -17,10 +17,13 @@ import (
)
func TestReactorInvalidPrecommit(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
config := configSetup(t)
n := 4
states, cleanup := randConsensusState(t,
states, cleanup := randConsensusState(ctx, t,
config, n, "consensus_reactor_test",
newMockTickerFunc(true), newKVStore)
t.Cleanup(cleanup)
@@ -30,11 +33,11 @@ func TestReactorInvalidPrecommit(t *testing.T) {
states[i].SetTimeoutTicker(ticker)
}
rts := setup(t, n, states, 100) // buffer must be large enough to not deadlock
rts := setup(ctx, t, n, states, 100) // buffer must be large enough to not deadlock
for _, reactor := range rts.reactors {
state := reactor.state.GetState()
reactor.SwitchToConsensus(state, false)
reactor.SwitchToConsensus(ctx, state, false)
}
// this val sends a random precommit at each height
@@ -48,7 +51,7 @@ func TestReactorInvalidPrecommit(t *testing.T) {
byzState.mtx.Lock()
privVal := byzState.privValidator
byzState.doPrevote = func(height int64, round int32) {
invalidDoPrevoteFunc(t, height, round, byzState, byzReactor, privVal)
invalidDoPrevoteFunc(ctx, t, height, round, byzState, byzReactor, privVal)
}
byzState.mtx.Unlock()
@@ -56,8 +59,7 @@ func TestReactorInvalidPrecommit(t *testing.T) {
//
// TODO: Make this tighter by ensuring the halt happens by block 2.
var wg sync.WaitGroup
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for i := 0; i < 10; i++ {
for _, sub := range rts.subs {
wg.Add(1)
@@ -75,7 +77,15 @@ func TestReactorInvalidPrecommit(t *testing.T) {
wg.Wait()
}
func invalidDoPrevoteFunc(t *testing.T, height int64, round int32, cs *State, r *Reactor, pv types.PrivValidator) {
func invalidDoPrevoteFunc(
ctx context.Context,
t *testing.T,
height int64,
round int32,
cs *State,
r *Reactor,
pv types.PrivValidator,
) {
// routine to:
// - precommit for a random block
// - send precommit to all peers
@@ -84,7 +94,7 @@ func invalidDoPrevoteFunc(t *testing.T, height int64, round int32, cs *State, r
cs.mtx.Lock()
cs.privValidator = pv
pubKey, err := cs.privValidator.GetPubKey(context.Background())
pubKey, err := cs.privValidator.GetPubKey(ctx)
require.NoError(t, err)
addr := pubKey.Address()
@@ -105,7 +115,7 @@ func invalidDoPrevoteFunc(t *testing.T, height int64, round int32, cs *State, r
}
p := precommit.ToProto()
err = cs.privValidator.SignVote(context.Background(), cs.state.ChainID, p)
err = cs.privValidator.SignVote(ctx, cs.state.ChainID, p)
require.NoError(t, err)
precommit.Signature = p.Signature
+33 -20
View File
@@ -27,6 +27,9 @@ func assertMempool(txn txNotifier) mempool.Mempool {
}
func TestMempoolNoProgressUntilTxsAvailable(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
baseConfig := configSetup(t)
config, err := ResetConfig("consensus_mempool_txs_available_test")
@@ -35,15 +38,15 @@ func TestMempoolNoProgressUntilTxsAvailable(t *testing.T) {
config.Consensus.CreateEmptyBlocks = false
state, privVals := randGenesisState(baseConfig, 1, false, 10)
cs := newStateWithConfig(log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
cs := newStateWithConfig(ctx, log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
assertMempool(cs.txNotifier).EnableTxsAvailable()
height, round := cs.Height, cs.Round
newBlockCh := subscribe(t, cs.eventBus, types.EventQueryNewBlock)
startTestRound(cs, height, round)
newBlockCh := subscribe(ctx, t, cs.eventBus, types.EventQueryNewBlock)
startTestRound(ctx, cs, height, round)
ensureNewEventOnChannel(newBlockCh) // first block gets committed
ensureNoNewEventOnChannel(newBlockCh)
deliverTxsRange(cs, 0, 1)
deliverTxsRange(ctx, cs, 0, 1)
ensureNewEventOnChannel(newBlockCh) // commit txs
ensureNewEventOnChannel(newBlockCh) // commit updated app hash
ensureNoNewEventOnChannel(newBlockCh)
@@ -51,6 +54,8 @@ func TestMempoolNoProgressUntilTxsAvailable(t *testing.T) {
func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
baseConfig := configSetup(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
config, err := ResetConfig("consensus_mempool_txs_available_test")
require.NoError(t, err)
@@ -58,12 +63,12 @@ func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
config.Consensus.CreateEmptyBlocksInterval = ensureTimeout
state, privVals := randGenesisState(baseConfig, 1, false, 10)
cs := newStateWithConfig(log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
cs := newStateWithConfig(ctx, log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
assertMempool(cs.txNotifier).EnableTxsAvailable()
newBlockCh := subscribe(t, cs.eventBus, types.EventQueryNewBlock)
startTestRound(cs, cs.Height, cs.Round)
newBlockCh := subscribe(ctx, t, cs.eventBus, types.EventQueryNewBlock)
startTestRound(ctx, cs, cs.Height, cs.Round)
ensureNewEventOnChannel(newBlockCh) // first block gets committed
ensureNoNewEventOnChannel(newBlockCh) // then we dont make a block ...
@@ -72,6 +77,8 @@ func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
func TestMempoolProgressInHigherRound(t *testing.T) {
baseConfig := configSetup(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
config, err := ResetConfig("consensus_mempool_txs_available_test")
require.NoError(t, err)
@@ -79,12 +86,12 @@ func TestMempoolProgressInHigherRound(t *testing.T) {
config.Consensus.CreateEmptyBlocks = false
state, privVals := randGenesisState(baseConfig, 1, false, 10)
cs := newStateWithConfig(log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
cs := newStateWithConfig(ctx, log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
assertMempool(cs.txNotifier).EnableTxsAvailable()
height, round := cs.Height, cs.Round
newBlockCh := subscribe(t, cs.eventBus, types.EventQueryNewBlock)
newRoundCh := subscribe(t, cs.eventBus, types.EventQueryNewRound)
timeoutCh := subscribe(t, cs.eventBus, types.EventQueryTimeoutPropose)
newBlockCh := subscribe(ctx, t, cs.eventBus, types.EventQueryNewBlock)
newRoundCh := subscribe(ctx, t, cs.eventBus, types.EventQueryNewRound)
timeoutCh := subscribe(ctx, t, cs.eventBus, types.EventQueryTimeoutPropose)
cs.setProposal = func(proposal *types.Proposal) error {
if cs.Height == 2 && cs.Round == 0 {
// dont set the proposal in round 0 so we timeout and
@@ -94,7 +101,7 @@ func TestMempoolProgressInHigherRound(t *testing.T) {
}
return cs.defaultSetProposal(proposal)
}
startTestRound(cs, height, round)
startTestRound(ctx, cs, height, round)
ensureNewRound(newRoundCh, height, round) // first round at first height
ensureNewEventOnChannel(newBlockCh) // first block gets committed
@@ -103,7 +110,7 @@ func TestMempoolProgressInHigherRound(t *testing.T) {
round = 0
ensureNewRound(newRoundCh, height, round) // first round at next height
deliverTxsRange(cs, 0, 1) // we deliver txs, but dont set a proposal so we get the next round
deliverTxsRange(ctx, cs, 0, 1) // we deliver txs, but dont set a proposal so we get the next round
ensureNewTimeout(timeoutCh, height, round, cs.config.TimeoutPropose.Nanoseconds())
round++ // moving to the next round
@@ -111,12 +118,12 @@ func TestMempoolProgressInHigherRound(t *testing.T) {
ensureNewEventOnChannel(newBlockCh) // now we can commit the block
}
func deliverTxsRange(cs *State, start, end int) {
func deliverTxsRange(ctx context.Context, cs *State, start, end int) {
// Deliver some txs.
for i := start; i < end; i++ {
txBytes := make([]byte, 8)
binary.BigEndian.PutUint64(txBytes, uint64(i))
err := assertMempool(cs.txNotifier).CheckTx(context.Background(), txBytes, nil, mempool.TxInfo{})
err := assertMempool(cs.txNotifier).CheckTx(ctx, txBytes, nil, mempool.TxInfo{})
if err != nil {
panic(fmt.Sprintf("Error after CheckTx: %v", err))
}
@@ -124,6 +131,9 @@ func deliverTxsRange(cs *State, start, end int) {
}
func TestMempoolTxConcurrentWithCommit(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
config := configSetup(t)
logger := log.TestingLogger()
state, privVals := randGenesisState(config, 1, false, 10)
@@ -131,16 +141,17 @@ func TestMempoolTxConcurrentWithCommit(t *testing.T) {
blockStore := store.NewBlockStore(dbm.NewMemDB())
cs := newStateWithConfigAndBlockStore(
ctx,
logger, config, state, privVals[0], NewCounterApplication(), blockStore)
err := stateStore.Save(state)
require.NoError(t, err)
newBlockHeaderCh := subscribe(t, cs.eventBus, types.EventQueryNewBlockHeader)
newBlockHeaderCh := subscribe(ctx, t, cs.eventBus, types.EventQueryNewBlockHeader)
const numTxs int64 = 3000
go deliverTxsRange(cs, 0, int(numTxs))
go deliverTxsRange(ctx, cs, 0, int(numTxs))
startTestRound(cs, cs.Height, cs.Round)
startTestRound(ctx, cs, cs.Height, cs.Round)
for n := int64(0); n < numTxs; {
select {
case msg := <-newBlockHeaderCh:
@@ -154,12 +165,14 @@ func TestMempoolTxConcurrentWithCommit(t *testing.T) {
func TestMempoolRmBadTx(t *testing.T) {
config := configSetup(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
state, privVals := randGenesisState(config, 1, false, 10)
app := NewCounterApplication()
stateStore := sm.NewStore(dbm.NewMemDB())
blockStore := store.NewBlockStore(dbm.NewMemDB())
cs := newStateWithConfigAndBlockStore(log.TestingLogger(), config, state, privVals[0], app, blockStore)
cs := newStateWithConfigAndBlockStore(ctx, log.TestingLogger(), config, state, privVals[0], app, blockStore)
err := stateStore.Save(state)
require.NoError(t, err)
@@ -179,7 +192,7 @@ func TestMempoolRmBadTx(t *testing.T) {
// Try to send the tx through the mempool.
// CheckTx should not err, but the app should return a bad abci code
// and the tx should get removed from the pool
err := assertMempool(cs.txNotifier).CheckTx(context.Background(), txBytes, func(r *abci.Response) {
err := assertMempool(cs.txNotifier).CheckTx(ctx, txBytes, func(r *abci.Response) {
if r.GetCheckTx().Code != code.CodeTypeBadNonce {
t.Errorf("expected checktx to return bad nonce, got %v", r)
return
+6 -5
View File
@@ -1,6 +1,7 @@
package consensus
import (
"context"
"fmt"
"runtime/debug"
"time"
@@ -85,7 +86,7 @@ type ReactorOption func(*Reactor)
// NOTE: Temporary interface for switching to block sync, we should get rid of v0.
// See: https://github.com/tendermint/tendermint/issues/4595
type BlockSyncReactor interface {
SwitchToBlockSync(sm.State) error
SwitchToBlockSync(context.Context, sm.State) error
GetMaxPeerBlockHeight() int64
@@ -174,7 +175,7 @@ func NewReactor(
// envelopes on each. In addition, it also listens for peer updates and handles
// messages on that p2p channel accordingly. The caller must be sure to execute
// OnStop to ensure the outbound p2p Channels are closed.
func (r *Reactor) OnStart() error {
func (r *Reactor) OnStart(ctx context.Context) error {
r.Logger.Debug("consensus wait sync", "wait_sync", r.WaitSync())
// start routine that computes peer statistics for evaluating peer quality
@@ -186,7 +187,7 @@ func (r *Reactor) OnStart() error {
r.subscribeToBroadcastEvents()
if !r.WaitSync() {
if err := r.state.Start(); err != nil {
if err := r.state.Start(ctx); err != nil {
return err
}
}
@@ -264,7 +265,7 @@ func ReactorMetrics(metrics *Metrics) ReactorOption {
// SwitchToConsensus switches from block-sync mode to consensus mode. It resets
// the state, turns off block-sync, and starts the consensus state-machine.
func (r *Reactor) SwitchToConsensus(state sm.State, skipWAL bool) {
func (r *Reactor) SwitchToConsensus(ctx context.Context, state sm.State, skipWAL bool) {
r.Logger.Info("switching to consensus")
// we have no votes, so reconstruct LastCommit from SeenCommit
@@ -287,7 +288,7 @@ func (r *Reactor) SwitchToConsensus(state sm.State, skipWAL bool) {
r.state.doWALCatchup = false
}
if err := r.state.Start(); err != nil {
if err := r.state.Start(ctx); err != nil {
panic(fmt.Sprintf(`failed to start consensus state: %v
conS:
+94 -79
View File
@@ -59,11 +59,17 @@ func chDesc(chID p2p.ChannelID, size int) *p2p.ChannelDescriptor {
}
}
func setup(t *testing.T, numNodes int, states []*State, size int) *reactorTestSuite {
func setup(
ctx context.Context,
t *testing.T,
numNodes int,
states []*State,
size int,
) *reactorTestSuite {
t.Helper()
rts := &reactorTestSuite{
network: p2ptest.MakeNetwork(t, p2ptest.NetworkOptions{NumNodes: numNodes}),
network: p2ptest.MakeNetwork(ctx, t, p2ptest.NetworkOptions{NumNodes: numNodes}),
states: make(map[types.NodeID]*State),
reactors: make(map[types.NodeID]*Reactor, numNodes),
subs: make(map[types.NodeID]eventbus.Subscription, numNodes),
@@ -75,7 +81,7 @@ func setup(t *testing.T, numNodes int, states []*State, size int) *reactorTestSu
rts.voteChannels = rts.network.MakeChannelsNoCleanup(t, chDesc(VoteChannel, size))
rts.voteSetBitsChannels = rts.network.MakeChannelsNoCleanup(t, chDesc(VoteSetBitsChannel, size))
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(ctx)
// Canceled during cleanup (see below).
i := 0
@@ -89,7 +95,7 @@ func setup(t *testing.T, numNodes int, states []*State, size int) *reactorTestSu
rts.dataChannels[nodeID],
rts.voteChannels[nodeID],
rts.voteSetBitsChannels[nodeID],
node.MakePeerUpdates(t),
node.MakePeerUpdates(ctx, t),
true,
)
@@ -119,7 +125,7 @@ func setup(t *testing.T, numNodes int, states []*State, size int) *reactorTestSu
require.NoError(t, state.blockExec.Store().Save(state.state))
}
require.NoError(t, reactor.Start())
require.NoError(t, reactor.Start(ctx))
require.True(t, reactor.IsRunning())
i++
@@ -131,14 +137,8 @@ func setup(t *testing.T, numNodes int, states []*State, size int) *reactorTestSu
rts.network.Start(t)
t.Cleanup(func() {
for nodeID, r := range rts.reactors {
require.NoError(t, rts.states[nodeID].eventBus.Stop())
require.NoError(t, r.Stop())
require.False(t, r.IsRunning())
}
leaktest.Check(t)
cancel()
leaktest.Check(t)
})
return rts
@@ -162,6 +162,7 @@ func validateBlock(block *types.Block, activeVals map[string]struct{}) error {
}
func waitForAndValidateBlock(
bctx context.Context,
t *testing.T,
n int,
activeVals map[string]struct{},
@@ -169,8 +170,9 @@ func waitForAndValidateBlock(
states []*State,
txs ...[]byte,
) {
t.Helper()
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(bctx)
defer cancel()
fn := func(j int) {
msg, err := blocksSubs[j].Next(ctx)
@@ -183,7 +185,7 @@ func waitForAndValidateBlock(
require.NoError(t, validateBlock(newBlock, activeVals))
for _, tx := range txs {
require.NoError(t, assertMempool(states[j].txNotifier).CheckTx(context.Background(), tx, nil, mempool.TxInfo{}))
require.NoError(t, assertMempool(states[j].txNotifier).CheckTx(ctx, tx, nil, mempool.TxInfo{}))
}
}
@@ -200,6 +202,7 @@ func waitForAndValidateBlock(
}
func waitForAndValidateBlockWithTx(
bctx context.Context,
t *testing.T,
n int,
activeVals map[string]struct{},
@@ -207,8 +210,9 @@ func waitForAndValidateBlockWithTx(
states []*State,
txs ...[]byte,
) {
t.Helper()
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(bctx)
defer cancel()
fn := func(j int) {
ntxs := 0
@@ -249,15 +253,17 @@ func waitForAndValidateBlockWithTx(
}
func waitForBlockWithUpdatedValsAndValidateIt(
bctx context.Context,
t *testing.T,
n int,
updatedVals map[string]struct{},
blocksSubs []eventbus.Subscription,
css []*State,
) {
ctx, cancel := context.WithCancel(context.Background())
t.Helper()
ctx, cancel := context.WithCancel(bctx)
defer cancel()
fn := func(j int) {
var newBlock *types.Block
@@ -299,23 +305,24 @@ func ensureBlockSyncStatus(t *testing.T, msg tmpubsub.Message, complete bool, he
}
func TestReactorBasic(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg := configSetup(t)
n := 4
states, cleanup := randConsensusState(t,
states, cleanup := randConsensusState(ctx, t,
cfg, n, "consensus_reactor_test",
newMockTickerFunc(true), newKVStore)
t.Cleanup(cleanup)
rts := setup(t, n, states, 100) // buffer must be large enough to not deadlock
rts := setup(ctx, t, n, states, 100) // buffer must be large enough to not deadlock
for _, reactor := range rts.reactors {
state := reactor.state.GetState()
reactor.SwitchToConsensus(state, false)
reactor.SwitchToConsensus(ctx, state, false)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
for _, sub := range rts.subs {
wg.Add(1)
@@ -351,6 +358,9 @@ func TestReactorBasic(t *testing.T) {
}
func TestReactorWithEvidence(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg := configSetup(t)
n := 4
@@ -416,7 +426,7 @@ func TestReactorWithEvidence(t *testing.T) {
cs.SetPrivValidator(pv)
eventBus := eventbus.NewDefault(log.TestingLogger().With("module", "events"))
require.NoError(t, eventBus.Start())
require.NoError(t, eventBus.Start(ctx))
cs.SetEventBus(eventBus)
cs.SetTimeoutTicker(tickerFunc())
@@ -424,15 +434,13 @@ func TestReactorWithEvidence(t *testing.T) {
states[i] = cs
}
rts := setup(t, n, states, 100) // buffer must be large enough to not deadlock
rts := setup(ctx, t, n, states, 100) // buffer must be large enough to not deadlock
for _, reactor := range rts.reactors {
state := reactor.state.GetState()
reactor.SwitchToConsensus(state, false)
reactor.SwitchToConsensus(ctx, state, false)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
for _, sub := range rts.subs {
wg.Add(1)
@@ -456,10 +464,14 @@ func TestReactorWithEvidence(t *testing.T) {
}
func TestReactorCreatesBlockWhenEmptyBlocksFalse(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg := configSetup(t)
n := 4
states, cleanup := randConsensusState(
ctx,
t,
cfg,
n,
@@ -473,26 +485,24 @@ func TestReactorCreatesBlockWhenEmptyBlocksFalse(t *testing.T) {
t.Cleanup(cleanup)
rts := setup(t, n, states, 100) // buffer must be large enough to not deadlock
rts := setup(ctx, t, n, states, 100) // buffer must be large enough to not deadlock
for _, reactor := range rts.reactors {
state := reactor.state.GetState()
reactor.SwitchToConsensus(state, false)
reactor.SwitchToConsensus(ctx, state, false)
}
// send a tx
require.NoError(
t,
assertMempool(states[3].txNotifier).CheckTx(
context.Background(),
ctx,
[]byte{1, 2, 3},
nil,
mempool.TxInfo{},
),
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
for _, sub := range rts.subs {
wg.Add(1)
@@ -511,23 +521,24 @@ func TestReactorCreatesBlockWhenEmptyBlocksFalse(t *testing.T) {
}
func TestReactorRecordsVotesAndBlockParts(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg := configSetup(t)
n := 4
states, cleanup := randConsensusState(t,
states, cleanup := randConsensusState(ctx, t,
cfg, n, "consensus_reactor_test",
newMockTickerFunc(true), newKVStore)
t.Cleanup(cleanup)
rts := setup(t, n, states, 100) // buffer must be large enough to not deadlock
rts := setup(ctx, t, n, states, 100) // buffer must be large enough to not deadlock
for _, reactor := range rts.reactors {
state := reactor.state.GetState()
reactor.SwitchToConsensus(state, false)
reactor.SwitchToConsensus(ctx, state, false)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
for _, sub := range rts.subs {
wg.Add(1)
@@ -575,10 +586,14 @@ func TestReactorRecordsVotesAndBlockParts(t *testing.T) {
}
func TestReactorVotingPowerChange(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg := configSetup(t)
n := 4
states, cleanup := randConsensusState(
ctx,
t,
cfg,
n,
@@ -589,25 +604,23 @@ func TestReactorVotingPowerChange(t *testing.T) {
t.Cleanup(cleanup)
rts := setup(t, n, states, 100) // buffer must be large enough to not deadlock
rts := setup(ctx, t, n, states, 100) // buffer must be large enough to not deadlock
for _, reactor := range rts.reactors {
state := reactor.state.GetState()
reactor.SwitchToConsensus(state, false)
reactor.SwitchToConsensus(ctx, state, false)
}
// map of active validators
activeVals := make(map[string]struct{})
for i := 0; i < n; i++ {
pubKey, err := states[i].privValidator.GetPubKey(context.Background())
pubKey, err := states[i].privValidator.GetPubKey(ctx)
require.NoError(t, err)
addr := pubKey.Address()
activeVals[string(addr)] = struct{}{}
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
for _, sub := range rts.subs {
wg.Add(1)
@@ -629,7 +642,7 @@ func TestReactorVotingPowerChange(t *testing.T) {
blocksSubs = append(blocksSubs, sub)
}
val1PubKey, err := states[0].privValidator.GetPubKey(context.Background())
val1PubKey, err := states[0].privValidator.GetPubKey(ctx)
require.NoError(t, err)
val1PubKeyABCI, err := encoding.PubKeyToProto(val1PubKey)
@@ -638,10 +651,10 @@ func TestReactorVotingPowerChange(t *testing.T) {
updateValidatorTx := kvstore.MakeValSetChangeTx(val1PubKeyABCI, 25)
previousTotalVotingPower := states[0].GetRoundState().LastValidators.TotalVotingPower()
waitForAndValidateBlock(t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlockWithTx(t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlock(t, n, activeVals, blocksSubs, states)
waitForAndValidateBlock(t, n, activeVals, blocksSubs, states)
waitForAndValidateBlock(ctx, t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlockWithTx(ctx, t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlock(ctx, t, n, activeVals, blocksSubs, states)
waitForAndValidateBlock(ctx, t, n, activeVals, blocksSubs, states)
require.NotEqualf(
t, previousTotalVotingPower, states[0].GetRoundState().LastValidators.TotalVotingPower(),
@@ -653,10 +666,10 @@ func TestReactorVotingPowerChange(t *testing.T) {
updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 2)
previousTotalVotingPower = states[0].GetRoundState().LastValidators.TotalVotingPower()
waitForAndValidateBlock(t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlockWithTx(t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlock(t, n, activeVals, blocksSubs, states)
waitForAndValidateBlock(t, n, activeVals, blocksSubs, states)
waitForAndValidateBlock(ctx, t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlockWithTx(ctx, t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlock(ctx, t, n, activeVals, blocksSubs, states)
waitForAndValidateBlock(ctx, t, n, activeVals, blocksSubs, states)
require.NotEqualf(
t, states[0].GetRoundState().LastValidators.TotalVotingPower(), previousTotalVotingPower,
@@ -667,10 +680,10 @@ func TestReactorVotingPowerChange(t *testing.T) {
updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 26)
previousTotalVotingPower = states[0].GetRoundState().LastValidators.TotalVotingPower()
waitForAndValidateBlock(t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlockWithTx(t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlock(t, n, activeVals, blocksSubs, states)
waitForAndValidateBlock(t, n, activeVals, blocksSubs, states)
waitForAndValidateBlock(ctx, t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlockWithTx(ctx, t, n, activeVals, blocksSubs, states, updateValidatorTx)
waitForAndValidateBlock(ctx, t, n, activeVals, blocksSubs, states)
waitForAndValidateBlock(ctx, t, n, activeVals, blocksSubs, states)
require.NotEqualf(
t, previousTotalVotingPower, states[0].GetRoundState().LastValidators.TotalVotingPower(),
@@ -681,11 +694,15 @@ func TestReactorVotingPowerChange(t *testing.T) {
}
func TestReactorValidatorSetChanges(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg := configSetup(t)
nPeers := 7
nVals := 4
states, _, _, cleanup := randConsensusNetWithPeers(
ctx,
cfg,
nVals,
nPeers,
@@ -695,11 +712,11 @@ func TestReactorValidatorSetChanges(t *testing.T) {
)
t.Cleanup(cleanup)
rts := setup(t, nPeers, states, 100) // buffer must be large enough to not deadlock
rts := setup(ctx, t, nPeers, states, 100) // buffer must be large enough to not deadlock
for _, reactor := range rts.reactors {
state := reactor.state.GetState()
reactor.SwitchToConsensus(state, false)
reactor.SwitchToConsensus(ctx, state, false)
}
// map of active validators
@@ -711,8 +728,6 @@ func TestReactorValidatorSetChanges(t *testing.T) {
activeVals[string(pubKey.Address())] = struct{}{}
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var wg sync.WaitGroup
for _, sub := range rts.subs {
wg.Add(1)
@@ -729,7 +744,7 @@ func TestReactorValidatorSetChanges(t *testing.T) {
wg.Wait()
newValidatorPubKey1, err := states[nVals].privValidator.GetPubKey(context.Background())
newValidatorPubKey1, err := states[nVals].privValidator.GetPubKey(ctx)
require.NoError(t, err)
valPubKey1ABCI, err := encoding.PubKeyToProto(newValidatorPubKey1)
@@ -745,24 +760,24 @@ func TestReactorValidatorSetChanges(t *testing.T) {
// wait till everyone makes block 2
// ensure the commit includes all validators
// send newValTx to change vals in block 3
waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, states, newValidatorTx1)
waitForAndValidateBlock(ctx, t, nPeers, activeVals, blocksSubs, states, newValidatorTx1)
// wait till everyone makes block 3.
// it includes the commit for block 2, which is by the original validator set
waitForAndValidateBlockWithTx(t, nPeers, activeVals, blocksSubs, states, newValidatorTx1)
waitForAndValidateBlockWithTx(ctx, t, nPeers, activeVals, blocksSubs, states, newValidatorTx1)
// wait till everyone makes block 4.
// it includes the commit for block 3, which is by the original validator set
waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, states)
waitForAndValidateBlock(ctx, t, nPeers, activeVals, blocksSubs, states)
// the commits for block 4 should be with the updated validator set
activeVals[string(newValidatorPubKey1.Address())] = struct{}{}
// wait till everyone makes block 5
// it includes the commit for block 4, which should have the updated validator set
waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, blocksSubs, states)
waitForBlockWithUpdatedValsAndValidateIt(ctx, t, nPeers, activeVals, blocksSubs, states)
updateValidatorPubKey1, err := states[nVals].privValidator.GetPubKey(context.Background())
updateValidatorPubKey1, err := states[nVals].privValidator.GetPubKey(ctx)
require.NoError(t, err)
updatePubKey1ABCI, err := encoding.PubKeyToProto(updateValidatorPubKey1)
@@ -771,10 +786,10 @@ func TestReactorValidatorSetChanges(t *testing.T) {
updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25)
previousTotalVotingPower := states[nVals].GetRoundState().LastValidators.TotalVotingPower()
waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, states, updateValidatorTx1)
waitForAndValidateBlockWithTx(t, nPeers, activeVals, blocksSubs, states, updateValidatorTx1)
waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, states)
waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, blocksSubs, states)
waitForAndValidateBlock(ctx, t, nPeers, activeVals, blocksSubs, states, updateValidatorTx1)
waitForAndValidateBlockWithTx(ctx, t, nPeers, activeVals, blocksSubs, states, updateValidatorTx1)
waitForAndValidateBlock(ctx, t, nPeers, activeVals, blocksSubs, states)
waitForBlockWithUpdatedValsAndValidateIt(ctx, t, nPeers, activeVals, blocksSubs, states)
require.NotEqualf(
t, states[nVals].GetRoundState().LastValidators.TotalVotingPower(), previousTotalVotingPower,
@@ -782,7 +797,7 @@ func TestReactorValidatorSetChanges(t *testing.T) {
previousTotalVotingPower, states[nVals].GetRoundState().LastValidators.TotalVotingPower(),
)
newValidatorPubKey2, err := states[nVals+1].privValidator.GetPubKey(context.Background())
newValidatorPubKey2, err := states[nVals+1].privValidator.GetPubKey(ctx)
require.NoError(t, err)
newVal2ABCI, err := encoding.PubKeyToProto(newValidatorPubKey2)
@@ -790,7 +805,7 @@ func TestReactorValidatorSetChanges(t *testing.T) {
newValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, testMinPower)
newValidatorPubKey3, err := states[nVals+2].privValidator.GetPubKey(context.Background())
newValidatorPubKey3, err := states[nVals+2].privValidator.GetPubKey(ctx)
require.NoError(t, err)
newVal3ABCI, err := encoding.PubKeyToProto(newValidatorPubKey3)
@@ -798,24 +813,24 @@ func TestReactorValidatorSetChanges(t *testing.T) {
newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower)
waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, states, newValidatorTx2, newValidatorTx3)
waitForAndValidateBlockWithTx(t, nPeers, activeVals, blocksSubs, states, newValidatorTx2, newValidatorTx3)
waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, states)
waitForAndValidateBlock(ctx, t, nPeers, activeVals, blocksSubs, states, newValidatorTx2, newValidatorTx3)
waitForAndValidateBlockWithTx(ctx, t, nPeers, activeVals, blocksSubs, states, newValidatorTx2, newValidatorTx3)
waitForAndValidateBlock(ctx, t, nPeers, activeVals, blocksSubs, states)
activeVals[string(newValidatorPubKey2.Address())] = struct{}{}
activeVals[string(newValidatorPubKey3.Address())] = struct{}{}
waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, blocksSubs, states)
waitForBlockWithUpdatedValsAndValidateIt(ctx, t, nPeers, activeVals, blocksSubs, states)
removeValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, 0)
removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0)
waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, states, removeValidatorTx2, removeValidatorTx3)
waitForAndValidateBlockWithTx(t, nPeers, activeVals, blocksSubs, states, removeValidatorTx2, removeValidatorTx3)
waitForAndValidateBlock(t, nPeers, activeVals, blocksSubs, states)
waitForAndValidateBlock(ctx, t, nPeers, activeVals, blocksSubs, states, removeValidatorTx2, removeValidatorTx3)
waitForAndValidateBlockWithTx(ctx, t, nPeers, activeVals, blocksSubs, states, removeValidatorTx2, removeValidatorTx3)
waitForAndValidateBlock(ctx, t, nPeers, activeVals, blocksSubs, states)
delete(activeVals, string(newValidatorPubKey2.Address()))
delete(activeVals, string(newValidatorPubKey3.Address()))
waitForBlockWithUpdatedValsAndValidateIt(t, nPeers, activeVals, blocksSubs, states)
waitForBlockWithUpdatedValsAndValidateIt(ctx, t, nPeers, activeVals, blocksSubs, states)
}
+6 -5
View File
@@ -237,10 +237,10 @@ func (h *Handshaker) NBlocks() int {
}
// TODO: retry the handshake/replay if it fails ?
func (h *Handshaker) Handshake(proxyApp proxy.AppConns) error {
func (h *Handshaker) Handshake(ctx context.Context, proxyApp proxy.AppConns) error {
// Handshake is done via ABCI Info on the query conn.
res, err := proxyApp.Query().InfoSync(context.Background(), proxy.RequestInfo)
res, err := proxyApp.Query().InfoSync(ctx, proxy.RequestInfo)
if err != nil {
return fmt.Errorf("error calling Info: %v", err)
}
@@ -264,7 +264,7 @@ func (h *Handshaker) Handshake(proxyApp proxy.AppConns) error {
}
// Replay blocks up to the latest in the blockstore.
_, err = h.ReplayBlocks(h.initialState, appHash, blockHeight, proxyApp)
_, err = h.ReplayBlocks(ctx, h.initialState, appHash, blockHeight, proxyApp)
if err != nil {
return fmt.Errorf("error on replay: %v", err)
}
@@ -281,6 +281,7 @@ func (h *Handshaker) Handshake(proxyApp proxy.AppConns) error {
// matches the current state.
// Returns the final AppHash or an error.
func (h *Handshaker) ReplayBlocks(
ctx context.Context,
state sm.State,
appHash []byte,
appBlockHeight int64,
@@ -315,7 +316,7 @@ func (h *Handshaker) ReplayBlocks(
Validators: nextVals,
AppStateBytes: h.genDoc.AppState,
}
res, err := proxyApp.Consensus().InitChainSync(context.Background(), req)
res, err := proxyApp.Consensus().InitChainSync(ctx, req)
if err != nil {
return nil, err
}
@@ -421,7 +422,7 @@ func (h *Handshaker) ReplayBlocks(
if err != nil {
return nil, err
}
mockApp := newMockProxyApp(h.logger, appHash, abciResponses)
mockApp := newMockProxyApp(ctx, h.logger, appHash, abciResponses)
h.logger.Info("Replay last block using mock app")
state, err = h.replayBlock(state, storeBlockHeight, mockApp)
return state.AppHash, err
+8 -7
View File
@@ -32,17 +32,18 @@ const (
// replay the wal file
func RunReplayFile(
ctx context.Context,
logger log.Logger,
cfg config.BaseConfig,
csConfig *config.ConsensusConfig,
console bool,
) error {
consensusState, err := newConsensusStateForReplay(cfg, logger, csConfig)
consensusState, err := newConsensusStateForReplay(ctx, cfg, logger, csConfig)
if err != nil {
return err
}
if err := consensusState.ReplayFile(csConfig.WalFile(), console); err != nil {
if err := consensusState.ReplayFile(ctx, csConfig.WalFile(), console); err != nil {
return fmt.Errorf("consensus replay: %w", err)
}
@@ -50,7 +51,7 @@ func RunReplayFile(
}
// Replay msgs in file or start the console
func (cs *State) ReplayFile(file string, console bool) error {
func (cs *State) ReplayFile(ctx context.Context, file string, console bool) error {
if cs.IsRunning() {
return errors.New("cs is already running, cannot replay")
@@ -63,7 +64,6 @@ func (cs *State) ReplayFile(file string, console bool) error {
// ensure all new step events are regenerated as expected
ctx := context.Background()
newStepSub, err := cs.eventBus.SubscribeWithArgs(ctx, tmpubsub.SubscribeArgs{
ClientID: subscriber,
Query: types.EventQueryNewRoundStep,
@@ -307,6 +307,7 @@ func (pb *playback) replayConsoleLoop() (int, error) {
// convenience for replay mode
func newConsensusStateForReplay(
ctx context.Context,
cfg config.BaseConfig,
logger log.Logger,
csConfig *config.ConsensusConfig,
@@ -339,19 +340,19 @@ func newConsensusStateForReplay(
// Create proxyAppConn connection (consensus, mempool, query)
clientCreator, _ := proxy.DefaultClientCreator(logger, cfg.ProxyApp, cfg.ABCI, cfg.DBDir())
proxyApp := proxy.NewAppConns(clientCreator, logger, proxy.NopMetrics())
err = proxyApp.Start()
err = proxyApp.Start(ctx)
if err != nil {
return nil, fmt.Errorf("starting proxy app conns: %w", err)
}
eventBus := eventbus.NewDefault(logger)
if err := eventBus.Start(); err != nil {
if err := eventBus.Start(ctx); err != nil {
return nil, fmt.Errorf("failed to start event bus: %w", err)
}
handshaker := NewHandshaker(logger, stateStore, state, blockStore, eventBus, gdoc)
if err = handshaker.Handshake(proxyApp); err != nil {
if err = handshaker.Handshake(ctx, proxyApp); err != nil {
return nil, err
}
+7 -2
View File
@@ -55,13 +55,18 @@ func (emptyMempool) CloseWAL() {}
// Useful because we don't want to call Commit() twice for the same block on
// the real app.
func newMockProxyApp(logger log.Logger, appHash []byte, abciResponses *tmstate.ABCIResponses) proxy.AppConnConsensus {
func newMockProxyApp(
ctx context.Context,
logger log.Logger,
appHash []byte,
abciResponses *tmstate.ABCIResponses,
) proxy.AppConnConsensus {
clientCreator := abciclient.NewLocalCreator(&mockProxyApp{
appHash: appHash,
abciResponses: abciResponses,
})
cli, _ := clientCreator(logger)
err := cli.Start()
err := cli.Start(ctx)
if err != nil {
panic(err)
}
+135 -100
View File
@@ -56,7 +56,7 @@ import (
// and which ones we need the wal for - then we'd also be able to only flush the
// wal writer when we need to, instead of with every message.
func startNewStateAndWaitForBlock(t *testing.T, consensusReplayConfig *config.Config,
func startNewStateAndWaitForBlock(ctx context.Context, t *testing.T, consensusReplayConfig *config.Config,
lastBlockHeight int64, blockDB dbm.DB, stateStore sm.Store) {
logger := log.TestingLogger()
state, err := sm.MakeGenesisStateFromFile(consensusReplayConfig.GenesisFile())
@@ -64,6 +64,7 @@ func startNewStateAndWaitForBlock(t *testing.T, consensusReplayConfig *config.Co
privValidator := loadPrivValidator(consensusReplayConfig)
blockStore := store.NewBlockStore(dbm.NewMemDB())
cs := newStateWithConfigAndBlockStore(
ctx,
logger,
consensusReplayConfig,
state,
@@ -75,7 +76,7 @@ func startNewStateAndWaitForBlock(t *testing.T, consensusReplayConfig *config.Co
bytes, _ := os.ReadFile(cs.config.WalFile())
t.Logf("====== WAL: \n\r%X\n", bytes)
err = cs.Start()
err = cs.Start(ctx)
require.NoError(t, err)
defer func() {
if err := cs.Stop(); err != nil {
@@ -87,12 +88,12 @@ func startNewStateAndWaitForBlock(t *testing.T, consensusReplayConfig *config.Co
// in the WAL itself. Assuming the consensus state is running, replay of any
// WAL, including the empty one, should eventually be followed by a new
// block, or else something is wrong.
newBlockSub, err := cs.eventBus.SubscribeWithArgs(context.Background(), pubsub.SubscribeArgs{
newBlockSub, err := cs.eventBus.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
ClientID: testSubscriber,
Query: types.EventQueryNewBlock,
})
require.NoError(t, err)
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
ctx, cancel := context.WithTimeout(ctx, 120*time.Second)
defer cancel()
_, err = newBlockSub.Next(ctx)
if errors.Is(err, context.DeadlineExceeded) {
@@ -109,7 +110,7 @@ func sendTxs(ctx context.Context, cs *State) {
return
default:
tx := []byte{byte(i)}
if err := assertMempool(cs.txNotifier).CheckTx(context.Background(), tx, nil, mempool.TxInfo{}); err != nil {
if err := assertMempool(cs.txNotifier).CheckTx(ctx, tx, nil, mempool.TxInfo{}); err != nil {
panic(err)
}
i++
@@ -119,6 +120,9 @@ func sendTxs(ctx context.Context, cs *State) {
// TestWALCrash uses crashing WAL to test we can recover from any WAL failure.
func TestWALCrash(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
testCases := []struct {
name string
initFn func(dbm.DB, *State, context.Context)
@@ -139,12 +143,12 @@ func TestWALCrash(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
consensusReplayConfig, err := ResetConfig(tc.name)
require.NoError(t, err)
crashWALandCheckLiveness(t, consensusReplayConfig, tc.initFn, tc.heightToStop)
crashWALandCheckLiveness(ctx, t, consensusReplayConfig, tc.initFn, tc.heightToStop)
})
}
}
func crashWALandCheckLiveness(t *testing.T, consensusReplayConfig *config.Config,
func crashWALandCheckLiveness(ctx context.Context, t *testing.T, consensusReplayConfig *config.Config,
initFn func(dbm.DB, *State, context.Context), heightToStop int64) {
walPanicked := make(chan error)
crashingWal := &crashingWAL{panicCh: walPanicked, heightToStop: heightToStop}
@@ -164,6 +168,7 @@ LOOP:
require.NoError(t, err)
privValidator := loadPrivValidator(consensusReplayConfig)
cs := newStateWithConfigAndBlockStore(
ctx,
logger,
consensusReplayConfig,
state,
@@ -173,7 +178,7 @@ LOOP:
)
// start sending transactions
ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithCancel(ctx)
initFn(stateDB, cs, ctx)
// clean up WAL file from the previous iteration
@@ -181,7 +186,7 @@ LOOP:
os.Remove(walFile)
// set crashing WAL
csWal, err := cs.OpenWAL(walFile)
csWal, err := cs.OpenWAL(ctx, walFile)
require.NoError(t, err)
crashingWal.next = csWal
@@ -190,7 +195,7 @@ LOOP:
cs.wal = crashingWal
// start consensus state
err = cs.Start()
err = cs.Start(ctx)
require.NoError(t, err)
i++
@@ -200,7 +205,7 @@ LOOP:
t.Logf("WAL panicked: %v", err)
// make sure we can make blocks after a crash
startNewStateAndWaitForBlock(t, consensusReplayConfig, cs.Height, blockDB, stateStore)
startNewStateAndWaitForBlock(ctx, t, consensusReplayConfig, cs.Height, blockDB, stateStore)
// stop consensus state and transactions sender (initFn)
cs.Stop() //nolint:errcheck // Logging this error causes failure
@@ -286,9 +291,9 @@ func (w *crashingWAL) SearchForEndHeight(
return w.next.SearchForEndHeight(height, options)
}
func (w *crashingWAL) Start() error { return w.next.Start() }
func (w *crashingWAL) Stop() error { return w.next.Stop() }
func (w *crashingWAL) Wait() { w.next.Wait() }
func (w *crashingWAL) Start(ctx context.Context) error { return w.next.Start(ctx) }
func (w *crashingWAL) Stop() error { return w.next.Stop() }
func (w *crashingWAL) Wait() { w.next.Wait() }
//------------------------------------------------------------------------------------------
type simulatorTestSuite struct {
@@ -316,7 +321,7 @@ const (
var modes = []uint{0, 1, 2, 3}
// This is actually not a test, it's for storing validator change tx data for testHandshakeReplay
func setupSimulator(t *testing.T) *simulatorTestSuite {
func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
t.Helper()
cfg := configSetup(t)
@@ -329,6 +334,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
nVals := 4
css, genDoc, cfg, cleanup := randConsensusNetWithPeers(
ctx,
cfg,
nVals,
nPeers,
@@ -341,8 +347,8 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
partSize := types.BlockPartSizeBytes
newRoundCh := subscribe(t, css[0].eventBus, types.EventQueryNewRound)
proposalCh := subscribe(t, css[0].eventBus, types.EventQueryCompleteProposal)
newRoundCh := subscribe(ctx, t, css[0].eventBus, types.EventQueryNewRound)
proposalCh := subscribe(ctx, t, css[0].eventBus, types.EventQueryCompleteProposal)
vss := make([]*validatorStub, nPeers)
for i := 0; i < nPeers; i++ {
@@ -351,13 +357,13 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
height, round := css[0].Height, css[0].Round
// start the machine
startTestRound(css[0], height, round)
startTestRound(ctx, css[0], height, round)
incrementHeight(vss...)
ensureNewRound(newRoundCh, height, 0)
ensureNewProposal(proposalCh, height, round)
rs := css[0].GetRoundState()
signAddVotes(sim.Config, css[0], tmproto.PrecommitType,
signAddVotes(ctx, sim.Config, css[0], tmproto.PrecommitType,
rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(),
vss[1:nVals]...)
@@ -366,12 +372,12 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
// HEIGHT 2
height++
incrementHeight(vss...)
newValidatorPubKey1, err := css[nVals].privValidator.GetPubKey(context.Background())
newValidatorPubKey1, err := css[nVals].privValidator.GetPubKey(ctx)
require.NoError(t, err)
valPubKey1ABCI, err := encoding.PubKeyToProto(newValidatorPubKey1)
require.NoError(t, err)
newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower)
err = assertMempool(css[0].txNotifier).CheckTx(context.Background(), newValidatorTx1, nil, mempool.TxInfo{})
err = assertMempool(css[0].txNotifier).CheckTx(ctx, newValidatorTx1, nil, mempool.TxInfo{})
assert.Nil(t, err)
propBlock, _ := css[0].createProposalBlock() // changeProposer(t, cs1, vs2)
propBlockParts := propBlock.MakePartSet(partSize)
@@ -379,7 +385,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
proposal := types.NewProposal(vss[1].Height, round, -1, blockID)
p := proposal.ToProto()
if err := vss[1].SignProposal(context.Background(), cfg.ChainID(), p); err != nil {
if err := vss[1].SignProposal(ctx, cfg.ChainID(), p); err != nil {
t.Fatal("failed to sign bad proposal", err)
}
proposal.Signature = p.Signature
@@ -390,7 +396,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
}
ensureNewProposal(proposalCh, height, round)
rs = css[0].GetRoundState()
signAddVotes(sim.Config, css[0], tmproto.PrecommitType,
signAddVotes(ctx, sim.Config, css[0], tmproto.PrecommitType,
rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(),
vss[1:nVals]...)
ensureNewRound(newRoundCh, height+1, 0)
@@ -398,12 +404,12 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
// HEIGHT 3
height++
incrementHeight(vss...)
updateValidatorPubKey1, err := css[nVals].privValidator.GetPubKey(context.Background())
updateValidatorPubKey1, err := css[nVals].privValidator.GetPubKey(ctx)
require.NoError(t, err)
updatePubKey1ABCI, err := encoding.PubKeyToProto(updateValidatorPubKey1)
require.NoError(t, err)
updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25)
err = assertMempool(css[0].txNotifier).CheckTx(context.Background(), updateValidatorTx1, nil, mempool.TxInfo{})
err = assertMempool(css[0].txNotifier).CheckTx(ctx, updateValidatorTx1, nil, mempool.TxInfo{})
assert.Nil(t, err)
propBlock, _ = css[0].createProposalBlock() // changeProposer(t, cs1, vs2)
propBlockParts = propBlock.MakePartSet(partSize)
@@ -411,7 +417,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
proposal = types.NewProposal(vss[2].Height, round, -1, blockID)
p = proposal.ToProto()
if err := vss[2].SignProposal(context.Background(), cfg.ChainID(), p); err != nil {
if err := vss[2].SignProposal(ctx, cfg.ChainID(), p); err != nil {
t.Fatal("failed to sign bad proposal", err)
}
proposal.Signature = p.Signature
@@ -422,7 +428,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
}
ensureNewProposal(proposalCh, height, round)
rs = css[0].GetRoundState()
signAddVotes(sim.Config, css[0], tmproto.PrecommitType,
signAddVotes(ctx, sim.Config, css[0], tmproto.PrecommitType,
rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(),
vss[1:nVals]...)
ensureNewRound(newRoundCh, height+1, 0)
@@ -430,19 +436,19 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
// HEIGHT 4
height++
incrementHeight(vss...)
newValidatorPubKey2, err := css[nVals+1].privValidator.GetPubKey(context.Background())
newValidatorPubKey2, err := css[nVals+1].privValidator.GetPubKey(ctx)
require.NoError(t, err)
newVal2ABCI, err := encoding.PubKeyToProto(newValidatorPubKey2)
require.NoError(t, err)
newValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, testMinPower)
err = assertMempool(css[0].txNotifier).CheckTx(context.Background(), newValidatorTx2, nil, mempool.TxInfo{})
err = assertMempool(css[0].txNotifier).CheckTx(ctx, newValidatorTx2, nil, mempool.TxInfo{})
assert.Nil(t, err)
newValidatorPubKey3, err := css[nVals+2].privValidator.GetPubKey(context.Background())
newValidatorPubKey3, err := css[nVals+2].privValidator.GetPubKey(ctx)
require.NoError(t, err)
newVal3ABCI, err := encoding.PubKeyToProto(newValidatorPubKey3)
require.NoError(t, err)
newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower)
err = assertMempool(css[0].txNotifier).CheckTx(context.Background(), newValidatorTx3, nil, mempool.TxInfo{})
err = assertMempool(css[0].txNotifier).CheckTx(ctx, newValidatorTx3, nil, mempool.TxInfo{})
assert.Nil(t, err)
propBlock, _ = css[0].createProposalBlock() // changeProposer(t, cs1, vs2)
propBlockParts = propBlock.MakePartSet(partSize)
@@ -453,10 +459,10 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
valIndexFn := func(cssIdx int) int {
for i, vs := range newVss {
vsPubKey, err := vs.GetPubKey(context.Background())
vsPubKey, err := vs.GetPubKey(ctx)
require.NoError(t, err)
cssPubKey, err := css[cssIdx].privValidator.GetPubKey(context.Background())
cssPubKey, err := css[cssIdx].privValidator.GetPubKey(ctx)
require.NoError(t, err)
if vsPubKey.Equals(cssPubKey) {
@@ -470,7 +476,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
proposal = types.NewProposal(vss[3].Height, round, -1, blockID)
p = proposal.ToProto()
if err := vss[3].SignProposal(context.Background(), cfg.ChainID(), p); err != nil {
if err := vss[3].SignProposal(ctx, cfg.ChainID(), p); err != nil {
t.Fatal("failed to sign bad proposal", err)
}
proposal.Signature = p.Signature
@@ -482,7 +488,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
ensureNewProposal(proposalCh, height, round)
removeValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, 0)
err = assertMempool(css[0].txNotifier).CheckTx(context.Background(), removeValidatorTx2, nil, mempool.TxInfo{})
err = assertMempool(css[0].txNotifier).CheckTx(ctx, removeValidatorTx2, nil, mempool.TxInfo{})
assert.Nil(t, err)
rs = css[0].GetRoundState()
@@ -490,7 +496,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
if i == selfIndex {
continue
}
signAddVotes(sim.Config, css[0],
signAddVotes(ctx, sim.Config, css[0],
tmproto.PrecommitType, rs.ProposalBlock.Hash(),
rs.ProposalBlockParts.Header(), newVss[i])
}
@@ -511,7 +517,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
if i == selfIndex {
continue
}
signAddVotes(sim.Config, css[0],
signAddVotes(ctx, sim.Config, css[0],
tmproto.PrecommitType, rs.ProposalBlock.Hash(),
rs.ProposalBlockParts.Header(), newVss[i])
}
@@ -521,7 +527,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
height++
incrementHeight(vss...)
removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0)
err = assertMempool(css[0].txNotifier).CheckTx(context.Background(), removeValidatorTx3, nil, mempool.TxInfo{})
err = assertMempool(css[0].txNotifier).CheckTx(ctx, removeValidatorTx3, nil, mempool.TxInfo{})
assert.Nil(t, err)
propBlock, _ = css[0].createProposalBlock() // changeProposer(t, cs1, vs2)
propBlockParts = propBlock.MakePartSet(partSize)
@@ -533,7 +539,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
selfIndex = valIndexFn(0)
proposal = types.NewProposal(vss[1].Height, round, -1, blockID)
p = proposal.ToProto()
if err := vss[1].SignProposal(context.Background(), cfg.ChainID(), p); err != nil {
if err := vss[1].SignProposal(ctx, cfg.ChainID(), p); err != nil {
t.Fatal("failed to sign bad proposal", err)
}
proposal.Signature = p.Signature
@@ -548,7 +554,7 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
if i == selfIndex {
continue
}
signAddVotes(sim.Config, css[0],
signAddVotes(ctx, sim.Config, css[0],
tmproto.PrecommitType, rs.ProposalBlock.Hash(),
rs.ProposalBlockParts.Header(), newVss[i])
}
@@ -569,55 +575,70 @@ func setupSimulator(t *testing.T) *simulatorTestSuite {
// Sync from scratch
func TestHandshakeReplayAll(t *testing.T) {
sim := setupSimulator(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sim := setupSimulator(ctx, t)
for _, m := range modes {
testHandshakeReplay(t, sim, 0, m, false)
testHandshakeReplay(ctx, t, sim, 0, m, false)
}
for _, m := range modes {
testHandshakeReplay(t, sim, 0, m, true)
testHandshakeReplay(ctx, t, sim, 0, m, true)
}
}
// Sync many, not from scratch
func TestHandshakeReplaySome(t *testing.T) {
sim := setupSimulator(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sim := setupSimulator(ctx, t)
for _, m := range modes {
testHandshakeReplay(t, sim, 2, m, false)
testHandshakeReplay(ctx, t, sim, 2, m, false)
}
for _, m := range modes {
testHandshakeReplay(t, sim, 2, m, true)
testHandshakeReplay(ctx, t, sim, 2, m, true)
}
}
// Sync from lagging by one
func TestHandshakeReplayOne(t *testing.T) {
sim := setupSimulator(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sim := setupSimulator(ctx, t)
for _, m := range modes {
testHandshakeReplay(t, sim, numBlocks-1, m, false)
testHandshakeReplay(ctx, t, sim, numBlocks-1, m, false)
}
for _, m := range modes {
testHandshakeReplay(t, sim, numBlocks-1, m, true)
testHandshakeReplay(ctx, t, sim, numBlocks-1, m, true)
}
}
// Sync from caught up
func TestHandshakeReplayNone(t *testing.T) {
sim := setupSimulator(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sim := setupSimulator(ctx, t)
for _, m := range modes {
testHandshakeReplay(t, sim, numBlocks, m, false)
testHandshakeReplay(ctx, t, sim, numBlocks, m, false)
}
for _, m := range modes {
testHandshakeReplay(t, sim, numBlocks, m, true)
testHandshakeReplay(ctx, t, sim, numBlocks, m, true)
}
}
// Test mockProxyApp should not panic when app return ABCIResponses with some empty ResponseDeliverTx
func TestMockProxyApp(t *testing.T) {
sim := setupSimulator(t) // setup config and simulator
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sim := setupSimulator(ctx, t) // setup config and simulator
cfg := sim.Config
assert.NotNil(t, cfg)
@@ -639,7 +660,7 @@ func TestMockProxyApp(t *testing.T) {
err = proto.Unmarshal(bytes, loadedAbciRes)
require.NoError(t, err)
mock := newMockProxyApp(logger, []byte("mock_hash"), loadedAbciRes)
mock := newMockProxyApp(ctx, logger, []byte("mock_hash"), loadedAbciRes)
abciRes := new(tmstate.ABCIResponses)
abciRes.DeliverTxs = make([]*abci.ResponseDeliverTx, len(loadedAbciRes.DeliverTxs))
@@ -663,7 +684,7 @@ func TestMockProxyApp(t *testing.T) {
mock.SetResponseCallback(proxyCb)
someTx := []byte("tx")
_, err = mock.DeliverTxAsync(context.Background(), abci.RequestDeliverTx{Tx: someTx})
_, err = mock.DeliverTxAsync(ctx, abci.RequestDeliverTx{Tx: someTx})
assert.NoError(t, err)
})
assert.True(t, validTxs == 1)
@@ -687,12 +708,23 @@ func tempWALWithData(data []byte) string {
// Make some blocks. Start a fresh app and apply nBlocks blocks.
// Then restart the app and sync it up with the remaining blocks
func testHandshakeReplay(t *testing.T, sim *simulatorTestSuite, nBlocks int, mode uint, testValidatorsChange bool) {
func testHandshakeReplay(
ctx context.Context,
t *testing.T,
sim *simulatorTestSuite,
nBlocks int,
mode uint,
testValidatorsChange bool,
) {
var chain []*types.Block
var commits []*types.Commit
var store *mockBlockStore
var stateDB dbm.DB
var genesisState sm.State
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
t.Cleanup(cancel)
cfg := sim.Config
@@ -712,7 +744,7 @@ func testHandshakeReplay(t *testing.T, sim *simulatorTestSuite, nBlocks int, mod
testConfig, err := ResetConfig(fmt.Sprintf("%s_%v_s", t.Name(), mode))
require.NoError(t, err)
defer func() { _ = os.RemoveAll(testConfig.RootDir) }()
walBody, err := WALWithNBlocks(t, numBlocks)
walBody, err := WALWithNBlocks(ctx, t, numBlocks)
require.NoError(t, err)
walFile := tempWALWithData(walBody)
cfg.Consensus.SetWalFile(walFile)
@@ -722,16 +754,12 @@ func testHandshakeReplay(t *testing.T, sim *simulatorTestSuite, nBlocks int, mod
wal, err := NewWAL(logger, walFile)
require.NoError(t, err)
err = wal.Start()
err = wal.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := wal.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); wal.Wait() })
chain, commits, err = makeBlockchainFromWAL(wal)
require.NoError(t, err)
pubKey, err := privVal.GetPubKey(context.Background())
pubKey, err := privVal.GetPubKey(ctx)
require.NoError(t, err)
stateDB, genesisState, store = stateAndStore(cfg, pubKey, kvstore.ProtocolVersion)
@@ -742,7 +770,19 @@ func testHandshakeReplay(t *testing.T, sim *simulatorTestSuite, nBlocks int, mod
state := genesisState.Copy()
// run the chain through state.ApplyBlock to build up the tendermint state
state = buildTMStateFromChain(cfg, logger, sim.Mempool, sim.Evpool, stateStore, state, chain, nBlocks, mode, store)
state = buildTMStateFromChain(
ctx,
cfg,
logger,
sim.Mempool,
sim.Evpool,
stateStore,
state,
chain,
nBlocks,
mode,
store,
)
latestAppHash := state.AppHash
// make a new client creator
@@ -759,7 +799,7 @@ func testHandshakeReplay(t *testing.T, sim *simulatorTestSuite, nBlocks int, mod
stateStore := sm.NewStore(stateDB1)
err := stateStore.Save(genesisState)
require.NoError(t, err)
buildAppStateFromChain(proxyApp, stateStore, sim.Mempool, sim.Evpool, genesisState, chain, nBlocks, mode, store)
buildAppStateFromChain(ctx, proxyApp, stateStore, sim.Mempool, sim.Evpool, genesisState, chain, nBlocks, mode, store)
}
// Prune block store if requested
@@ -775,17 +815,13 @@ func testHandshakeReplay(t *testing.T, sim *simulatorTestSuite, nBlocks int, mod
genDoc, _ := sm.MakeGenesisDocFromFile(cfg.GenesisFile())
handshaker := NewHandshaker(logger, stateStore, state, store, eventbus.NopEventBus{}, genDoc)
proxyApp := proxy.NewAppConns(clientCreator2, logger, proxy.NopMetrics())
if err := proxyApp.Start(); err != nil {
if err := proxyApp.Start(ctx); err != nil {
t.Fatalf("Error starting proxy app connections: %v", err)
}
t.Cleanup(func() {
if err := proxyApp.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); proxyApp.Wait() })
err := handshaker.Handshake(proxyApp)
err := handshaker.Handshake(ctx, proxyApp)
if expectError {
require.Error(t, err)
return
@@ -794,7 +830,7 @@ func testHandshakeReplay(t *testing.T, sim *simulatorTestSuite, nBlocks int, mod
}
// get the latest app hash from the app
res, err := proxyApp.Query().InfoSync(context.Background(), abci.RequestInfo{Version: ""})
res, err := proxyApp.Query().InfoSync(ctx, abci.RequestInfo{Version: ""})
if err != nil {
t.Fatal(err)
}
@@ -838,6 +874,7 @@ func applyBlock(stateStore sm.Store,
}
func buildAppStateFromChain(
ctx context.Context,
proxyApp proxy.AppConns,
stateStore sm.Store,
mempool mempool.Mempool,
@@ -846,16 +883,16 @@ func buildAppStateFromChain(
chain []*types.Block,
nBlocks int,
mode uint,
blockStore *mockBlockStore) {
blockStore *mockBlockStore,
) {
// start a new app without handshake, play nBlocks blocks
if err := proxyApp.Start(); err != nil {
if err := proxyApp.Start(ctx); err != nil {
panic(err)
}
defer proxyApp.Stop() //nolint:errcheck // ignore
state.Version.Consensus.App = kvstore.ProtocolVersion // simulate handshake, receive app version
validators := types.TM2PB.ValidatorUpdates(state.Validators)
if _, err := proxyApp.Consensus().InitChainSync(context.Background(), abci.RequestInitChain{
if _, err := proxyApp.Consensus().InitChainSync(ctx, abci.RequestInitChain{
Validators: validators,
}); err != nil {
panic(err)
@@ -887,6 +924,7 @@ func buildAppStateFromChain(
}
func buildTMStateFromChain(
ctx context.Context,
cfg *config.Config,
logger log.Logger,
mempool mempool.Mempool,
@@ -905,14 +943,13 @@ func buildTMStateFromChain(
clientCreator := abciclient.NewLocalCreator(kvstoreApp)
proxyApp := proxy.NewAppConns(clientCreator, logger, proxy.NopMetrics())
if err := proxyApp.Start(); err != nil {
if err := proxyApp.Start(ctx); err != nil {
panic(err)
}
defer proxyApp.Stop() //nolint:errcheck
state.Version.Consensus.App = kvstore.ProtocolVersion // simulate handshake, receive app version
validators := types.TM2PB.ValidatorUpdates(state.Validators)
if _, err := proxyApp.Consensus().InitChainSync(context.Background(), abci.RequestInitChain{
if _, err := proxyApp.Consensus().InitChainSync(ctx, abci.RequestInitChain{
Validators: validators,
}); err != nil {
panic(err)
@@ -949,13 +986,17 @@ func TestHandshakePanicsIfAppReturnsWrongAppHash(t *testing.T) {
// - 0x01
// - 0x02
// - 0x03
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg, err := ResetConfig("handshake_test_")
require.NoError(t, err)
t.Cleanup(func() { os.RemoveAll(cfg.RootDir) })
privVal, err := privval.LoadFilePV(cfg.PrivValidator.KeyFile(), cfg.PrivValidator.StateFile())
require.NoError(t, err)
const appVersion = 0x0
pubKey, err := privVal.GetPubKey(context.Background())
pubKey, err := privVal.GetPubKey(ctx)
require.NoError(t, err)
stateDB, state, store := stateAndStore(cfg, pubKey, appVersion)
stateStore := sm.NewStore(stateDB)
@@ -975,17 +1016,13 @@ func TestHandshakePanicsIfAppReturnsWrongAppHash(t *testing.T) {
app := &badApp{numBlocks: 3, allHashesAreWrong: true}
clientCreator := abciclient.NewLocalCreator(app)
proxyApp := proxy.NewAppConns(clientCreator, logger, proxy.NopMetrics())
err := proxyApp.Start()
err := proxyApp.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := proxyApp.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); proxyApp.Wait() })
assert.Panics(t, func() {
h := NewHandshaker(logger, stateStore, state, store, eventbus.NopEventBus{}, genDoc)
if err = h.Handshake(proxyApp); err != nil {
if err = h.Handshake(ctx, proxyApp); err != nil {
t.Log(err)
}
})
@@ -999,17 +1036,13 @@ func TestHandshakePanicsIfAppReturnsWrongAppHash(t *testing.T) {
app := &badApp{numBlocks: 3, onlyLastHashIsWrong: true}
clientCreator := abciclient.NewLocalCreator(app)
proxyApp := proxy.NewAppConns(clientCreator, logger, proxy.NopMetrics())
err := proxyApp.Start()
err := proxyApp.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := proxyApp.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); proxyApp.Wait() })
assert.Panics(t, func() {
h := NewHandshaker(logger, stateStore, state, store, eventbus.NopEventBus{}, genDoc)
if err = h.Handshake(proxyApp); err != nil {
if err = h.Handshake(ctx, proxyApp); err != nil {
t.Log(err)
}
})
@@ -1237,6 +1270,9 @@ func (bs *mockBlockStore) PruneBlocks(height int64) (uint64, error) {
// Test handshake/init chain
func TestHandshakeUpdatesValidators(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
val, _ := factory.RandValidator(true, 10)
vals := types.NewValidatorSet([]*types.Validator{val})
app := &initChainApp{vals: types.TM2PB.ValidatorUpdates(vals)}
@@ -1248,7 +1284,7 @@ func TestHandshakeUpdatesValidators(t *testing.T) {
privVal, err := privval.LoadFilePV(cfg.PrivValidator.KeyFile(), cfg.PrivValidator.StateFile())
require.NoError(t, err)
pubKey, err := privVal.GetPubKey(context.Background())
pubKey, err := privVal.GetPubKey(ctx)
require.NoError(t, err)
stateDB, state, store := stateAndStore(cfg, pubKey, 0x0)
stateStore := sm.NewStore(stateDB)
@@ -1262,12 +1298,11 @@ func TestHandshakeUpdatesValidators(t *testing.T) {
logger := log.TestingLogger()
handshaker := NewHandshaker(logger, stateStore, state, store, eventbus.NopEventBus{}, genDoc)
proxyApp := proxy.NewAppConns(clientCreator, logger, proxy.NopMetrics())
if err := proxyApp.Start(); err != nil {
if err := proxyApp.Start(ctx); err != nil {
t.Fatalf("Error starting proxy app connections: %v", err)
}
t.Cleanup(func() { require.NoError(t, proxyApp.Stop()) })
if err := handshaker.Handshake(proxyApp); err != nil {
if err := handshaker.Handshake(ctx, proxyApp); err != nil {
t.Fatalf("Error on abci handshake: %v", err)
}
// reload the state, check the validator set was updated
+20 -14
View File
@@ -329,11 +329,11 @@ func (cs *State) LoadCommit(height int64) *types.Commit {
// OnStart loads the latest state via the WAL, and starts the timeout and
// receive routines.
func (cs *State) OnStart() error {
func (cs *State) OnStart(ctx context.Context) error {
// We may set the WAL in testing before calling Start, so only OpenWAL if its
// still the nilWAL.
if _, ok := cs.wal.(nilWAL); ok {
if err := cs.loadWalFile(); err != nil {
if err := cs.loadWalFile(ctx); err != nil {
return err
}
}
@@ -384,13 +384,13 @@ func (cs *State) OnStart() error {
cs.Logger.Info("successful WAL repair")
// reload WAL file
if err := cs.loadWalFile(); err != nil {
if err := cs.loadWalFile(ctx); err != nil {
return err
}
}
}
if err := cs.evsw.Start(); err != nil {
if err := cs.evsw.Start(ctx); err != nil {
return err
}
@@ -399,7 +399,7 @@ func (cs *State) OnStart() error {
// NOTE: we will get a build up of garbage go routines
// firing on the tockChan until the receiveRoutine is started
// to deal with them (by that point, at most one will be valid)
if err := cs.timeoutTicker.Start(); err != nil {
if err := cs.timeoutTicker.Start(ctx); err != nil {
return err
}
@@ -420,8 +420,8 @@ func (cs *State) OnStart() error {
// timeoutRoutine: receive requests for timeouts on tickChan and fire timeouts on tockChan
// receiveRoutine: serializes processing of proposoals, block parts, votes; coordinates state transitions
func (cs *State) startRoutines(maxSteps int) {
err := cs.timeoutTicker.Start()
func (cs *State) startRoutines(ctx context.Context, maxSteps int) {
err := cs.timeoutTicker.Start(ctx)
if err != nil {
cs.Logger.Error("failed to start timeout ticker", "err", err)
return
@@ -431,8 +431,8 @@ func (cs *State) startRoutines(maxSteps int) {
}
// loadWalFile loads WAL data from file. It overwrites cs.wal.
func (cs *State) loadWalFile() error {
wal, err := cs.OpenWAL(cs.config.WalFile())
func (cs *State) loadWalFile(ctx context.Context) error {
wal, err := cs.OpenWAL(ctx, cs.config.WalFile())
if err != nil {
cs.Logger.Error("failed to load state WAL", "err", err)
return err
@@ -457,11 +457,15 @@ func (cs *State) OnStop() {
close(cs.onStopCh)
if err := cs.evsw.Stop(); err != nil {
cs.Logger.Error("failed trying to stop eventSwitch", "error", err)
if !errors.Is(err, service.ErrAlreadyStopped) {
cs.Logger.Error("failed trying to stop eventSwitch", "error", err)
}
}
if err := cs.timeoutTicker.Stop(); err != nil {
cs.Logger.Error("failed trying to stop timeoutTicket", "error", err)
if !errors.Is(err, service.ErrAlreadyStopped) {
cs.Logger.Error("failed trying to stop timeoutTicket", "error", err)
}
}
// WAL is stopped in receiveRoutine.
}
@@ -475,14 +479,14 @@ func (cs *State) Wait() {
// OpenWAL opens a file to log all consensus messages and timeouts for
// deterministic accountability.
func (cs *State) OpenWAL(walFile string) (WAL, error) {
func (cs *State) OpenWAL(ctx context.Context, walFile string) (WAL, error) {
wal, err := NewWAL(cs.Logger.With("wal", walFile), walFile)
if err != nil {
cs.Logger.Error("failed to open WAL", "file", walFile, "err", err)
return nil, err
}
if err := wal.Start(); err != nil {
if err := wal.Start(ctx); err != nil {
cs.Logger.Error("failed to start WAL", "err", err)
return nil, err
}
@@ -762,7 +766,9 @@ func (cs *State) receiveRoutine(maxSteps int) {
// close wal now that we're done writing to it
if err := cs.wal.Stop(); err != nil {
cs.Logger.Error("failed trying to stop WAL", "error", err)
if !errors.Is(err, service.ErrAlreadyStopped) {
cs.Logger.Error("failed trying to stop WAL", "error", err)
}
}
cs.wal.Wait()
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,6 +1,7 @@
package consensus
import (
"context"
"time"
"github.com/tendermint/tendermint/libs/log"
@@ -15,7 +16,7 @@ var (
// conditional on the height/round/step in the timeoutInfo.
// The timeoutInfo.Duration may be non-positive.
type TimeoutTicker interface {
Start() error
Start(context.Context) error
Stop() error
Chan() <-chan timeoutInfo // on which to receive a timeout
ScheduleTimeout(ti timeoutInfo) // reset the timer
@@ -47,8 +48,7 @@ func NewTimeoutTicker(logger log.Logger) TimeoutTicker {
}
// OnStart implements service.Service. It starts the timeout routine.
func (t *timeoutTicker) OnStart() error {
func (t *timeoutTicker) OnStart(gctx context.Context) error {
go t.timeoutRoutine()
return nil
@@ -29,23 +29,26 @@ func TestMain(m *testing.M) {
}
func TestPeerCatchupRounds(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
valSet, privVals := factory.RandValidatorSet(10, 1)
hvs := NewHeightVoteSet(cfg.ChainID(), 1, valSet)
vote999_0 := makeVoteHR(t, 1, 0, 999, privVals)
vote999_0 := makeVoteHR(ctx, t, 1, 0, 999, privVals)
added, err := hvs.AddVote(vote999_0, "peer1")
if !added || err != nil {
t.Error("Expected to successfully add vote from peer", added, err)
}
vote1000_0 := makeVoteHR(t, 1, 0, 1000, privVals)
vote1000_0 := makeVoteHR(ctx, t, 1, 0, 1000, privVals)
added, err = hvs.AddVote(vote1000_0, "peer1")
if !added || err != nil {
t.Error("Expected to successfully add vote from peer", added, err)
}
vote1001_0 := makeVoteHR(t, 1, 0, 1001, privVals)
vote1001_0 := makeVoteHR(ctx, t, 1, 0, 1001, privVals)
added, err = hvs.AddVote(vote1001_0, "peer1")
if err != ErrGotVoteFromUnwantedRound {
t.Errorf("expected GotVoteFromUnwantedRoundError, but got %v", err)
@@ -61,9 +64,15 @@ func TestPeerCatchupRounds(t *testing.T) {
}
func makeVoteHR(t *testing.T, height int64, valIndex, round int32, privVals []types.PrivValidator) *types.Vote {
func makeVoteHR(
ctx context.Context,
t *testing.T,
height int64,
valIndex, round int32,
privVals []types.PrivValidator,
) *types.Vote {
privVal := privVals[valIndex]
pubKey, err := privVal.GetPubKey(context.Background())
pubKey, err := privVal.GetPubKey(ctx)
if err != nil {
panic(err)
}
@@ -82,7 +91,7 @@ func makeVoteHR(t *testing.T, height int64, valIndex, round int32, privVals []ty
chainID := cfg.ChainID()
v := vote.ToProto()
err = privVal.SignVote(context.Background(), chainID, v)
err = privVal.SignVote(ctx, chainID, v)
if err != nil {
panic(fmt.Sprintf("Error signing vote: %v", err))
}
+13 -8
View File
@@ -1,6 +1,7 @@
package consensus
import (
"context"
"encoding/binary"
"errors"
"fmt"
@@ -63,7 +64,7 @@ type WAL interface {
SearchForEndHeight(height int64, options *WALSearchOptions) (rd io.ReadCloser, found bool, err error)
// service methods
Start() error
Start(context.Context) error
Stop() error
Wait()
}
@@ -116,7 +117,7 @@ func (wal *BaseWAL) Group() *auto.Group {
return wal.group
}
func (wal *BaseWAL) OnStart() error {
func (wal *BaseWAL) OnStart(ctx context.Context) error {
size, err := wal.group.Head.Size()
if err != nil {
return err
@@ -125,7 +126,7 @@ func (wal *BaseWAL) OnStart() error {
return err
}
}
err = wal.group.Start()
err = wal.group.Start(ctx)
if err != nil {
return err
}
@@ -159,10 +160,14 @@ func (wal *BaseWAL) FlushAndSync() error {
func (wal *BaseWAL) OnStop() {
wal.flushTicker.Stop()
if err := wal.FlushAndSync(); err != nil {
wal.Logger.Error("error on flush data to disk", "error", err)
if !errors.Is(err, service.ErrAlreadyStopped) {
wal.Logger.Error("error on flush data to disk", "error", err)
}
}
if err := wal.group.Stop(); err != nil {
wal.Logger.Error("error trying to stop wal", "error", err)
if !errors.Is(err, service.ErrAlreadyStopped) {
wal.Logger.Error("error trying to stop wal", "error", err)
}
}
wal.group.Close()
}
@@ -423,6 +428,6 @@ func (nilWAL) FlushAndSync() error { return nil }
func (nilWAL) SearchForEndHeight(height int64, options *WALSearchOptions) (rd io.ReadCloser, found bool, err error) {
return nil, false, nil
}
func (nilWAL) Start() error { return nil }
func (nilWAL) Stop() error { return nil }
func (nilWAL) Wait() {}
func (nilWAL) Start(context.Context) error { return nil }
func (nilWAL) Stop() error { return nil }
func (nilWAL) Wait() {}
+11 -19
View File
@@ -3,6 +3,7 @@ package consensus
import (
"bufio"
"bytes"
"context"
"fmt"
"io"
mrand "math/rand"
@@ -30,7 +31,7 @@ import (
// persistent kvstore application and special consensus wal instance
// (byteBufferWAL) and waits until numBlocks are created.
// If the node fails to produce given numBlocks, it returns an error.
func WALGenerateNBlocks(t *testing.T, wr io.Writer, numBlocks int) (err error) {
func WALGenerateNBlocks(ctx context.Context, t *testing.T, wr io.Writer, numBlocks int) (err error) {
cfg := getConfig(t)
app := kvstore.NewPersistentKVStoreApplication(filepath.Join(cfg.DBDir(), "wal_generator"))
@@ -67,24 +68,15 @@ func WALGenerateNBlocks(t *testing.T, wr io.Writer, numBlocks int) (err error) {
blockStore := store.NewBlockStore(blockStoreDB)
proxyApp := proxy.NewAppConns(abciclient.NewLocalCreator(app), logger.With("module", "proxy"), proxy.NopMetrics())
if err := proxyApp.Start(); err != nil {
if err := proxyApp.Start(ctx); err != nil {
return fmt.Errorf("failed to start proxy app connections: %w", err)
}
t.Cleanup(func() {
if err := proxyApp.Stop(); err != nil {
t.Error(err)
}
})
eventBus := eventbus.NewDefault(logger.With("module", "events"))
if err := eventBus.Start(); err != nil {
if err := eventBus.Start(ctx); err != nil {
return fmt.Errorf("failed to start event bus: %w", err)
}
t.Cleanup(func() {
if err := eventBus.Stop(); err != nil {
t.Error(err)
}
})
mempool := emptyMempool{}
evpool := sm.EmptyEvidencePool{}
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool, blockStore)
@@ -105,7 +97,7 @@ func WALGenerateNBlocks(t *testing.T, wr io.Writer, numBlocks int) (err error) {
consensusState.wal = wal
if err := consensusState.Start(); err != nil {
if err := consensusState.Start(ctx); err != nil {
return fmt.Errorf("failed to start consensus state: %w", err)
}
@@ -124,11 +116,11 @@ func WALGenerateNBlocks(t *testing.T, wr io.Writer, numBlocks int) (err error) {
}
// WALWithNBlocks returns a WAL content with numBlocks.
func WALWithNBlocks(t *testing.T, numBlocks int) (data []byte, err error) {
func WALWithNBlocks(ctx context.Context, t *testing.T, numBlocks int) (data []byte, err error) {
var b bytes.Buffer
wr := bufio.NewWriter(&b)
if err := WALGenerateNBlocks(t, wr, numBlocks); err != nil {
if err := WALGenerateNBlocks(ctx, t, wr, numBlocks); err != nil {
return []byte{}, err
}
@@ -227,6 +219,6 @@ func (w *byteBufferWAL) SearchForEndHeight(
return nil, false, nil
}
func (w *byteBufferWAL) Start() error { return nil }
func (w *byteBufferWAL) Stop() error { return nil }
func (w *byteBufferWAL) Wait() {}
func (w *byteBufferWAL) Start(context.Context) error { return nil }
func (w *byteBufferWAL) Stop() error { return nil }
func (w *byteBufferWAL) Wait() {}
+22 -25
View File
@@ -2,6 +2,7 @@ package consensus
import (
"bytes"
"context"
"path/filepath"
"testing"
@@ -18,15 +19,16 @@ import (
tmtypes "github.com/tendermint/tendermint/types"
)
const (
walTestFlushInterval = time.Duration(100) * time.Millisecond
)
const walTestFlushInterval = 100 * time.Millisecond
func TestWALTruncate(t *testing.T) {
walDir := t.TempDir()
walFile := filepath.Join(walDir, "wal")
logger := log.TestingLogger()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// this magic number 4K can truncate the content when RotateFile.
// defaultHeadSizeLimit(10M) is hard to simulate.
// this magic number 1 * time.Millisecond make RotateFile check frequently.
@@ -36,21 +38,14 @@ func TestWALTruncate(t *testing.T) {
autofile.GroupCheckDuration(1*time.Millisecond),
)
require.NoError(t, err)
err = wal.Start()
err = wal.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := wal.Stop(); err != nil {
t.Error(err)
}
// wait for the wal to finish shutting down so we
// can safely remove the directory
wal.Wait()
})
t.Cleanup(wal.Wait)
// 60 block's size nearly 70K, greater than group's headBuf size(4096 * 10),
// when headBuf is full, truncate content will Flush to the file. at this
// time, RotateFile is called, truncate content exist in each file.
err = WALGenerateNBlocks(t, wal.Group(), 60)
err = WALGenerateNBlocks(ctx, t, wal.Group(), 60)
require.NoError(t, err)
time.Sleep(1 * time.Millisecond) // wait groupCheckDuration, make sure RotateFile run
@@ -105,18 +100,14 @@ func TestWALWrite(t *testing.T) {
walDir := t.TempDir()
walFile := filepath.Join(walDir, "wal")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
wal, err := NewWAL(log.TestingLogger(), walFile)
require.NoError(t, err)
err = wal.Start()
err = wal.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := wal.Stop(); err != nil {
t.Error(err)
}
// wait for the wal to finish shutting down so we
// can safely remove the directory
wal.Wait()
})
t.Cleanup(wal.Wait)
// 1) Write returns an error if msg is too big
msg := &BlockPartMessage{
@@ -142,7 +133,10 @@ func TestWALWrite(t *testing.T) {
}
func TestWALSearchForEndHeight(t *testing.T) {
walBody, err := WALWithNBlocks(t, 6)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
walBody, err := WALWithNBlocks(ctx, t, 6)
if err != nil {
t.Fatal(err)
}
@@ -171,18 +165,21 @@ func TestWALPeriodicSync(t *testing.T) {
walFile := filepath.Join(walDir, "wal")
wal, err := NewWAL(log.TestingLogger(), walFile, autofile.GroupCheckDuration(1*time.Millisecond))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
require.NoError(t, err)
wal.SetFlushInterval(walTestFlushInterval)
// Generate some data
err = WALGenerateNBlocks(t, wal.Group(), 5)
err = WALGenerateNBlocks(ctx, t, wal.Group(), 5)
require.NoError(t, err)
// We should have data in the buffer now
assert.NotZero(t, wal.Group().Buffered())
require.NoError(t, wal.Start())
require.NoError(t, wal.Start(ctx))
t.Cleanup(func() {
if err := wal.Stop(); err != nil {
t.Error(err)
+6 -3
View File
@@ -2,6 +2,7 @@ package eventbus
import (
"context"
"errors"
"fmt"
"strings"
@@ -38,13 +39,15 @@ func NewDefault(l log.Logger) *EventBus {
return b
}
func (b *EventBus) OnStart() error {
return b.pubsub.Start()
func (b *EventBus) OnStart(ctx context.Context) error {
return b.pubsub.Start(ctx)
}
func (b *EventBus) OnStop() {
if err := b.pubsub.Stop(); err != nil {
b.pubsub.Logger.Error("error trying to stop eventBus", "error", err)
if !errors.Is(err, service.ErrAlreadyStopped) {
b.pubsub.Logger.Error("error trying to stop eventBus", "error", err)
}
}
}
+73 -77
View File
@@ -19,14 +19,12 @@ import (
)
func TestEventBusPublishEventTx(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
eventBus := eventbus.NewDefault(log.TestingLogger())
err := eventBus.Start()
err := eventBus.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := eventBus.Stop(); err != nil {
t.Error(err)
}
})
tx := types.Tx("foo")
result := abci.ResponseDeliverTx{
@@ -37,7 +35,6 @@ func TestEventBusPublishEventTx(t *testing.T) {
}
// PublishEventTx adds 3 composite keys, so the query below should work
ctx := context.Background()
query := fmt.Sprintf("tm.event='Tx' AND tx.height=1 AND tx.hash='%X' AND testType.baz=1", tx.Hash())
txsSub, err := eventBus.SubscribeWithArgs(ctx, tmpubsub.SubscribeArgs{
ClientID: "test",
@@ -76,14 +73,11 @@ func TestEventBusPublishEventTx(t *testing.T) {
}
func TestEventBusPublishEventNewBlock(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
eventBus := eventbus.NewDefault(log.TestingLogger())
err := eventBus.Start()
err := eventBus.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := eventBus.Stop(); err != nil {
t.Error(err)
}
})
block := types.MakeBlock(0, []types.Tx{}, nil, []types.Evidence{})
blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(types.BlockPartSizeBytes).Header()}
@@ -99,7 +93,6 @@ func TestEventBusPublishEventNewBlock(t *testing.T) {
}
// PublishEventNewBlock adds the tm.event compositeKey, so the query below should work
ctx := context.Background()
query := "tm.event='NewBlock' AND testType.baz=1 AND testType.foz=2"
blocksSub, err := eventBus.SubscribeWithArgs(ctx, tmpubsub.SubscribeArgs{
ClientID: "test",
@@ -136,14 +129,11 @@ func TestEventBusPublishEventNewBlock(t *testing.T) {
}
func TestEventBusPublishEventTxDuplicateKeys(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
eventBus := eventbus.NewDefault(log.TestingLogger())
err := eventBus.Start()
err := eventBus.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := eventBus.Stop(); err != nil {
t.Error(err)
}
})
tx := types.Tx("foo")
result := abci.ResponseDeliverTx{
@@ -203,54 +193,65 @@ func TestEventBusPublishEventTxDuplicateKeys(t *testing.T) {
}
for i, tc := range testCases {
ctx := context.Background()
sub, err := eventBus.SubscribeWithArgs(ctx, tmpubsub.SubscribeArgs{
ClientID: fmt.Sprintf("client-%d", i),
Query: tmquery.MustParse(tc.query),
})
require.NoError(t, err)
var name string
gotResult := make(chan bool, 1)
go func() {
defer close(gotResult)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
msg, err := sub.Next(ctx)
if err == nil {
data := msg.Data().(types.EventDataTx)
assert.Equal(t, int64(1), data.Height)
assert.Equal(t, uint32(0), data.Index)
assert.EqualValues(t, tx, data.Tx)
assert.Equal(t, result, data.Result)
gotResult <- true
}
}()
assert.NoError(t, eventBus.PublishEventTx(types.EventDataTx{
TxResult: abci.TxResult{
Height: 1,
Index: 0,
Tx: tx,
Result: result,
},
}))
if got := <-gotResult; got != tc.expectResults {
require.Failf(t, "Wrong transaction result",
"got a tx: %v, wanted a tx: %v", got, tc.expectResults)
if tc.expectResults {
name = fmt.Sprintf("ExpetedResultsCase%d", i)
} else {
name = fmt.Sprintf("NoResultsCase%d", i)
}
t.Run(name, func(t *testing.T) {
sub, err := eventBus.SubscribeWithArgs(ctx, tmpubsub.SubscribeArgs{
ClientID: fmt.Sprintf("client-%d", i),
Query: tmquery.MustParse(tc.query),
})
require.NoError(t, err)
gotResult := make(chan bool, 1)
go func() {
defer close(gotResult)
tctx, cancel := context.WithTimeout(ctx, 1*time.Second)
defer cancel()
msg, err := sub.Next(tctx)
if err == nil {
data := msg.Data().(types.EventDataTx)
assert.Equal(t, int64(1), data.Height)
assert.Equal(t, uint32(0), data.Index)
assert.EqualValues(t, tx, data.Tx)
assert.Equal(t, result, data.Result)
gotResult <- true
}
}()
assert.NoError(t, eventBus.PublishEventTx(types.EventDataTx{
TxResult: abci.TxResult{
Height: 1,
Index: 0,
Tx: tx,
Result: result,
},
}))
require.NoError(t, ctx.Err(), "context should not have been canceled")
if got := <-gotResult; got != tc.expectResults {
require.Failf(t, "Wrong transaction result",
"got a tx: %v, wanted a tx: %v", got, tc.expectResults)
}
})
}
}
func TestEventBusPublishEventNewBlockHeader(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
eventBus := eventbus.NewDefault(log.TestingLogger())
err := eventBus.Start()
err := eventBus.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := eventBus.Stop(); err != nil {
t.Error(err)
}
})
block := types.MakeBlock(0, []types.Tx{}, nil, []types.Evidence{})
resultBeginBlock := abci.ResponseBeginBlock{
@@ -265,7 +266,6 @@ func TestEventBusPublishEventNewBlockHeader(t *testing.T) {
}
// PublishEventNewBlockHeader adds the tm.event compositeKey, so the query below should work
ctx := context.Background()
query := "tm.event='NewBlockHeader' AND testType.baz=1 AND testType.foz=2"
headersSub, err := eventBus.SubscribeWithArgs(ctx, tmpubsub.SubscribeArgs{
ClientID: "test",
@@ -300,18 +300,15 @@ func TestEventBusPublishEventNewBlockHeader(t *testing.T) {
}
func TestEventBusPublishEventNewEvidence(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
eventBus := eventbus.NewDefault(log.TestingLogger())
err := eventBus.Start()
err := eventBus.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := eventBus.Stop(); err != nil {
t.Error(err)
}
})
ev := types.NewMockDuplicateVoteEvidence(1, time.Now(), "test-chain-id")
ctx := context.Background()
const query = `tm.event='NewEvidence'`
evSub, err := eventBus.SubscribeWithArgs(ctx, tmpubsub.SubscribeArgs{
ClientID: "test",
@@ -344,18 +341,15 @@ func TestEventBusPublishEventNewEvidence(t *testing.T) {
}
func TestEventBusPublish(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
eventBus := eventbus.NewDefault(log.TestingLogger())
err := eventBus.Start()
err := eventBus.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := eventBus.Stop(); err != nil {
t.Error(err)
}
})
const numEventsExpected = 14
ctx := context.Background()
sub, err := eventBus.SubscribeWithArgs(ctx, tmpubsub.SubscribeArgs{
ClientID: "test",
Query: tmquery.Empty{},
@@ -434,8 +428,11 @@ func benchmarkEventBus(numClients int, randQueries bool, randEvents bool, b *tes
// for random* functions
mrand.Seed(time.Now().Unix())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
eventBus := eventbus.NewDefault(log.TestingLogger()) // set buffer capacity to 0 so we are not testing cache
err := eventBus.Start()
err := eventBus.Start(ctx)
if err != nil {
b.Error(err)
}
@@ -445,7 +442,6 @@ func benchmarkEventBus(numClients int, randQueries bool, randEvents bool, b *tes
}
})
ctx := context.Background()
q := types.EventQueryNewBlock
for i := 0; i < numClients; i++ {
+2 -1
View File
@@ -1,6 +1,7 @@
package evidence
import (
"context"
"fmt"
"runtime/debug"
"sync"
@@ -81,7 +82,7 @@ func NewReactor(
// envelopes on each. In addition, it also listens for peer updates and handles
// messages on that p2p channel accordingly. The caller must be sure to execute
// OnStop to ensure the outbound p2p Channels are closed. No error is returned.
func (r *Reactor) OnStart() error {
func (r *Reactor) OnStart(ctx context.Context) error {
go r.processEvidenceCh()
go r.processPeerUpdates()
+28 -9
View File
@@ -1,6 +1,7 @@
package evidence_test
import (
"context"
"encoding/hex"
"math/rand"
"sync"
@@ -44,7 +45,7 @@ type reactorTestSuite struct {
numStateStores int
}
func setup(t *testing.T, stateStores []sm.Store, chBuf uint) *reactorTestSuite {
func setup(ctx context.Context, t *testing.T, stateStores []sm.Store, chBuf uint) *reactorTestSuite {
t.Helper()
pID := make([]byte, 16)
@@ -55,7 +56,7 @@ func setup(t *testing.T, stateStores []sm.Store, chBuf uint) *reactorTestSuite {
rts := &reactorTestSuite{
numStateStores: numStateStores,
logger: log.TestingLogger().With("testCase", t.Name()),
network: p2ptest.MakeNetwork(t, p2ptest.NetworkOptions{NumNodes: numStateStores}),
network: p2ptest.MakeNetwork(ctx, t, p2ptest.NetworkOptions{NumNodes: numStateStores}),
reactors: make(map[types.NodeID]*evidence.Reactor, numStateStores),
pools: make(map[types.NodeID]*evidence.Pool, numStateStores),
peerUpdates: make(map[types.NodeID]*p2p.PeerUpdates, numStateStores),
@@ -93,7 +94,7 @@ func setup(t *testing.T, stateStores []sm.Store, chBuf uint) *reactorTestSuite {
rts.peerUpdates[nodeID],
rts.pools[nodeID])
require.NoError(t, rts.reactors[nodeID].Start())
require.NoError(t, rts.reactors[nodeID].Start(ctx))
require.True(t, rts.reactors[nodeID].IsRunning())
idx++
@@ -233,13 +234,16 @@ func createEvidenceList(
}
func TestReactorMultiDisconnect(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
val := types.NewMockPV()
height := int64(numEvidence) + 10
stateDB1 := initializeValidatorState(t, val, height)
stateDB2 := initializeValidatorState(t, val, height)
rts := setup(t, []sm.Store{stateDB1, stateDB2}, 20)
rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}, 20)
primary := rts.nodes[0]
secondary := rts.nodes[1]
@@ -281,7 +285,10 @@ func TestReactorBroadcastEvidence(t *testing.T) {
stateDBs[i] = initializeValidatorState(t, val, height)
}
rts := setup(t, stateDBs, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, stateDBs, 0)
rts.start(t)
// Create a series of fixtures where each suite contains a reactor and
@@ -335,7 +342,10 @@ func TestReactorBroadcastEvidence_Lagging(t *testing.T) {
stateDB1 := initializeValidatorState(t, val, height1)
stateDB2 := initializeValidatorState(t, val, height2)
rts := setup(t, []sm.Store{stateDB1, stateDB2}, 100)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}, 100)
rts.start(t)
primary := rts.nodes[0]
@@ -368,7 +378,10 @@ func TestReactorBroadcastEvidence_Pending(t *testing.T) {
stateDB1 := initializeValidatorState(t, val, height)
stateDB2 := initializeValidatorState(t, val, height)
rts := setup(t, []sm.Store{stateDB1, stateDB2}, 100)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}, 100)
primary := rts.nodes[0]
secondary := rts.nodes[1]
@@ -405,7 +418,10 @@ func TestReactorBroadcastEvidence_Committed(t *testing.T) {
stateDB1 := initializeValidatorState(t, val, height)
stateDB2 := initializeValidatorState(t, val, height)
rts := setup(t, []sm.Store{stateDB1, stateDB2}, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, []sm.Store{stateDB1, stateDB2}, 0)
primary := rts.nodes[0]
secondary := rts.nodes[1]
@@ -460,7 +476,10 @@ func TestReactorBroadcastEvidence_FullyConnected(t *testing.T) {
stateDBs[i] = initializeValidatorState(t, val, height)
}
rts := setup(t, stateDBs, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, stateDBs, 0)
rts.start(t)
evList := createEvidenceList(t, rts.pools[rts.network.RandomNode().NodeID], val, numEvidence)
+6 -14
View File
@@ -85,26 +85,18 @@ func NewFromConfig(logger log.Logger, cfg *config.Config) (*Inspector, error) {
// Run starts the Inspector servers and blocks until the servers shut down. The passed
// in context is used to control the lifecycle of the servers.
func (ins *Inspector) Run(ctx context.Context) error {
err := ins.eventBus.Start()
err := ins.eventBus.Start(ctx)
if err != nil {
return fmt.Errorf("error starting event bus: %s", err)
}
defer func() {
err := ins.eventBus.Stop()
if err != nil {
ins.logger.Error("event bus stopped with error", "err", err)
}
}()
err = ins.indexerService.Start()
defer ins.eventBus.Wait()
err = ins.indexerService.Start(ctx)
if err != nil {
return fmt.Errorf("error starting indexer service: %s", err)
}
defer func() {
err := ins.indexerService.Stop()
if err != nil {
ins.logger.Error("indexer service stopped with error", "err", err)
}
}()
defer ins.indexerService.Wait()
return startRPCServers(ctx, ins.config, ins.logger, ins.routes)
}
+10 -10
View File
@@ -101,7 +101,7 @@ func TestBlock(t *testing.T) {
requireConnect(t, rpcConfig.ListenAddress, 20)
cli, err := httpclient.New(rpcConfig.ListenAddress)
require.NoError(t, err)
resultBlock, err := cli.Block(context.Background(), &testHeight)
resultBlock, err := cli.Block(ctx, &testHeight)
require.NoError(t, err)
require.Equal(t, testBlock.Height, resultBlock.Block.Height)
require.Equal(t, testBlock.LastCommitHash, resultBlock.Block.LastCommitHash)
@@ -153,7 +153,7 @@ func TestTxSearch(t *testing.T) {
require.NoError(t, err)
var page = 1
resultTxSearch, err := cli.TxSearch(context.Background(), testQuery, false, &page, &page, "")
resultTxSearch, err := cli.TxSearch(ctx, testQuery, false, &page, &page, "")
require.NoError(t, err)
require.Len(t, resultTxSearch.Txs, 1)
require.Equal(t, types.Tx(testTx), resultTxSearch.Txs[0].Tx)
@@ -199,7 +199,7 @@ func TestTx(t *testing.T) {
cli, err := httpclient.New(rpcConfig.ListenAddress)
require.NoError(t, err)
res, err := cli.Tx(context.Background(), testHash, false)
res, err := cli.Tx(ctx, testHash, false)
require.NoError(t, err)
require.Equal(t, types.Tx(testTx), res.Tx)
@@ -247,7 +247,7 @@ func TestConsensusParams(t *testing.T) {
requireConnect(t, rpcConfig.ListenAddress, 20)
cli, err := httpclient.New(rpcConfig.ListenAddress)
require.NoError(t, err)
params, err := cli.ConsensusParams(context.Background(), &testHeight)
params, err := cli.ConsensusParams(ctx, &testHeight)
require.NoError(t, err)
require.Equal(t, params.ConsensusParams.Block.MaxGas, testMaxGas)
@@ -300,7 +300,7 @@ func TestBlockResults(t *testing.T) {
requireConnect(t, rpcConfig.ListenAddress, 20)
cli, err := httpclient.New(rpcConfig.ListenAddress)
require.NoError(t, err)
res, err := cli.BlockResults(context.Background(), &testHeight)
res, err := cli.BlockResults(ctx, &testHeight)
require.NoError(t, err)
require.Equal(t, res.TotalGasUsed, testGasUsed)
@@ -348,7 +348,7 @@ func TestCommit(t *testing.T) {
requireConnect(t, rpcConfig.ListenAddress, 20)
cli, err := httpclient.New(rpcConfig.ListenAddress)
require.NoError(t, err)
res, err := cli.Commit(context.Background(), &testHeight)
res, err := cli.Commit(ctx, &testHeight)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, res.SignedHeader.Commit.Round, testRound)
@@ -402,7 +402,7 @@ func TestBlockByHash(t *testing.T) {
requireConnect(t, rpcConfig.ListenAddress, 20)
cli, err := httpclient.New(rpcConfig.ListenAddress)
require.NoError(t, err)
res, err := cli.BlockByHash(context.Background(), testHash)
res, err := cli.BlockByHash(ctx, testHash)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, []byte(res.BlockID.Hash), testHash)
@@ -455,7 +455,7 @@ func TestBlockchain(t *testing.T) {
requireConnect(t, rpcConfig.ListenAddress, 20)
cli, err := httpclient.New(rpcConfig.ListenAddress)
require.NoError(t, err)
res, err := cli.BlockchainInfo(context.Background(), 0, 100)
res, err := cli.BlockchainInfo(ctx, 0, 100)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, testBlockHash, []byte(res.BlockMetas[0].BlockID.Hash))
@@ -511,7 +511,7 @@ func TestValidators(t *testing.T) {
testPage := 1
testPerPage := 100
res, err := cli.Validators(context.Background(), &testHeight, &testPage, &testPerPage)
res, err := cli.Validators(ctx, &testHeight, &testPage, &testPerPage)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, testVotingPower, res.Validators[0].VotingPower)
@@ -571,7 +571,7 @@ func TestBlockSearch(t *testing.T) {
testPage := 1
testPerPage := 100
testOrderBy := "desc"
res, err := cli.BlockSearch(context.Background(), testQuery, &testPage, &testPerPage, testOrderBy)
res, err := cli.BlockSearch(ctx, testQuery, &testPage, &testPerPage, testOrderBy)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, testBlockHash, []byte(res.Blocks[0].BlockID.Hash))
+7 -16
View File
@@ -1,15 +1,17 @@
package main
import (
"context"
"flag"
"fmt"
"io"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
auto "github.com/tendermint/tendermint/internal/libs/autofile"
tmos "github.com/tendermint/tendermint/libs/os"
)
const Version = "0.0.1"
@@ -32,21 +34,10 @@ func parseFlags() (headPath string, chopSize int64, limitSize int64, version boo
return
}
type fmtLogger struct{}
func (fmtLogger) Info(msg string, keyvals ...interface{}) {
strs := make([]string, len(keyvals))
for i, kv := range keyvals {
strs[i] = fmt.Sprintf("%v", kv)
}
fmt.Printf("%s %s\n", msg, strings.Join(strs, ","))
}
func main() {
// Stop upon receiving SIGTERM or CTRL-C.
tmos.TrapSignal(fmtLogger{}, func() {
fmt.Println("logjack shutting down")
})
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM)
defer cancel()
defer func() { fmt.Println("logjack shutting down") }()
// Read options
headPath, chopSize, limitSize, version := parseFlags()
@@ -62,7 +53,7 @@ func main() {
os.Exit(1)
}
if err = group.Start(); err != nil {
if err = group.Start(ctx); err != nil {
fmt.Printf("logjack couldn't start with file %v\n", headPath)
os.Exit(1)
}
+2 -1
View File
@@ -2,6 +2,7 @@ package autofile
import (
"bufio"
"context"
"errors"
"fmt"
"io"
@@ -135,7 +136,7 @@ func GroupTotalSizeLimit(limit int64) func(*Group) {
// OnStart implements service.Service by starting the goroutine that checks file
// and group limits.
func (g *Group) OnStart() error {
func (g *Group) OnStart(ctx context.Context) error {
g.ticker = time.NewTicker(g.groupCheckDuration)
go g.processTicks()
return nil
+4 -1
View File
@@ -11,7 +11,10 @@ import (
)
func BenchmarkTxMempool_CheckTx(b *testing.B) {
txmp := setup(b, 10000)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
txmp := setup(ctx, b, 10000)
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
b.ResetTimer()
+55 -15
View File
@@ -72,9 +72,12 @@ func (app *application) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx {
}
}
func setup(t testing.TB, cacheSize int, options ...TxMempoolOption) *TxMempool {
func setup(ctx context.Context, t testing.TB, cacheSize int, options ...TxMempoolOption) *TxMempool {
t.Helper()
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
app := &application{kvstore.NewApplication()}
cc := abciclient.NewLocalCreator(app)
logger := log.TestingLogger()
@@ -84,11 +87,12 @@ func setup(t testing.TB, cacheSize int, options ...TxMempoolOption) *TxMempool {
cfg.Mempool.CacheSize = cacheSize
appConnMem, err := cc(logger)
require.NoError(t, err)
require.NoError(t, appConnMem.Start())
require.NoError(t, appConnMem.Start(ctx))
t.Cleanup(func() {
os.RemoveAll(cfg.RootDir)
require.NoError(t, appConnMem.Stop())
cancel()
appConnMem.Wait()
})
return NewTxMempool(logger.With("test", t.Name()), cfg.Mempool, appConnMem, 0, options...)
@@ -128,7 +132,10 @@ func convertTex(in []testTx) types.Txs {
}
func TestTxMempool_TxsAvailable(t *testing.T) {
txmp := setup(t, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
txmp := setup(ctx, t, 0)
txmp.EnableTxsAvailable()
ensureNoTxFire := func() {
@@ -182,7 +189,10 @@ func TestTxMempool_TxsAvailable(t *testing.T) {
}
func TestTxMempool_Size(t *testing.T) {
txmp := setup(t, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
txmp := setup(ctx, t, 0)
txs := checkTxs(t, txmp, 100, 0)
require.Equal(t, len(txs), txmp.Size())
require.Equal(t, int64(5690), txmp.SizeBytes())
@@ -206,7 +216,10 @@ func TestTxMempool_Size(t *testing.T) {
}
func TestTxMempool_Flush(t *testing.T) {
txmp := setup(t, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
txmp := setup(ctx, t, 0)
txs := checkTxs(t, txmp, 100, 0)
require.Equal(t, len(txs), txmp.Size())
require.Equal(t, int64(5690), txmp.SizeBytes())
@@ -231,7 +244,10 @@ func TestTxMempool_Flush(t *testing.T) {
}
func TestTxMempool_ReapMaxBytesMaxGas(t *testing.T) {
txmp := setup(t, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
txmp := setup(ctx, t, 0)
tTxs := checkTxs(t, txmp, 100, 0) // all txs request 1 gas unit
require.Equal(t, len(tTxs), txmp.Size())
require.Equal(t, int64(5690), txmp.SizeBytes())
@@ -281,7 +297,10 @@ func TestTxMempool_ReapMaxBytesMaxGas(t *testing.T) {
}
func TestTxMempool_ReapMaxTxs(t *testing.T) {
txmp := setup(t, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
txmp := setup(ctx, t, 0)
tTxs := checkTxs(t, txmp, 100, 0)
require.Equal(t, len(tTxs), txmp.Size())
require.Equal(t, int64(5690), txmp.SizeBytes())
@@ -330,7 +349,10 @@ func TestTxMempool_ReapMaxTxs(t *testing.T) {
}
func TestTxMempool_CheckTxExceedsMaxSize(t *testing.T) {
txmp := setup(t, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
txmp := setup(ctx, t, 0)
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
tx := make([]byte, txmp.config.MaxTxBytes+1)
@@ -347,7 +369,10 @@ func TestTxMempool_CheckTxExceedsMaxSize(t *testing.T) {
}
func TestTxMempool_CheckTxSamePeer(t *testing.T) {
txmp := setup(t, 100)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
txmp := setup(ctx, t, 100)
peerID := uint16(1)
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
@@ -362,7 +387,10 @@ func TestTxMempool_CheckTxSamePeer(t *testing.T) {
}
func TestTxMempool_CheckTxSameSender(t *testing.T) {
txmp := setup(t, 100)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
txmp := setup(ctx, t, 100)
peerID := uint16(1)
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
@@ -384,7 +412,10 @@ func TestTxMempool_CheckTxSameSender(t *testing.T) {
}
func TestTxMempool_ConcurrentTxs(t *testing.T) {
txmp := setup(t, 100)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
txmp := setup(ctx, t, 100)
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
checkTxDone := make(chan struct{})
@@ -448,7 +479,10 @@ func TestTxMempool_ConcurrentTxs(t *testing.T) {
}
func TestTxMempool_ExpiredTxs_NumBlocks(t *testing.T) {
txmp := setup(t, 500)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
txmp := setup(ctx, t, 500)
txmp.height = 100
txmp.config.TTLNumBlocks = 10
@@ -498,6 +532,9 @@ func TestTxMempool_ExpiredTxs_NumBlocks(t *testing.T) {
}
func TestTxMempool_CheckTxPostCheckError(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cases := []struct {
name string
err error
@@ -514,10 +551,13 @@ func TestTxMempool_CheckTxPostCheckError(t *testing.T) {
for _, tc := range cases {
testCase := tc
t.Run(testCase.name, func(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
postCheckFn := func(_ types.Tx, _ *abci.ResponseCheckTx) error {
return testCase.err
}
txmp := setup(t, 0, WithPostCheck(postCheckFn))
txmp := setup(ctx, t, 0, WithPostCheck(postCheckFn))
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
tx := make([]byte, txmp.config.MaxTxBytes-1)
_, err := rng.Read(tx)
@@ -532,7 +572,7 @@ func TestTxMempool_CheckTxPostCheckError(t *testing.T) {
}
require.Equal(t, expectedErrString, checkTxRes.CheckTx.MempoolError)
}
require.NoError(t, txmp.CheckTx(context.Background(), tx, callback, TxInfo{SenderID: 0}))
require.NoError(t, txmp.CheckTx(ctx, tx, callback, TxInfo{SenderID: 0}))
})
}
}
+1 -1
View File
@@ -112,7 +112,7 @@ func GetChannelDescriptor(cfg *config.MempoolConfig) *p2p.ChannelDescriptor {
// envelopes on each. In addition, it also listens for peer updates and handles
// messages on that p2p channel accordingly. The caller must be sure to execute
// OnStop to ensure the outbound p2p Channels are closed.
func (r *Reactor) OnStart() error {
func (r *Reactor) OnStart(ctx context.Context) error {
if !r.cfg.Broadcast {
r.Logger.Info("tx broadcasting is disabled")
}
+35 -14
View File
@@ -36,7 +36,7 @@ type reactorTestSuite struct {
nodes []types.NodeID
}
func setupReactors(t *testing.T, numNodes int, chBuf uint) *reactorTestSuite {
func setupReactors(ctx context.Context, t *testing.T, numNodes int, chBuf uint) *reactorTestSuite {
t.Helper()
cfg, err := config.ResetTestRoot(strings.ReplaceAll(t.Name(), "/", "|"))
@@ -45,7 +45,7 @@ func setupReactors(t *testing.T, numNodes int, chBuf uint) *reactorTestSuite {
rts := &reactorTestSuite{
logger: log.TestingLogger().With("testCase", t.Name()),
network: p2ptest.MakeNetwork(t, p2ptest.NetworkOptions{NumNodes: numNodes}),
network: p2ptest.MakeNetwork(ctx, t, p2ptest.NetworkOptions{NumNodes: numNodes}),
reactors: make(map[types.NodeID]*Reactor, numNodes),
mempoolChannels: make(map[types.NodeID]*p2p.Channel, numNodes),
mempools: make(map[types.NodeID]*TxMempool, numNodes),
@@ -60,7 +60,7 @@ func setupReactors(t *testing.T, numNodes int, chBuf uint) *reactorTestSuite {
for nodeID := range rts.network.Nodes {
rts.kvstores[nodeID] = kvstore.NewApplication()
mempool := setup(t, 0)
mempool := setup(ctx, t, 0)
rts.mempools[nodeID] = mempool
rts.peerChans[nodeID] = make(chan p2p.PeerUpdate)
@@ -78,7 +78,7 @@ func setupReactors(t *testing.T, numNodes int, chBuf uint) *reactorTestSuite {
rts.nodes = append(rts.nodes, nodeID)
require.NoError(t, rts.reactors[nodeID].Start())
require.NoError(t, rts.reactors[nodeID].Start(ctx))
require.True(t, rts.reactors[nodeID].IsRunning())
}
@@ -147,8 +147,11 @@ func (rts *reactorTestSuite) waitForTxns(t *testing.T, txs []types.Tx, ids ...ty
}
func TestReactorBroadcastDoesNotPanic(t *testing.T) {
numNodes := 2
rts := setupReactors(t, numNodes, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
const numNodes = 2
rts := setupReactors(ctx, t, numNodes, 0)
observePanic := func(r interface{}) {
t.Fatal("panic detected in reactor")
@@ -192,8 +195,10 @@ func TestReactorBroadcastDoesNotPanic(t *testing.T) {
func TestReactorBroadcastTxs(t *testing.T) {
numTxs := 1000
numNodes := 10
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setupReactors(t, numNodes, 0)
rts := setupReactors(ctx, t, numNodes, 0)
primary := rts.nodes[0]
secondaries := rts.nodes[1:]
@@ -215,7 +220,10 @@ func TestReactorConcurrency(t *testing.T) {
numTxs := 5
numNodes := 2
rts := setupReactors(t, numNodes, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setupReactors(ctx, t, numNodes, 0)
primary := rts.nodes[0]
secondary := rts.nodes[1]
@@ -273,7 +281,10 @@ func TestReactorNoBroadcastToSender(t *testing.T) {
numTxs := 1000
numNodes := 2
rts := setupReactors(t, numNodes, uint(numTxs))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setupReactors(ctx, t, numNodes, uint(numTxs))
primary := rts.nodes[0]
secondary := rts.nodes[1]
@@ -296,7 +307,10 @@ func TestReactor_MaxTxBytes(t *testing.T) {
numNodes := 2
cfg := config.TestConfig()
rts := setupReactors(t, numNodes, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setupReactors(ctx, t, numNodes, 0)
primary := rts.nodes[0]
secondary := rts.nodes[1]
@@ -305,7 +319,7 @@ func TestReactor_MaxTxBytes(t *testing.T) {
// second reactor.
tx1 := tmrand.Bytes(cfg.Mempool.MaxTxBytes)
err := rts.reactors[primary].mempool.CheckTx(
context.Background(),
ctx,
tx1,
nil,
TxInfo{
@@ -321,7 +335,7 @@ func TestReactor_MaxTxBytes(t *testing.T) {
// broadcast a tx, which is beyond the max size and ensure it's not sent
tx2 := tmrand.Bytes(cfg.Mempool.MaxTxBytes + 1)
err = rts.mempools[primary].CheckTx(context.Background(), tx2, nil, TxInfo{SenderID: UnknownPeerID})
err = rts.mempools[primary].CheckTx(ctx, tx2, nil, TxInfo{SenderID: UnknownPeerID})
require.Error(t, err)
rts.assertMempoolChannelsDrained(t)
@@ -330,7 +344,11 @@ func TestReactor_MaxTxBytes(t *testing.T) {
func TestDontExhaustMaxActiveIDs(t *testing.T) {
// we're creating a single node network, but not starting the
// network.
rts := setupReactors(t, 1, MaxActiveIDs+1)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setupReactors(ctx, t, 1, MaxActiveIDs+1)
nodeID := rts.nodes[0]
@@ -395,7 +413,10 @@ func TestBroadcastTxForPeerStopsWhenPeerStops(t *testing.T) {
t.Skip("skipping test in short mode")
}
rts := setupReactors(t, 2, 0)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setupReactors(ctx, t, 2, 0)
primary := rts.nodes[0]
secondary := rts.nodes[1]
+7
View File
@@ -1,6 +1,7 @@
package p2p_test
import (
"context"
"net"
"strings"
"testing"
@@ -204,6 +205,9 @@ func TestParseNodeAddress(t *testing.T) {
func TestNodeAddress_Resolve(t *testing.T) {
id := types.NodeID("00112233445566778899aabbccddeeff00112233")
bctx, bcancel := context.WithCancel(context.Background())
defer bcancel()
testcases := []struct {
address p2p.NodeAddress
expect p2p.Endpoint
@@ -275,6 +279,9 @@ func TestNodeAddress_Resolve(t *testing.T) {
for _, tc := range testcases {
tc := tc
t.Run(tc.address.String(), func(t *testing.T) {
ctx, cancel := context.WithCancel(bctx)
defer cancel()
endpoints, err := tc.address.Resolve(ctx)
if !tc.ok {
require.Error(t, err)
+3 -2
View File
@@ -2,6 +2,7 @@ package conn
import (
"bufio"
"context"
"errors"
"fmt"
"io"
@@ -209,8 +210,8 @@ func NewMConnectionWithConfig(
}
// OnStart implements BaseService
func (c *MConnection) OnStart() error {
if err := c.BaseService.OnStart(); err != nil {
func (c *MConnection) OnStart(ctx context.Context) error {
if err := c.BaseService.OnStart(ctx); err != nil {
return err
}
c.flushTimer = timer.NewThrottleTimer("flush", c.config.FlushThrottle)
+69 -18
View File
@@ -1,6 +1,7 @@
package conn
import (
"context"
"encoding/hex"
"net"
"testing"
@@ -47,8 +48,11 @@ func TestMConnectionSendFlushStop(t *testing.T) {
server, client := NetPipe()
t.Cleanup(closeAll(t, client, server))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
clientConn := createTestMConnection(log.TestingLogger(), client)
err := clientConn.Start()
err := clientConn.Start(ctx)
require.Nil(t, err)
t.Cleanup(stopAll(t, clientConn))
@@ -81,8 +85,11 @@ func TestMConnectionSend(t *testing.T) {
server, client := NetPipe()
t.Cleanup(closeAll(t, client, server))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mconn := createTestMConnection(log.TestingLogger(), client)
err := mconn.Start()
err := mconn.Start(ctx)
require.Nil(t, err)
t.Cleanup(stopAll(t, mconn))
@@ -118,13 +125,17 @@ func TestMConnectionReceive(t *testing.T) {
errorsCh <- r
}
logger := log.TestingLogger()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mconn1 := createMConnectionWithCallbacks(logger, client, onReceive, onError)
err := mconn1.Start()
err := mconn1.Start(ctx)
require.Nil(t, err)
t.Cleanup(stopAll(t, mconn1))
mconn2 := createTestMConnection(logger, server)
err = mconn2.Start()
err = mconn2.Start(ctx)
require.Nil(t, err)
t.Cleanup(stopAll(t, mconn2))
@@ -153,8 +164,12 @@ func TestMConnectionPongTimeoutResultsInError(t *testing.T) {
onError := func(r interface{}) {
errorsCh <- r
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mconn := createMConnectionWithCallbacks(log.TestingLogger(), client, onReceive, onError)
err := mconn.Start()
err := mconn.Start(ctx)
require.Nil(t, err)
t.Cleanup(stopAll(t, mconn))
@@ -191,8 +206,11 @@ func TestMConnectionMultiplePongsInTheBeginning(t *testing.T) {
onError := func(r interface{}) {
errorsCh <- r
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mconn := createMConnectionWithCallbacks(log.TestingLogger(), client, onReceive, onError)
err := mconn.Start()
err := mconn.Start(ctx)
require.Nil(t, err)
t.Cleanup(stopAll(t, mconn))
@@ -245,8 +263,11 @@ func TestMConnectionMultiplePings(t *testing.T) {
onError := func(r interface{}) {
errorsCh <- r
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mconn := createMConnectionWithCallbacks(log.TestingLogger(), client, onReceive, onError)
err := mconn.Start()
err := mconn.Start(ctx)
require.Nil(t, err)
t.Cleanup(stopAll(t, mconn))
@@ -292,8 +313,12 @@ func TestMConnectionPingPongs(t *testing.T) {
onError := func(r interface{}) {
errorsCh <- r
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mconn := createMConnectionWithCallbacks(log.TestingLogger(), client, onReceive, onError)
err := mconn.Start()
err := mconn.Start(ctx)
require.Nil(t, err)
t.Cleanup(stopAll(t, mconn))
@@ -349,8 +374,11 @@ func TestMConnectionStopsAndReturnsError(t *testing.T) {
onError := func(r interface{}) {
errorsCh <- r
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mconn := createMConnectionWithCallbacks(log.TestingLogger(), client, onReceive, onError)
err := mconn.Start()
err := mconn.Start(ctx)
require.Nil(t, err)
t.Cleanup(stopAll(t, mconn))
@@ -369,7 +397,11 @@ func TestMConnectionStopsAndReturnsError(t *testing.T) {
}
}
func newClientAndServerConnsForReadErrors(t *testing.T, chOnErr chan struct{}) (*MConnection, *MConnection) {
func newClientAndServerConnsForReadErrors(
ctx context.Context,
t *testing.T,
chOnErr chan struct{},
) (*MConnection, *MConnection) {
server, client := NetPipe()
onReceive := func(chID ChannelID, msgBytes []byte) {}
@@ -381,8 +413,9 @@ func newClientAndServerConnsForReadErrors(t *testing.T, chOnErr chan struct{}) (
{ID: 0x02, Priority: 1, SendQueueCapacity: 1},
}
logger := log.TestingLogger()
mconnClient := NewMConnection(logger.With("module", "client"), client, chDescs, onReceive, onError)
err := mconnClient.Start()
err := mconnClient.Start(ctx)
require.Nil(t, err)
// create server conn with 1 channel
@@ -391,8 +424,9 @@ func newClientAndServerConnsForReadErrors(t *testing.T, chOnErr chan struct{}) (
onError = func(r interface{}) {
chOnErr <- struct{}{}
}
mconnServer := createMConnectionWithCallbacks(serverLogger, server, onReceive, onError)
err = mconnServer.Start()
err = mconnServer.Start(ctx)
require.Nil(t, err)
return mconnClient, mconnServer
}
@@ -408,8 +442,11 @@ func expectSend(ch chan struct{}) bool {
}
func TestMConnectionReadErrorBadEncoding(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
chOnErr := make(chan struct{})
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(ctx, t, chOnErr)
client := mconnClient.conn
@@ -421,8 +458,11 @@ func TestMConnectionReadErrorBadEncoding(t *testing.T) {
}
func TestMConnectionReadErrorUnknownChannel(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
chOnErr := make(chan struct{})
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(ctx, t, chOnErr)
msg := []byte("Ant-Man")
@@ -440,7 +480,10 @@ func TestMConnectionReadErrorLongMessage(t *testing.T) {
chOnErr := make(chan struct{})
chOnRcv := make(chan struct{})
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(ctx, t, chOnErr)
t.Cleanup(stopAll(t, mconnClient, mconnServer))
mconnServer.onReceive = func(chID ChannelID, msgBytes []byte) {
@@ -474,8 +517,11 @@ func TestMConnectionReadErrorLongMessage(t *testing.T) {
}
func TestMConnectionReadErrorUnknownMsgType(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
chOnErr := make(chan struct{})
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(ctx, t, chOnErr)
t.Cleanup(stopAll(t, mconnClient, mconnServer))
// send msg with unknown msg type
@@ -487,9 +533,11 @@ func TestMConnectionReadErrorUnknownMsgType(t *testing.T) {
func TestMConnectionTrySend(t *testing.T) {
server, client := NetPipe()
t.Cleanup(closeAll(t, client, server))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mconn := createTestMConnection(log.TestingLogger(), client)
err := mconn.Start()
err := mconn.Start(ctx)
require.Nil(t, err)
t.Cleanup(stopAll(t, mconn))
@@ -535,7 +583,10 @@ func TestMConnectionChannelOverflow(t *testing.T) {
chOnErr := make(chan struct{})
chOnRcv := make(chan struct{})
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(ctx, t, chOnErr)
t.Cleanup(stopAll(t, mconnClient, mconnServer))
mconnServer.onReceive = func(chID ChannelID, msgBytes []byte) {
-3
View File
@@ -1,8 +1,6 @@
package p2p_test
import (
"context"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/internal/p2p"
@@ -13,7 +11,6 @@ import (
// Common setup for P2P tests.
var (
ctx = context.Background()
chID = p2p.ChannelID(1)
chDesc = &p2p.ChannelDescriptor{
ID: chID,
+7 -6
View File
@@ -47,7 +47,7 @@ func (opts *NetworkOptions) setDefaults() {
// MakeNetwork creates a test network with the given number of nodes and
// connects them to each other.
func MakeNetwork(t *testing.T, opts NetworkOptions) *Network {
func MakeNetwork(ctx context.Context, t *testing.T, opts NetworkOptions) *Network {
opts.setDefaults()
logger := log.TestingLogger()
network := &Network{
@@ -57,7 +57,7 @@ func MakeNetwork(t *testing.T, opts NetworkOptions) *Network {
}
for i := 0; i < opts.NumNodes; i++ {
node := network.MakeNode(t, opts.NodeOpts)
node := network.MakeNode(ctx, t, opts.NodeOpts)
network.Nodes[node.NodeID] = node
}
@@ -221,7 +221,7 @@ type Node struct {
// MakeNode creates a new Node configured for the network with a
// running peer manager, but does not add it to the existing
// network. Callers are responsible for updating peering relationships.
func (n *Network) MakeNode(t *testing.T, opts NodeOptions) *Node {
func (n *Network) MakeNode(ctx context.Context, t *testing.T, opts NodeOptions) *Node {
privKey := ed25519.GenPrivKey()
nodeID := types.NodeIDFromPubKey(privKey.PubKey())
nodeInfo := types.NodeInfo{
@@ -252,8 +252,9 @@ func (n *Network) MakeNode(t *testing.T, opts NodeOptions) *Node {
transport.Endpoints(),
p2p.RouterOptions{DialSleep: func(_ context.Context) {}},
)
require.NoError(t, err)
require.NoError(t, router.Start())
require.NoError(t, router.Start(ctx))
t.Cleanup(func() {
if router.IsRunning() {
@@ -304,12 +305,12 @@ func (n *Node) MakeChannelNoCleanup(
// MakePeerUpdates opens a peer update subscription, with automatic cleanup.
// It checks that all updates have been consumed during cleanup.
func (n *Node) MakePeerUpdates(t *testing.T) *p2p.PeerUpdates {
func (n *Node) MakePeerUpdates(ctx context.Context, t *testing.T) *p2p.PeerUpdates {
t.Helper()
sub := n.PeerManager.Subscribe()
t.Cleanup(func() {
t.Helper()
RequireNoUpdates(t, sub)
RequireNoUpdates(ctx, t, sub)
sub.Close()
})
+6 -2
View File
@@ -1,6 +1,7 @@
package p2ptest
import (
"context"
"testing"
"time"
@@ -95,11 +96,14 @@ func RequireSendReceive(
}
// RequireNoUpdates requires that a PeerUpdates subscription is empty.
func RequireNoUpdates(t *testing.T, peerUpdates *p2p.PeerUpdates) {
func RequireNoUpdates(ctx context.Context, t *testing.T, peerUpdates *p2p.PeerUpdates) {
t.Helper()
select {
case update := <-peerUpdates.Updates():
require.Fail(t, "unexpected peer updates", "got %v", update)
if ctx.Err() == nil {
require.Fail(t, "unexpected peer updates", "got %v", update)
}
case <-ctx.Done():
default:
}
}
+38 -8
View File
@@ -273,6 +273,9 @@ func TestPeerManager_Add(t *testing.T) {
}
func TestPeerManager_DialNext(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
@@ -296,6 +299,9 @@ func TestPeerManager_DialNext(t *testing.T) {
}
func TestPeerManager_DialNext_Retry(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
options := p2p.PeerManagerOptions{
@@ -311,7 +317,7 @@ func TestPeerManager_DialNext_Retry(t *testing.T) {
// Do five dial retries (six dials total). The retry time should double for
// each failure. At the forth retry, MaxRetryTime should kick in.
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
ctx, cancel = context.WithTimeout(ctx, 5*time.Second)
defer cancel()
for i := 0; i <= 5; i++ {
@@ -342,6 +348,9 @@ func TestPeerManager_DialNext_Retry(t *testing.T) {
}
func TestPeerManager_DialNext_WakeOnAdd(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
@@ -356,7 +365,7 @@ func TestPeerManager_DialNext_WakeOnAdd(t *testing.T) {
}()
// This will block until peer is added above.
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
defer cancel()
dial, err := peerManager.DialNext(ctx)
require.NoError(t, err)
@@ -364,6 +373,9 @@ func TestPeerManager_DialNext_WakeOnAdd(t *testing.T) {
}
func TestPeerManager_DialNext_WakeOnDialFailed(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{
MaxConnected: 1,
})
@@ -395,7 +407,7 @@ func TestPeerManager_DialNext_WakeOnDialFailed(t *testing.T) {
}()
// This should make b available for dialing (not a, retries are disabled).
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
defer cancel()
dial, err = peerManager.DialNext(ctx)
require.NoError(t, err)
@@ -403,6 +415,9 @@ func TestPeerManager_DialNext_WakeOnDialFailed(t *testing.T) {
}
func TestPeerManager_DialNext_WakeOnDialFailedRetry(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
options := p2p.PeerManagerOptions{MinRetryTime: 200 * time.Millisecond}
peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), options)
require.NoError(t, err)
@@ -421,7 +436,7 @@ func TestPeerManager_DialNext_WakeOnDialFailedRetry(t *testing.T) {
// The retry timer should unblock DialNext and make a available again after
// the retry time passes.
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
defer cancel()
dial, err = peerManager.DialNext(ctx)
require.NoError(t, err)
@@ -430,6 +445,9 @@ func TestPeerManager_DialNext_WakeOnDialFailedRetry(t *testing.T) {
}
func TestPeerManager_DialNext_WakeOnDisconnected(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
@@ -450,7 +468,7 @@ func TestPeerManager_DialNext_WakeOnDisconnected(t *testing.T) {
peerManager.Disconnected(a.NodeID)
}()
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
defer cancel()
dial, err = peerManager.DialNext(ctx)
require.NoError(t, err)
@@ -1289,6 +1307,9 @@ func TestPeerManager_Ready(t *testing.T) {
// See TryEvictNext for most tests, this just tests blocking behavior.
func TestPeerManager_EvictNext(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
@@ -1322,6 +1343,9 @@ func TestPeerManager_EvictNext(t *testing.T) {
}
func TestPeerManager_EvictNext_WakeOnError(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
peerManager, err := p2p.NewPeerManager(selfID, dbm.NewMemDB(), p2p.PeerManagerOptions{})
@@ -1340,7 +1364,7 @@ func TestPeerManager_EvictNext_WakeOnError(t *testing.T) {
}()
// This will block until peer errors above.
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
defer cancel()
evict, err := peerManager.EvictNext(ctx)
require.NoError(t, err)
@@ -1348,6 +1372,9 @@ func TestPeerManager_EvictNext_WakeOnError(t *testing.T) {
}
func TestPeerManager_EvictNext_WakeOnUpgradeDialed(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
@@ -1378,7 +1405,7 @@ func TestPeerManager_EvictNext_WakeOnUpgradeDialed(t *testing.T) {
}()
// This will block until peer is upgraded above.
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
defer cancel()
evict, err := peerManager.EvictNext(ctx)
require.NoError(t, err)
@@ -1386,6 +1413,9 @@ func TestPeerManager_EvictNext_WakeOnUpgradeDialed(t *testing.T) {
}
func TestPeerManager_EvictNext_WakeOnUpgradeAccepted(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("a", 40))}
b := p2p.NodeAddress{Protocol: "memory", NodeID: types.NodeID(strings.Repeat("b", 40))}
@@ -1410,7 +1440,7 @@ func TestPeerManager_EvictNext_WakeOnUpgradeAccepted(t *testing.T) {
}()
// This will block until peer is upgraded above.
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
defer cancel()
evict, err := peerManager.EvictNext(ctx)
require.NoError(t, err)
+2 -1
View File
@@ -1,6 +1,7 @@
package pex
import (
"context"
"fmt"
"runtime/debug"
"sync"
@@ -139,7 +140,7 @@ func NewReactor(
// envelopes on each. In addition, it also listens for peer updates and handles
// messages on that p2p channel accordingly. The caller must be sure to execute
// OnStop to ensure the outbound p2p Channels are closed.
func (r *Reactor) OnStart() error {
func (r *Reactor) OnStart(ctx context.Context) error {
go r.processPexCh()
go r.processPeerUpdates()
return nil
+56 -32
View File
@@ -1,6 +1,7 @@
package pex_test
import (
"context"
"strings"
"testing"
"time"
@@ -29,13 +30,15 @@ const (
)
func TestReactorBasic(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// start a network with one mock reactor and one "real" reactor
testNet := setupNetwork(t, testOptions{
testNet := setupNetwork(ctx, t, testOptions{
MockNodes: 1,
TotalNodes: 2,
})
testNet.connectAll(t)
testNet.start(t)
testNet.start(ctx, t)
// assert that the mock node receives a request from the real node
testNet.listenForRequest(t, secondNode, firstNode, shortWait)
@@ -47,14 +50,17 @@ func TestReactorBasic(t *testing.T) {
}
func TestReactorConnectFullNetwork(t *testing.T) {
testNet := setupNetwork(t, testOptions{
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
testNet := setupNetwork(ctx, t, testOptions{
TotalNodes: 4,
})
// make every node be only connected with one other node (it actually ends up
// being two because of two way connections but oh well)
testNet.connectN(t, 1)
testNet.start(t)
testNet.start(ctx, t)
// assert that all nodes add each other in the network
for idx := 0; idx < len(testNet.nodes); idx++ {
@@ -63,7 +69,10 @@ func TestReactorConnectFullNetwork(t *testing.T) {
}
func TestReactorSendsRequestsTooOften(t *testing.T) {
r := setupSingle(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
r := setupSingle(ctx, t)
badNode := newNodeID(t, "b")
@@ -90,12 +99,15 @@ func TestReactorSendsRequestsTooOften(t *testing.T) {
}
func TestReactorSendsResponseWithoutRequest(t *testing.T) {
testNet := setupNetwork(t, testOptions{
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
testNet := setupNetwork(ctx, t, testOptions{
MockNodes: 1,
TotalNodes: 3,
})
testNet.connectAll(t)
testNet.start(t)
testNet.start(ctx, t)
// firstNode sends the secondNode an unrequested response
// NOTE: secondNode will send a request by default during startup so we send
@@ -108,14 +120,17 @@ func TestReactorSendsResponseWithoutRequest(t *testing.T) {
}
func TestReactorNeverSendsTooManyPeers(t *testing.T) {
testNet := setupNetwork(t, testOptions{
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
testNet := setupNetwork(ctx, t, testOptions{
MockNodes: 1,
TotalNodes: 2,
})
testNet.connectAll(t)
testNet.start(t)
testNet.start(ctx, t)
testNet.addNodes(t, 110)
testNet.addNodes(ctx, t, 110)
nodes := make([]int, 110)
for i := 0; i < len(nodes); i++ {
nodes[i] = i + 2
@@ -128,7 +143,10 @@ func TestReactorNeverSendsTooManyPeers(t *testing.T) {
}
func TestReactorErrorsOnReceivingTooManyPeers(t *testing.T) {
r := setupSingle(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
r := setupSingle(ctx, t)
peer := p2p.NodeAddress{Protocol: p2p.MemoryProtocol, NodeID: randomNodeID(t)}
added, err := r.manager.Add(peer)
require.NoError(t, err)
@@ -172,14 +190,17 @@ func TestReactorErrorsOnReceivingTooManyPeers(t *testing.T) {
}
func TestReactorSmallPeerStoreInALargeNetwork(t *testing.T) {
testNet := setupNetwork(t, testOptions{
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
testNet := setupNetwork(ctx, t, testOptions{
TotalNodes: 8,
MaxPeers: 4,
MaxConnected: 3,
BufferSize: 8,
})
testNet.connectN(t, 1)
testNet.start(t)
testNet.start(ctx, t)
// test that all nodes reach full capacity
for _, nodeID := range testNet.nodes {
@@ -191,14 +212,17 @@ func TestReactorSmallPeerStoreInALargeNetwork(t *testing.T) {
}
func TestReactorLargePeerStoreInASmallNetwork(t *testing.T) {
testNet := setupNetwork(t, testOptions{
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
testNet := setupNetwork(ctx, t, testOptions{
TotalNodes: 3,
MaxPeers: 25,
MaxConnected: 25,
BufferSize: 5,
})
testNet.connectN(t, 1)
testNet.start(t)
testNet.start(ctx, t)
// assert that all nodes add each other in the network
for idx := 0; idx < len(testNet.nodes); idx++ {
@@ -207,12 +231,15 @@ func TestReactorLargePeerStoreInASmallNetwork(t *testing.T) {
}
func TestReactorWithNetworkGrowth(t *testing.T) {
testNet := setupNetwork(t, testOptions{
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
testNet := setupNetwork(ctx, t, testOptions{
TotalNodes: 5,
BufferSize: 5,
})
testNet.connectAll(t)
testNet.start(t)
testNet.start(ctx, t)
// assert that all nodes add each other in the network
for idx := 0; idx < len(testNet.nodes); idx++ {
@@ -220,10 +247,10 @@ func TestReactorWithNetworkGrowth(t *testing.T) {
}
// now we inject 10 more nodes
testNet.addNodes(t, 10)
testNet.addNodes(ctx, t, 10)
for i := 5; i < testNet.total; i++ {
node := testNet.nodes[i]
require.NoError(t, testNet.reactors[node].Start())
require.NoError(t, testNet.reactors[node].Start(ctx))
require.True(t, testNet.reactors[node].IsRunning())
// we connect all new nodes to a single entry point and check that the
// node can distribute the addresses to all the others
@@ -247,7 +274,7 @@ type singleTestReactor struct {
manager *p2p.PeerManager
}
func setupSingle(t *testing.T) *singleTestReactor {
func setupSingle(ctx context.Context, t *testing.T) *singleTestReactor {
t.Helper()
nodeID := newNodeID(t, "a")
chBuf := 2
@@ -268,14 +295,11 @@ func setupSingle(t *testing.T) *singleTestReactor {
require.NoError(t, err)
reactor := pex.NewReactor(log.TestingLogger(), peerManager, pexCh, peerUpdates)
require.NoError(t, reactor.Start())
require.NoError(t, reactor.Start(ctx))
t.Cleanup(func() {
err := reactor.Stop()
if err != nil {
t.Fatal(err)
}
pexCh.Close()
peerUpdates.Close()
reactor.Wait()
})
return &singleTestReactor{
@@ -315,7 +339,7 @@ type testOptions struct {
// setup setups a test suite with a network of nodes. Mocknodes represent the
// hollow nodes that the test can listen and send on
func setupNetwork(t *testing.T, opts testOptions) *reactorTestSuite {
func setupNetwork(ctx context.Context, t *testing.T, opts testOptions) *reactorTestSuite {
t.Helper()
require.Greater(t, opts.TotalNodes, opts.MockNodes)
@@ -335,7 +359,7 @@ func setupNetwork(t *testing.T, opts testOptions) *reactorTestSuite {
rts := &reactorTestSuite{
logger: log.TestingLogger().With("testCase", t.Name()),
network: p2ptest.MakeNetwork(t, networkOpts),
network: p2ptest.MakeNetwork(ctx, t, networkOpts),
reactors: make(map[types.NodeID]*pex.Reactor, realNodes),
pexChannels: make(map[types.NodeID]*p2p.Channel, opts.TotalNodes),
peerChans: make(map[types.NodeID]chan p2p.PeerUpdate, opts.TotalNodes),
@@ -375,7 +399,7 @@ func setupNetwork(t *testing.T, opts testOptions) *reactorTestSuite {
t.Cleanup(func() {
for nodeID, reactor := range rts.reactors {
if reactor.IsRunning() {
require.NoError(t, reactor.Stop())
reactor.Wait()
require.False(t, reactor.IsRunning())
}
rts.pexChannels[nodeID].Close()
@@ -391,20 +415,20 @@ func setupNetwork(t *testing.T, opts testOptions) *reactorTestSuite {
}
// starts up the pex reactors for each node
func (r *reactorTestSuite) start(t *testing.T) {
func (r *reactorTestSuite) start(ctx context.Context, t *testing.T) {
t.Helper()
for _, reactor := range r.reactors {
require.NoError(t, reactor.Start())
require.NoError(t, reactor.Start(ctx))
require.True(t, reactor.IsRunning())
}
}
func (r *reactorTestSuite) addNodes(t *testing.T, nodes int) {
func (r *reactorTestSuite) addNodes(ctx context.Context, t *testing.T, nodes int) {
t.Helper()
for i := 0; i < nodes; i++ {
node := r.network.MakeNode(t, p2ptest.NodeOptions{
node := r.network.MakeNode(ctx, t, p2ptest.NodeOptions{
MaxPeers: r.opts.MaxPeers,
MaxConnected: r.opts.MaxConnected,
})
+1 -1
View File
@@ -1023,7 +1023,7 @@ func (r *Router) NodeInfo() types.NodeInfo {
}
// OnStart implements service.Service.
func (r *Router) OnStart() error {
func (r *Router) OnStart(ctx context.Context) error {
for _, transport := range r.transports {
for _, endpoint := range r.endpoints {
if err := transport.Listen(endpoint); err != nil {
+67 -19
View File
@@ -44,10 +44,13 @@ func echoReactor(channel *p2p.Channel) {
}
func TestRouter_Network(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
t.Cleanup(leaktest.Check(t))
// Create a test network and open a channel where all peers run echoReactor.
network := p2ptest.MakeNetwork(t, p2ptest.NetworkOptions{NumNodes: 8})
network := p2ptest.MakeNetwork(ctx, t, p2ptest.NetworkOptions{NumNodes: 8})
local := network.RandomNode()
peers := network.Peers(local.NodeID)
channels := network.MakeChannels(t, chDesc)
@@ -114,10 +117,11 @@ func TestRouter_Channel_Basic(t *testing.T) {
)
require.NoError(t, err)
require.NoError(t, router.Start())
t.Cleanup(func() {
require.NoError(t, router.Stop())
})
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
require.NoError(t, router.Start(ctx))
t.Cleanup(router.Wait)
// Opening a channel should work.
channel, err := router.OpenChannel(chDesc)
@@ -158,10 +162,13 @@ func TestRouter_Channel_Basic(t *testing.T) {
// Channel tests are hairy to mock, so we use an in-memory network instead.
func TestRouter_Channel_SendReceive(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
t.Cleanup(leaktest.Check(t))
// Create a test network and open a channel on all nodes.
network := p2ptest.MakeNetwork(t, p2ptest.NetworkOptions{NumNodes: 3})
network := p2ptest.MakeNetwork(ctx, t, p2ptest.NetworkOptions{NumNodes: 3})
ids := network.NodeIDs()
aID, bID, cID := ids[0], ids[1], ids[2]
@@ -219,8 +226,11 @@ func TestRouter_Channel_SendReceive(t *testing.T) {
func TestRouter_Channel_Broadcast(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Create a test network and open a channel on all nodes.
network := p2ptest.MakeNetwork(t, p2ptest.NetworkOptions{NumNodes: 4})
network := p2ptest.MakeNetwork(ctx, t, p2ptest.NetworkOptions{NumNodes: 4})
ids := network.NodeIDs()
aID, bID, cID, dID := ids[0], ids[1], ids[2], ids[3]
@@ -247,8 +257,11 @@ func TestRouter_Channel_Broadcast(t *testing.T) {
func TestRouter_Channel_Wrapper(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Create a test network and open a channel on all nodes.
network := p2ptest.MakeNetwork(t, p2ptest.NetworkOptions{NumNodes: 2})
network := p2ptest.MakeNetwork(ctx, t, p2ptest.NetworkOptions{NumNodes: 2})
ids := network.NodeIDs()
aID, bID := ids[0], ids[1]
@@ -314,8 +327,11 @@ func (w *wrapperMessage) Unwrap() (proto.Message, error) {
func TestRouter_Channel_Error(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Create a test network and open a channel on all nodes.
network := p2ptest.MakeNetwork(t, p2ptest.NetworkOptions{NumNodes: 3})
network := p2ptest.MakeNetwork(ctx, t, p2ptest.NetworkOptions{NumNodes: 3})
network.Start(t)
ids := network.NodeIDs()
@@ -324,7 +340,7 @@ func TestRouter_Channel_Error(t *testing.T) {
a := channels[aID]
// Erroring b should cause it to be disconnected. It will reconnect shortly after.
sub := network.Nodes[aID].MakePeerUpdates(t)
sub := network.Nodes[aID].MakePeerUpdates(ctx, t)
p2ptest.RequireError(t, a, p2p.PeerError{NodeID: bID, Err: errors.New("boom")})
p2ptest.RequireUpdates(t, sub, []p2p.PeerUpdate{
{NodeID: bID, Status: p2p.PeerStatusDown},
@@ -353,9 +369,16 @@ func TestRouter_AcceptPeers(t *testing.T) {
false,
},
}
bctx, bcancel := context.WithCancel(context.Background())
defer bcancel()
for name, tc := range testcases {
tc := tc
t.Run(name, func(t *testing.T) {
ctx, cancel := context.WithCancel(bctx)
defer cancel()
t.Cleanup(leaktest.Check(t))
// Set up a mock transport that handshakes.
@@ -398,7 +421,7 @@ func TestRouter_AcceptPeers(t *testing.T) {
p2p.RouterOptions{},
)
require.NoError(t, err)
require.NoError(t, router.Start())
require.NoError(t, router.Start(ctx))
if tc.ok {
p2ptest.RequireUpdate(t, sub, p2p.PeerUpdate{
@@ -427,6 +450,9 @@ func TestRouter_AcceptPeers(t *testing.T) {
func TestRouter_AcceptPeers_Error(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Set up a mock transport that returns an error, which should prevent
// the router from calling Accept again.
mockTransport := &mocks.Transport{}
@@ -452,7 +478,7 @@ func TestRouter_AcceptPeers_Error(t *testing.T) {
)
require.NoError(t, err)
require.NoError(t, router.Start())
require.NoError(t, router.Start(ctx))
time.Sleep(time.Second)
require.NoError(t, router.Stop())
@@ -487,7 +513,10 @@ func TestRouter_AcceptPeers_ErrorEOF(t *testing.T) {
)
require.NoError(t, err)
require.NoError(t, router.Start())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
require.NoError(t, router.Start(ctx))
time.Sleep(time.Second)
require.NoError(t, router.Stop())
@@ -497,6 +526,9 @@ func TestRouter_AcceptPeers_ErrorEOF(t *testing.T) {
func TestRouter_AcceptPeers_HeadOfLineBlocking(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Set up a mock transport that returns a connection that blocks during the
// handshake. It should be able to accept several of these in parallel, i.e.
// a single connection can't halt other connections being accepted.
@@ -535,7 +567,7 @@ func TestRouter_AcceptPeers_HeadOfLineBlocking(t *testing.T) {
p2p.RouterOptions{},
)
require.NoError(t, err)
require.NoError(t, router.Start())
require.NoError(t, router.Start(ctx))
require.Eventually(t, func() bool {
return len(acceptCh) == 3
@@ -574,10 +606,16 @@ func TestRouter_DialPeers(t *testing.T) {
false,
},
}
bctx, bcancel := context.WithCancel(context.Background())
defer bcancel()
for name, tc := range testcases {
tc := tc
t.Run(name, func(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(bctx)
defer cancel()
address := p2p.NodeAddress{Protocol: "mock", NodeID: tc.dialID}
endpoint := p2p.Endpoint{Protocol: "mock", Path: string(tc.dialID)}
@@ -635,7 +673,7 @@ func TestRouter_DialPeers(t *testing.T) {
p2p.RouterOptions{},
)
require.NoError(t, err)
require.NoError(t, router.Start())
require.NoError(t, router.Start(ctx))
if tc.ok {
p2ptest.RequireUpdate(t, sub, p2p.PeerUpdate{
@@ -664,6 +702,9 @@ func TestRouter_DialPeers(t *testing.T) {
func TestRouter_DialPeers_Parallel(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
a := p2p.NodeAddress{Protocol: "mock", NodeID: types.NodeID(strings.Repeat("a", 40))}
b := p2p.NodeAddress{Protocol: "mock", NodeID: types.NodeID(strings.Repeat("b", 40))}
c := p2p.NodeAddress{Protocol: "mock", NodeID: types.NodeID(strings.Repeat("c", 40))}
@@ -729,7 +770,7 @@ func TestRouter_DialPeers_Parallel(t *testing.T) {
)
require.NoError(t, err)
require.NoError(t, router.Start())
require.NoError(t, router.Start(ctx))
require.Eventually(t,
func() bool {
@@ -750,6 +791,9 @@ func TestRouter_DialPeers_Parallel(t *testing.T) {
func TestRouter_EvictPeers(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Set up a mock transport that we can evict.
closeCh := make(chan time.Time)
closeOnce := sync.Once{}
@@ -792,7 +836,7 @@ func TestRouter_EvictPeers(t *testing.T) {
p2p.RouterOptions{},
)
require.NoError(t, err)
require.NoError(t, router.Start())
require.NoError(t, router.Start(ctx))
// Wait for the mock peer to connect, then evict it by reporting an error.
p2ptest.RequireUpdate(t, sub, p2p.PeerUpdate{
@@ -815,6 +859,8 @@ func TestRouter_EvictPeers(t *testing.T) {
func TestRouter_ChannelCompatability(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
incompatiblePeer := types.NodeInfo{
NodeID: peerID,
@@ -854,7 +900,7 @@ func TestRouter_ChannelCompatability(t *testing.T) {
p2p.RouterOptions{},
)
require.NoError(t, err)
require.NoError(t, router.Start())
require.NoError(t, router.Start(ctx))
time.Sleep(1 * time.Second)
require.NoError(t, router.Stop())
require.Empty(t, peerManager.Peers())
@@ -865,6 +911,8 @@ func TestRouter_ChannelCompatability(t *testing.T) {
func TestRouter_DontSendOnInvalidChannel(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
peer := types.NodeInfo{
NodeID: peerID,
@@ -909,7 +957,7 @@ func TestRouter_DontSendOnInvalidChannel(t *testing.T) {
p2p.RouterOptions{},
)
require.NoError(t, err)
require.NoError(t, router.Start())
require.NoError(t, router.Start(ctx))
p2ptest.RequireUpdate(t, sub, p2p.PeerUpdate{
NodeID: peerInfo.NodeID,
+1 -1
View File
@@ -291,7 +291,7 @@ func (c *mConnConnection) Handshake(
}
c.mconn = mconn
c.logger = mconn.Logger
if err = c.mconn.Start(); err != nil {
if err = c.mconn.Start(ctx); err != nil {
return types.NodeInfo{}, nil, err
}
return peerInfo, peerKey, nil
+13
View File
@@ -1,6 +1,7 @@
package p2p_test
import (
"context"
"io"
"net"
"testing"
@@ -58,6 +59,9 @@ func TestMConnTransport_AcceptBeforeListen(t *testing.T) {
}
func TestMConnTransport_AcceptMaxAcceptedConnections(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
transport := p2p.NewMConnTransport(
log.TestingLogger(),
conn.DefaultMConnConfig(),
@@ -124,6 +128,9 @@ func TestMConnTransport_AcceptMaxAcceptedConnections(t *testing.T) {
}
func TestMConnTransport_Listen(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
testcases := []struct {
endpoint p2p.Endpoint
ok bool
@@ -145,6 +152,9 @@ func TestMConnTransport_Listen(t *testing.T) {
t.Run(tc.endpoint.String(), func(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel = context.WithCancel(ctx)
defer cancel()
transport := p2p.NewMConnTransport(
log.TestingLogger(),
conn.DefaultMConnConfig(),
@@ -185,6 +195,9 @@ func TestMConnTransport_Listen(t *testing.T) {
go func() {
// Dialing the endpoint should work.
var err error
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
peerConn, err = transport.Dial(ctx, endpoint)
require.NoError(t, err)
close(dialedChan)
+67 -28
View File
@@ -25,20 +25,26 @@ var testTransports = map[string]transportFactory{}
// withTransports is a test helper that runs a test against all transports
// registered in testTransports.
func withTransports(t *testing.T, tester func(*testing.T, transportFactory)) {
func withTransports(ctx context.Context, t *testing.T, tester func(context.Context, *testing.T, transportFactory)) {
t.Helper()
for name, transportFactory := range testTransports {
transportFactory := transportFactory
t.Run(name, func(t *testing.T) {
t.Cleanup(leaktest.Check(t))
tester(t, transportFactory)
tctx, cancel := context.WithCancel(ctx)
defer cancel()
tester(tctx, t, transportFactory)
})
}
}
func TestTransport_AcceptClose(t *testing.T) {
// Just test accept unblock on close, happy path is tested widely elsewhere.
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
// In-progress Accept should error on concurrent close.
@@ -75,7 +81,10 @@ func TestTransport_DialEndpoints(t *testing.T) {
{[]byte{1, 2, 3, 4, 5}, false},
}
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
endpoints := a.Endpoints()
require.NotEmpty(t, endpoints)
@@ -149,8 +158,11 @@ func TestTransport_DialEndpoints(t *testing.T) {
}
func TestTransport_Dial(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Most just tests dial failures, happy path is tested widely elsewhere.
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
b := makeTransport(t)
@@ -190,7 +202,10 @@ func TestTransport_Dial(t *testing.T) {
}
func TestTransport_Endpoints(t *testing.T) {
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
b := makeTransport(t)
@@ -214,7 +229,10 @@ func TestTransport_Endpoints(t *testing.T) {
}
func TestTransport_Protocols(t *testing.T) {
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
protocols := a.Protocols()
endpoints := a.Endpoints()
@@ -228,17 +246,23 @@ func TestTransport_Protocols(t *testing.T) {
}
func TestTransport_String(t *testing.T) {
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
require.NotEmpty(t, a.String())
})
}
func TestConnection_Handshake(t *testing.T) {
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
b := makeTransport(t)
ab, ba := dialAccept(t, a, b)
ab, ba := dialAccept(ctx, t, a, b)
// A handshake should pass the given keys and NodeInfo.
aKey := ed25519.GenPrivKey()
@@ -270,7 +294,10 @@ func TestConnection_Handshake(t *testing.T) {
assert.Equal(t, aInfo, peerInfo)
assert.Equal(t, aKey.PubKey(), peerKey)
}
errCh <- err
select {
case errCh <- err:
case <-ctx.Done():
}
}()
peerInfo, peerKey, err := ab.Handshake(ctx, aInfo, aKey)
@@ -283,12 +310,15 @@ func TestConnection_Handshake(t *testing.T) {
}
func TestConnection_HandshakeCancel(t *testing.T) {
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
b := makeTransport(t)
// Handshake should error on context cancellation.
ab, ba := dialAccept(t, a, b)
ab, ba := dialAccept(ctx, t, a, b)
timeoutCtx, cancel := context.WithTimeout(ctx, 1*time.Minute)
cancel()
_, _, err := ab.Handshake(timeoutCtx, types.NodeInfo{}, ed25519.GenPrivKey())
@@ -298,7 +328,7 @@ func TestConnection_HandshakeCancel(t *testing.T) {
_ = ba.Close()
// Handshake should error on context timeout.
ab, ba = dialAccept(t, a, b)
ab, ba = dialAccept(ctx, t, a, b)
timeoutCtx, cancel = context.WithTimeout(ctx, 200*time.Millisecond)
defer cancel()
_, _, err = ab.Handshake(timeoutCtx, types.NodeInfo{}, ed25519.GenPrivKey())
@@ -310,10 +340,13 @@ func TestConnection_HandshakeCancel(t *testing.T) {
}
func TestConnection_FlushClose(t *testing.T) {
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
b := makeTransport(t)
ab, _ := dialAcceptHandshake(t, a, b)
ab, _ := dialAcceptHandshake(ctx, t, a, b)
err := ab.Close()
require.NoError(t, err)
@@ -329,10 +362,13 @@ func TestConnection_FlushClose(t *testing.T) {
}
func TestConnection_LocalRemoteEndpoint(t *testing.T) {
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
b := makeTransport(t)
ab, ba := dialAcceptHandshake(t, a, b)
ab, ba := dialAcceptHandshake(ctx, t, a, b)
// Local and remote connection endpoints correspond to each other.
require.NotEmpty(t, ab.LocalEndpoint())
@@ -343,10 +379,13 @@ func TestConnection_LocalRemoteEndpoint(t *testing.T) {
}
func TestConnection_SendReceive(t *testing.T) {
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
b := makeTransport(t)
ab, ba := dialAcceptHandshake(t, a, b)
ab, ba := dialAcceptHandshake(ctx, t, a, b)
// Can send and receive a to b.
err := ab.SendMessage(chID, []byte("foo"))
@@ -402,10 +441,13 @@ func TestConnection_SendReceive(t *testing.T) {
}
func TestConnection_String(t *testing.T) {
withTransports(t, func(t *testing.T, makeTransport transportFactory) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
withTransports(ctx, t, func(ctx context.Context, t *testing.T, makeTransport transportFactory) {
a := makeTransport(t)
b := makeTransport(t)
ab, _ := dialAccept(t, a, b)
ab, _ := dialAccept(ctx, t, a, b)
require.NotEmpty(t, ab.String())
})
}
@@ -552,7 +594,7 @@ func TestEndpoint_Validate(t *testing.T) {
// dialAccept is a helper that dials b from a and returns both sides of the
// connection.
func dialAccept(t *testing.T, a, b p2p.Transport) (p2p.Connection, p2p.Connection) {
func dialAccept(ctx context.Context, t *testing.T, a, b p2p.Transport) (p2p.Connection, p2p.Connection) {
t.Helper()
endpoints := b.Endpoints()
@@ -585,13 +627,10 @@ func dialAccept(t *testing.T, a, b p2p.Transport) (p2p.Connection, p2p.Connectio
// dialAcceptHandshake is a helper that dials and handshakes b from a and
// returns both sides of the connection.
func dialAcceptHandshake(t *testing.T, a, b p2p.Transport) (p2p.Connection, p2p.Connection) {
func dialAcceptHandshake(ctx context.Context, t *testing.T, a, b p2p.Transport) (p2p.Connection, p2p.Connection) {
t.Helper()
ab, ba := dialAccept(t, a, b)
ctx, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
ab, ba := dialAccept(ctx, t, a, b)
errCh := make(chan error, 1)
go func() {
+3 -2
View File
@@ -4,6 +4,7 @@
package trust
import (
"context"
"math"
"time"
@@ -109,8 +110,8 @@ func NewMetricWithConfig(tmc MetricConfig) *Metric {
}
// OnStart implements Service
func (tm *Metric) OnStart() error {
if err := tm.BaseService.OnStart(); err != nil {
func (tm *Metric) OnStart(ctx context.Context) error {
if err := tm.BaseService.OnStart(ctx); err != nil {
return err
}
go tm.processRequests()
+14 -4
View File
@@ -1,6 +1,7 @@
package trust
import (
"context"
"testing"
"time"
@@ -9,8 +10,11 @@ import (
)
func TestTrustMetricScores(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
tm := NewMetric()
err := tm.Start()
err := tm.Start(ctx)
require.NoError(t, err)
// Perfect score
@@ -27,6 +31,9 @@ func TestTrustMetricScores(t *testing.T) {
}
func TestTrustMetricConfig(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// 7 days
window := time.Minute * 60 * 24 * 7
config := MetricConfig{
@@ -35,7 +42,7 @@ func TestTrustMetricConfig(t *testing.T) {
}
tm := NewMetricWithConfig(config)
err := tm.Start()
err := tm.Start(ctx)
require.NoError(t, err)
// The max time intervals should be the TrackingWindow / IntervalLen
@@ -52,7 +59,7 @@ func TestTrustMetricConfig(t *testing.T) {
config.ProportionalWeight = 0.3
config.IntegralWeight = 0.7
tm = NewMetricWithConfig(config)
err = tm.Start()
err = tm.Start(ctx)
require.NoError(t, err)
// These weights should be equal to our custom values
@@ -74,12 +81,15 @@ func TestTrustMetricCopyNilPointer(t *testing.T) {
// XXX: This test fails non-deterministically
//nolint:unused,deadcode
func _TestTrustMetricStopPause(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// The TestTicker will provide manual control over
// the passing of time within the metric
tt := NewTestTicker()
tm := NewMetric()
tm.SetTicker(tt)
err := tm.Start()
err := tm.Start(ctx)
require.NoError(t, err)
// Allow some time intervals to pass and pause
tt.NextTick()
+8 -7
View File
@@ -4,6 +4,7 @@
package trust
import (
"context"
"encoding/json"
"fmt"
"time"
@@ -51,15 +52,15 @@ func NewTrustMetricStore(db dbm.DB, tmc MetricConfig, logger log.Logger) *Metric
}
// OnStart implements Service
func (tms *MetricStore) OnStart() error {
if err := tms.BaseService.OnStart(); err != nil {
func (tms *MetricStore) OnStart(ctx context.Context) error {
if err := tms.BaseService.OnStart(ctx); err != nil {
return err
}
tms.mtx.Lock()
defer tms.mtx.Unlock()
tms.loadFromDB()
tms.loadFromDB(ctx)
go tms.saveRoutine()
return nil
}
@@ -103,7 +104,7 @@ func (tms *MetricStore) AddPeerTrustMetric(key string, tm *Metric) {
}
// GetPeerTrustMetric returns a trust metric by peer key
func (tms *MetricStore) GetPeerTrustMetric(key string) *Metric {
func (tms *MetricStore) GetPeerTrustMetric(ctx context.Context, key string) *Metric {
tms.mtx.Lock()
defer tms.mtx.Unlock()
@@ -111,7 +112,7 @@ func (tms *MetricStore) GetPeerTrustMetric(key string) *Metric {
if !ok {
// If the metric is not available, we will create it
tm = NewMetricWithConfig(tms.config)
if err := tm.Start(); err != nil {
if err := tm.Start(ctx); err != nil {
tms.Logger.Error("unable to start metric store", "error", err)
}
// The metric needs to be in the map
@@ -152,7 +153,7 @@ func (tms *MetricStore) size() int {
// Loads the history data for all peers from the store DB
// cmn.Panics if file is corrupt
func (tms *MetricStore) loadFromDB() bool {
func (tms *MetricStore) loadFromDB(ctx context.Context) bool {
// Obtain the history data we have so far
bytes, err := tms.db.Get(trustMetricKey)
if err != nil {
@@ -173,7 +174,7 @@ func (tms *MetricStore) loadFromDB() bool {
for key, p := range peers {
tm := NewMetricWithConfig(tms.config)
if err := tm.Start(); err != nil {
if err := tm.Start(ctx); err != nil {
tms.Logger.Error("unable to start metric", "error", err)
}
tm.Init(p)
+23 -10
View File
@@ -4,6 +4,7 @@
package trust
import (
"context"
"fmt"
"testing"
@@ -15,6 +16,9 @@ import (
)
func TestTrustMetricStoreSaveLoad(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
dir := t.TempDir()
logger := log.TestingLogger()
@@ -26,7 +30,7 @@ func TestTrustMetricStoreSaveLoad(t *testing.T) {
store.saveToDB()
// Load the data from the file
store = NewTrustMetricStore(historyDB, DefaultConfig(), logger)
err = store.Start()
err = store.Start(ctx)
require.NoError(t, err)
// Make sure we still have 0 entries
assert.Zero(t, store.Size())
@@ -44,7 +48,7 @@ func TestTrustMetricStoreSaveLoad(t *testing.T) {
tm := NewMetric()
tm.SetTicker(tt[i])
err = tm.Start()
err = tm.Start(ctx)
require.NoError(t, err)
store.AddPeerTrustMetric(key, tm)
@@ -65,7 +69,7 @@ func TestTrustMetricStoreSaveLoad(t *testing.T) {
// Load the data from the DB
store = NewTrustMetricStore(historyDB, DefaultConfig(), logger)
err = store.Start()
err = store.Start(ctx)
require.NoError(t, err)
// Check that we still have 100 peers with imperfect trust values
@@ -79,6 +83,9 @@ func TestTrustMetricStoreSaveLoad(t *testing.T) {
}
func TestTrustMetricStoreConfig(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
historyDB, err := dbm.NewDB("", "memdb", "")
require.NoError(t, err)
@@ -91,11 +98,11 @@ func TestTrustMetricStoreConfig(t *testing.T) {
// Create a store with custom config
store := NewTrustMetricStore(historyDB, config, logger)
err = store.Start()
err = store.Start(ctx)
require.NoError(t, err)
// Have the store make us a metric with the config
tm := store.GetPeerTrustMetric("TestKey")
tm := store.GetPeerTrustMetric(ctx, "TestKey")
// Check that the options made it to the metric
assert.Equal(t, 0.5, tm.proportionalWeight)
@@ -105,18 +112,21 @@ func TestTrustMetricStoreConfig(t *testing.T) {
}
func TestTrustMetricStoreLookup(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
historyDB, err := dbm.NewDB("", "memdb", "")
require.NoError(t, err)
store := NewTrustMetricStore(historyDB, DefaultConfig(), log.TestingLogger())
err = store.Start()
err = store.Start(ctx)
require.NoError(t, err)
// Create 100 peers in the trust metric store
for i := 0; i < 100; i++ {
key := fmt.Sprintf("peer_%d", i)
store.GetPeerTrustMetric(key)
store.GetPeerTrustMetric(ctx, key)
// Check that the trust metric was successfully entered
ktm := store.peerMetrics[key]
@@ -128,16 +138,19 @@ func TestTrustMetricStoreLookup(t *testing.T) {
}
func TestTrustMetricStorePeerScore(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
historyDB, err := dbm.NewDB("", "memdb", "")
require.NoError(t, err)
store := NewTrustMetricStore(historyDB, DefaultConfig(), log.TestingLogger())
err = store.Start()
err = store.Start(ctx)
require.NoError(t, err)
key := "TestKey"
tm := store.GetPeerTrustMetric(key)
tm := store.GetPeerTrustMetric(ctx, key)
// This peer is innocent so far
first := tm.TrustScore()
@@ -156,7 +169,7 @@ func TestTrustMetricStorePeerScore(t *testing.T) {
store.PeerDisconnected(key)
// We will remember our experiences with this peer
tm = store.GetPeerTrustMetric(key)
tm = store.GetPeerTrustMetric(ctx, key)
assert.NotEqual(t, 100, tm.TrustScore())
err = store.Stop()
require.NoError(t, err)
+18 -23
View File
@@ -51,16 +51,15 @@ func TestEcho(t *testing.T) {
logger := log.TestingLogger()
clientCreator := abciclient.NewRemoteCreator(logger, sockPath, SOCKET, true)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Start server
s := server.NewSocketServer(logger.With("module", "abci-server"), sockPath, kvstore.NewApplication())
if err := s.Start(); err != nil {
if err := s.Start(ctx); err != nil {
t.Fatalf("Error starting socket server: %v", err.Error())
}
t.Cleanup(func() {
if err := s.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); s.Wait() })
// Start client
cli, err := clientCreator(logger.With("module", "abci-client"))
@@ -68,14 +67,13 @@ func TestEcho(t *testing.T) {
t.Fatalf("Error creating ABCI client: %v", err.Error())
}
if err := cli.Start(); err != nil {
if err := cli.Start(ctx); err != nil {
t.Fatalf("Error starting ABCI client: %v", err.Error())
}
proxy := newAppConnTest(cli)
t.Log("Connected")
ctx := context.Background()
for i := 0; i < 1000; i++ {
_, err = proxy.EchoAsync(ctx, fmt.Sprintf("echo-%v", i))
if err != nil {
@@ -99,16 +97,15 @@ func BenchmarkEcho(b *testing.B) {
logger := log.TestingLogger()
clientCreator := abciclient.NewRemoteCreator(logger, sockPath, SOCKET, true)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Start server
s := server.NewSocketServer(logger.With("module", "abci-server"), sockPath, kvstore.NewApplication())
if err := s.Start(); err != nil {
if err := s.Start(ctx); err != nil {
b.Fatalf("Error starting socket server: %v", err.Error())
}
b.Cleanup(func() {
if err := s.Stop(); err != nil {
b.Error(err)
}
})
b.Cleanup(func() { cancel(); s.Wait() })
// Start client
cli, err := clientCreator(logger.With("module", "abci-client"))
@@ -116,7 +113,7 @@ func BenchmarkEcho(b *testing.B) {
b.Fatalf("Error creating ABCI client: %v", err.Error())
}
if err := cli.Start(); err != nil {
if err := cli.Start(ctx); err != nil {
b.Fatalf("Error starting ABCI client: %v", err.Error())
}
@@ -125,7 +122,6 @@ func BenchmarkEcho(b *testing.B) {
echoString := strings.Repeat(" ", 200)
b.StartTimer() // Start benchmarking tests
ctx := context.Background()
for i := 0; i < b.N; i++ {
_, err = proxy.EchoAsync(ctx, echoString)
if err != nil {
@@ -152,16 +148,15 @@ func TestInfo(t *testing.T) {
logger := log.TestingLogger()
clientCreator := abciclient.NewRemoteCreator(logger, sockPath, SOCKET, true)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Start server
s := server.NewSocketServer(logger.With("module", "abci-server"), sockPath, kvstore.NewApplication())
if err := s.Start(); err != nil {
if err := s.Start(ctx); err != nil {
t.Fatalf("Error starting socket server: %v", err.Error())
}
t.Cleanup(func() {
if err := s.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); s.Wait() })
// Start client
cli, err := clientCreator(logger.With("module", "abci-client"))
@@ -169,7 +164,7 @@ func TestInfo(t *testing.T) {
t.Fatalf("Error creating ABCI client: %v", err.Error())
}
if err := cli.Start(); err != nil {
if err := cli.Start(ctx); err != nil {
t.Fatalf("Error starting ABCI client: %v", err.Error())
}
+37 -19
View File
@@ -1,6 +1,8 @@
package proxy
import (
"context"
"errors"
"fmt"
"os"
"syscall"
@@ -51,14 +53,22 @@ type multiAppConn struct {
queryConn AppConnQuery
snapshotConn AppConnSnapshot
consensusConnClient abciclient.Client
mempoolConnClient abciclient.Client
queryConnClient abciclient.Client
snapshotConnClient abciclient.Client
consensusConnClient stoppableClient
mempoolConnClient stoppableClient
queryConnClient stoppableClient
snapshotConnClient stoppableClient
clientCreator abciclient.Creator
}
// TODO: this is a totally internal and quasi permanent shim for
// clients. eventually we can have a single client and have some kind
// of reasonable lifecycle witout needing an explicit stop method.
type stoppableClient interface {
abciclient.Client
Stop() error
}
// NewMultiAppConn makes all necessary abci connections to the application.
func NewMultiAppConn(clientCreator abciclient.Creator, logger log.Logger, metrics *Metrics) AppConns {
multiAppConn := &multiAppConn{
@@ -85,36 +95,36 @@ func (app *multiAppConn) Snapshot() AppConnSnapshot {
return app.snapshotConn
}
func (app *multiAppConn) OnStart() error {
c, err := app.abciClientFor(connQuery)
func (app *multiAppConn) OnStart(ctx context.Context) error {
c, err := app.abciClientFor(ctx, connQuery)
if err != nil {
return err
}
app.queryConnClient = c
app.queryConnClient = c.(stoppableClient)
app.queryConn = NewAppConnQuery(c, app.metrics)
c, err = app.abciClientFor(connSnapshot)
c, err = app.abciClientFor(ctx, connSnapshot)
if err != nil {
app.stopAllClients()
return err
}
app.snapshotConnClient = c
app.snapshotConnClient = c.(stoppableClient)
app.snapshotConn = NewAppConnSnapshot(c, app.metrics)
c, err = app.abciClientFor(connMempool)
c, err = app.abciClientFor(ctx, connMempool)
if err != nil {
app.stopAllClients()
return err
}
app.mempoolConnClient = c
app.mempoolConnClient = c.(stoppableClient)
app.mempoolConn = NewAppConnMempool(c, app.metrics)
c, err = app.abciClientFor(connConsensus)
c, err = app.abciClientFor(ctx, connConsensus)
if err != nil {
app.stopAllClients()
return err
}
app.consensusConnClient = c
app.consensusConnClient = c.(stoppableClient)
app.consensusConn = NewAppConnConsensus(c, app.metrics)
// Kill Tendermint if the ABCI application crashes.
@@ -160,34 +170,42 @@ func (app *multiAppConn) killTMOnClientError() {
func (app *multiAppConn) stopAllClients() {
if app.consensusConnClient != nil {
if err := app.consensusConnClient.Stop(); err != nil {
app.Logger.Error("error while stopping consensus client", "error", err)
if !errors.Is(err, service.ErrAlreadyStopped) {
app.Logger.Error("error while stopping consensus client", "error", err)
}
}
}
if app.mempoolConnClient != nil {
if err := app.mempoolConnClient.Stop(); err != nil {
app.Logger.Error("error while stopping mempool client", "error", err)
if !errors.Is(err, service.ErrAlreadyStopped) {
app.Logger.Error("error while stopping mempool client", "error", err)
}
}
}
if app.queryConnClient != nil {
if err := app.queryConnClient.Stop(); err != nil {
app.Logger.Error("error while stopping query client", "error", err)
if !errors.Is(err, service.ErrAlreadyStopped) {
app.Logger.Error("error while stopping query client", "error", err)
}
}
}
if app.snapshotConnClient != nil {
if err := app.snapshotConnClient.Stop(); err != nil {
app.Logger.Error("error while stopping snapshot client", "error", err)
if !errors.Is(err, service.ErrAlreadyStopped) {
app.Logger.Error("error while stopping snapshot client", "error", err)
}
}
}
}
func (app *multiAppConn) abciClientFor(conn string) (abciclient.Client, error) {
func (app *multiAppConn) abciClientFor(ctx context.Context, conn string) (abciclient.Client, error) {
c, err := app.clientCreator(app.Logger.With(
"module", "abci-client",
"connection", conn))
if err != nil {
return nil, fmt.Errorf("error creating ABCI client (%s connection): %w", conn, err)
}
if err := c.Start(); err != nil {
if err := c.Start(ctx); err != nil {
return nil, fmt.Errorf("error starting ABCI client (%s connection): %w", conn, err)
}
return c, nil
+26 -15
View File
@@ -1,6 +1,7 @@
package proxy
import (
"context"
"errors"
"os"
"os/signal"
@@ -17,31 +18,42 @@ import (
"github.com/tendermint/tendermint/libs/log"
)
type noopStoppableClientImpl struct {
abciclient.Client
count int
}
func (c *noopStoppableClientImpl) Stop() error { c.count++; return nil }
func TestAppConns_Start_Stop(t *testing.T) {
quitCh := make(<-chan struct{})
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
clientMock := &abcimocks.Client{}
clientMock.On("Start").Return(nil).Times(4)
clientMock.On("Stop").Return(nil).Times(4)
clientMock.On("Start", mock.Anything).Return(nil).Times(4)
clientMock.On("Quit").Return(quitCh).Times(4)
cl := &noopStoppableClientImpl{Client: clientMock}
creatorCallCount := 0
creator := func(logger log.Logger) (abciclient.Client, error) {
creatorCallCount++
return clientMock, nil
return cl, nil
}
appConns := NewAppConns(creator, log.TestingLogger(), NopMetrics())
err := appConns.Start()
err := appConns.Start(ctx)
require.NoError(t, err)
time.Sleep(100 * time.Millisecond)
err = appConns.Stop()
require.NoError(t, err)
cancel()
appConns.Wait()
clientMock.AssertExpectations(t)
assert.Equal(t, 4, cl.count)
assert.Equal(t, 4, creatorCallCount)
}
@@ -56,31 +68,30 @@ func TestAppConns_Failure(t *testing.T) {
}
}()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
quitCh := make(chan struct{})
var recvQuitCh <-chan struct{} // nolint:gosimple
recvQuitCh = quitCh
clientMock := &abcimocks.Client{}
clientMock.On("SetLogger", mock.Anything).Return()
clientMock.On("Start").Return(nil)
clientMock.On("Stop").Return(nil)
clientMock.On("Start", mock.Anything).Return(nil)
clientMock.On("Quit").Return(recvQuitCh)
clientMock.On("Error").Return(errors.New("EOF")).Once()
cl := &noopStoppableClientImpl{Client: clientMock}
creator := func(log.Logger) (abciclient.Client, error) {
return clientMock, nil
return cl, nil
}
appConns := NewAppConns(creator, log.TestingLogger(), NopMetrics())
err := appConns.Start()
err := appConns.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := appConns.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() { cancel(); appConns.Wait() })
// simulate failure
close(quitCh)
+1 -1
View File
@@ -332,7 +332,7 @@ func execBlockOnProxyApp(
byzVals = append(byzVals, evidence.ABCI()...)
}
ctx := context.Background()
ctx := context.TODO()
// Begin block
var err error
+24 -12
View File
@@ -40,9 +40,12 @@ func TestApplyBlock(t *testing.T) {
cc := abciclient.NewLocalCreator(app)
logger := log.TestingLogger()
proxyApp := proxy.NewAppConns(cc, logger, proxy.NopMetrics())
err := proxyApp.Start()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
err := proxyApp.Start(ctx)
require.Nil(t, err)
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
state, stateDB, _ := makeState(1, 1)
stateStore := sm.NewStore(stateDB)
@@ -62,12 +65,15 @@ func TestApplyBlock(t *testing.T) {
// TestBeginBlockValidators ensures we send absent validators list.
func TestBeginBlockValidators(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
app := &testApp{}
cc := abciclient.NewLocalCreator(app)
proxyApp := proxy.NewAppConns(cc, log.TestingLogger(), proxy.NopMetrics())
err := proxyApp.Start()
err := proxyApp.Start(ctx)
require.Nil(t, err)
defer proxyApp.Stop() //nolint:errcheck // no need to check error again
state, stateDB, _ := makeState(2, 2)
stateStore := sm.NewStore(stateDB)
@@ -125,12 +131,14 @@ func TestBeginBlockValidators(t *testing.T) {
// TestBeginBlockByzantineValidators ensures we send byzantine validators list.
func TestBeginBlockByzantineValidators(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
app := &testApp{}
cc := abciclient.NewLocalCreator(app)
proxyApp := proxy.NewAppConns(cc, log.TestingLogger(), proxy.NopMetrics())
err := proxyApp.Start()
err := proxyApp.Start(ctx)
require.Nil(t, err)
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
state, stateDB, privVals := makeState(1, 1)
stateStore := sm.NewStore(stateDB)
@@ -350,13 +358,15 @@ func TestUpdateValidators(t *testing.T) {
// TestEndBlockValidatorUpdates ensures we update validator set and send an event.
func TestEndBlockValidatorUpdates(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
app := &testApp{}
cc := abciclient.NewLocalCreator(app)
logger := log.TestingLogger()
proxyApp := proxy.NewAppConns(cc, logger, proxy.NopMetrics())
err := proxyApp.Start()
err := proxyApp.Start(ctx)
require.Nil(t, err)
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
state, stateDB, _ := makeState(1, 1)
stateStore := sm.NewStore(stateDB)
@@ -372,7 +382,7 @@ func TestEndBlockValidatorUpdates(t *testing.T) {
)
eventBus := eventbus.NewDefault(logger)
err = eventBus.Start()
err = eventBus.Start(ctx)
require.NoError(t, err)
defer eventBus.Stop() //nolint:errcheck // ignore for tests
@@ -405,7 +415,7 @@ func TestEndBlockValidatorUpdates(t *testing.T) {
}
// test we threw an event
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
ctx, cancel = context.WithTimeout(ctx, 1*time.Second)
defer cancel()
msg, err := updatesSub.Next(ctx)
require.NoError(t, err)
@@ -420,13 +430,15 @@ func TestEndBlockValidatorUpdates(t *testing.T) {
// TestEndBlockValidatorUpdatesResultingInEmptySet checks that processing validator updates that
// would result in empty set causes no panic, an error is raised and NextValidators is not updated
func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
app := &testApp{}
cc := abciclient.NewLocalCreator(app)
logger := log.TestingLogger()
proxyApp := proxy.NewAppConns(cc, logger, proxy.NopMetrics())
err := proxyApp.Start()
err := proxyApp.Start(ctx)
require.Nil(t, err)
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
state, stateDB, _ := makeState(1, 1)
stateStore := sm.NewStore(stateDB)
+1 -1
View File
@@ -116,7 +116,7 @@ func (is *Service) publish(msg pubsub.Message) error {
// indexer if the underlying event sinks support indexing.
//
// TODO(creachadair): Can we get rid of the "enabled" check?
func (is *Service) OnStart() error {
func (is *Service) OnStart(ctx context.Context) error {
// If the event sinks support indexing, register an observer to capture
// block header data for the indexer.
if IndexingEnabled(is.eventSinks) {
+8 -13
View File
@@ -1,6 +1,7 @@
package indexer_test
import (
"context"
"database/sql"
"fmt"
"os"
@@ -47,16 +48,15 @@ func NewIndexerService(es []indexer.EventSink, eventBus *eventbus.EventBus) *ind
}
func TestIndexerServiceIndexesBlocks(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger := tmlog.TestingLogger()
// event bus
eventBus := eventbus.NewDefault(logger)
err := eventBus.Start()
err := eventBus.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
if err := eventBus.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(eventBus.Wait)
assert.False(t, indexer.KVSinkEnabled([]indexer.EventSink{}))
assert.False(t, indexer.IndexingEnabled([]indexer.EventSink{}))
@@ -71,13 +71,8 @@ func TestIndexerServiceIndexesBlocks(t *testing.T) {
assert.True(t, indexer.IndexingEnabled(eventSinks))
service := NewIndexerService(eventSinks, eventBus)
err = service.Start()
require.NoError(t, err)
t.Cleanup(func() {
if err := service.Stop(); err != nil {
t.Error(err)
}
})
require.NoError(t, service.Start(ctx))
t.Cleanup(service.Wait)
// publish block with txs
err = eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{
@@ -143,6 +143,9 @@ func TestType(t *testing.T) {
}
func TestIndexing(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
t.Run("IndexBlockEvents", func(t *testing.T) {
indexer := &EventSink{store: testDB(), chainID: chainID}
require.NoError(t, indexer.IndexBlockEvents(newTestBlockHeader()))
@@ -154,7 +157,7 @@ func TestIndexing(t *testing.T) {
verifyNotImplemented(t, "hasBlock", func() (bool, error) { return indexer.HasBlock(2) })
verifyNotImplemented(t, "block search", func() (bool, error) {
v, err := indexer.SearchBlockEvents(context.Background(), nil)
v, err := indexer.SearchBlockEvents(ctx, nil)
return v != nil, err
})
@@ -188,7 +191,7 @@ func TestIndexing(t *testing.T) {
return txr != nil, err
})
verifyNotImplemented(t, "tx search", func() (bool, error) {
txr, err := indexer.SearchTxEvents(context.Background(), nil)
txr, err := indexer.SearchTxEvents(ctx, nil)
return txr != nil, err
})
+3 -1
View File
@@ -310,6 +310,8 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) {
}
func TestProposerFrequency(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// some explicit test cases
testCases := []struct {
@@ -370,7 +372,7 @@ func TestProposerFrequency(t *testing.T) {
votePower := int64(mrand.Int()%maxPower) + 1
totalVotePower += votePower
privVal := types.NewMockPV()
pubKey, err := privVal.GetPubKey(context.Background())
pubKey, err := privVal.GetPubKey(ctx)
require.NoError(t, err)
val := types.NewValidator(pubKey, votePower)
val.ProposerPriority = mrand.Int63()
+15 -9
View File
@@ -28,9 +28,11 @@ import (
const validationTestsStopHeight int64 = 10
func TestValidateBlockHeader(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
proxyApp := newTestApp()
require.NoError(t, proxyApp.Start())
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
require.NoError(t, proxyApp.Start(ctx))
state, stateDB, privVals := makeState(3, 1)
stateStore := sm.NewStore(stateDB)
@@ -115,9 +117,11 @@ func TestValidateBlockHeader(t *testing.T) {
}
func TestValidateBlockCommit(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
proxyApp := newTestApp()
require.NoError(t, proxyApp.Start())
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
require.NoError(t, proxyApp.Start(ctx))
state, stateDB, privVals := makeState(1, 1)
stateStore := sm.NewStore(stateDB)
@@ -207,7 +211,7 @@ func TestValidateBlockCommit(t *testing.T) {
)
require.NoError(t, err, "height %d", height)
bpvPubKey, err := badPrivVal.GetPubKey(context.Background())
bpvPubKey, err := badPrivVal.GetPubKey(ctx)
require.NoError(t, err)
badVote := &types.Vote{
@@ -223,9 +227,9 @@ func TestValidateBlockCommit(t *testing.T) {
g := goodVote.ToProto()
b := badVote.ToProto()
err = badPrivVal.SignVote(context.Background(), chainID, g)
err = badPrivVal.SignVote(ctx, chainID, g)
require.NoError(t, err, "height %d", height)
err = badPrivVal.SignVote(context.Background(), chainID, b)
err = badPrivVal.SignVote(ctx, chainID, b)
require.NoError(t, err, "height %d", height)
goodVote.Signature, badVote.Signature = g.Signature, b.Signature
@@ -236,9 +240,11 @@ func TestValidateBlockCommit(t *testing.T) {
}
func TestValidateBlockEvidence(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
proxyApp := newTestApp()
require.NoError(t, proxyApp.Start())
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
require.NoError(t, proxyApp.Start(ctx))
state, stateDB, privVals := makeState(4, 1)
stateStore := sm.NewStore(stateDB)
+7 -1
View File
@@ -114,6 +114,10 @@ func TestDispatcherProviders(t *testing.T) {
func TestPeerListBasic(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
peerList := newPeerList()
assert.Zero(t, peerList.Len())
numPeers := 10
@@ -199,6 +203,9 @@ func TestEmptyPeerListReturnsWhenContextCanceled(t *testing.T) {
func TestPeerListConcurrent(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
peerList := newPeerList()
numPeers := 10
@@ -229,7 +236,6 @@ func TestPeerListConcurrent(t *testing.T) {
// we use a context with cancel and a separate go routine to wait for all
// the other goroutines to close.
ctx, cancel := context.WithCancel(context.Background())
go func() { wg.Wait(); cancel() }()
select {
+13 -36
View File
@@ -210,15 +210,11 @@ func NewReactor(
// handle individual envelopes as to not have to deal with bounding workers or pools.
// The caller must be sure to execute OnStop to ensure the outbound p2p Channels are
// closed. No error is returned.
func (r *Reactor) OnStart() error {
go r.processSnapshotCh()
go r.processChunkCh()
go r.processBlockCh()
go r.processParamsCh()
func (r *Reactor) OnStart(ctx context.Context) error {
go r.processCh(r.snapshotCh, "snapshot")
go r.processCh(r.chunkCh, "chunk")
go r.processCh(r.blockCh, "light block")
go r.processCh(r.paramsCh, "consensus params")
go r.processPeerUpdates()
return nil
@@ -607,7 +603,7 @@ func (r *Reactor) handleChunkMessage(envelope p2p.Envelope) error {
"chunk", msg.Index,
"peer", envelope.From,
)
resp, err := r.conn.LoadSnapshotChunkSync(context.Background(), abci.RequestLoadSnapshotChunk{
resp, err := r.conn.LoadSnapshotChunkSync(context.TODO(), abci.RequestLoadSnapshotChunk{
Height: msg.Height,
Format: msg.Format,
Chunk: msg.Index,
@@ -815,28 +811,6 @@ func (r *Reactor) handleMessage(chID p2p.ChannelID, envelope p2p.Envelope) (err
return err
}
// processSnapshotCh initiates a blocking process where we listen for and handle
// envelopes on the SnapshotChannel.
func (r *Reactor) processSnapshotCh() {
r.processCh(r.snapshotCh, "snapshot")
}
// processChunkCh initiates a blocking process where we listen for and handle
// envelopes on the ChunkChannel.
func (r *Reactor) processChunkCh() {
r.processCh(r.chunkCh, "chunk")
}
// processBlockCh initiates a blocking process where we listen for and handle
// envelopes on the LightBlockChannel.
func (r *Reactor) processBlockCh() {
r.processCh(r.blockCh, "light block")
}
func (r *Reactor) processParamsCh() {
r.processCh(r.paramsCh, "consensus params")
}
// processCh routes state sync messages to their respective handlers. Any error
// encountered during message execution will result in a PeerError being sent on
// the respective channel. When the reactor is stopped, we will catch the signal
@@ -848,8 +822,11 @@ func (r *Reactor) processCh(ch *p2p.Channel, chName string) {
select {
case envelope := <-ch.In:
if err := r.handleMessage(ch.ID, envelope); err != nil {
r.Logger.Error(fmt.Sprintf("failed to process %s message", chName),
"ch_id", ch.ID, "envelope", envelope, "err", err)
r.Logger.Error("failed to process message",
"err", err,
"channel", chName,
"ch_id", ch.ID,
"envelope", envelope)
ch.Error <- p2p.PeerError{
NodeID: envelope.From,
Err: err,
@@ -857,7 +834,7 @@ func (r *Reactor) processCh(ch *p2p.Channel, chName string) {
}
case <-r.closeCh:
r.Logger.Debug(fmt.Sprintf("stopped listening on %s channel; closing...", chName))
r.Logger.Debug("channel closed", "channel", chName)
return
}
}
@@ -923,7 +900,7 @@ func (r *Reactor) processPeerUpdates() {
// recentSnapshots fetches the n most recent snapshots from the app
func (r *Reactor) recentSnapshots(n uint32) ([]*snapshot, error) {
resp, err := r.conn.ListSnapshotsSync(context.Background(), abci.RequestListSnapshots{})
resp, err := r.conn.ListSnapshotsSync(context.TODO(), abci.RequestListSnapshots{})
if err != nil {
return nil, err
}
+81 -36
View File
@@ -69,6 +69,7 @@ type reactorTestSuite struct {
}
func setup(
ctx context.Context,
t *testing.T,
conn *proxymocks.AppConnSnapshot,
connQuery *proxymocks.AppConnQuery,
@@ -176,11 +177,11 @@ func setup(
rts.reactor.metrics,
)
require.NoError(t, rts.reactor.Start())
require.NoError(t, rts.reactor.Start(ctx))
require.True(t, rts.reactor.IsRunning())
t.Cleanup(func() {
require.NoError(t, rts.reactor.Stop())
rts.reactor.Wait()
require.False(t, rts.reactor.IsRunning())
})
@@ -188,8 +189,11 @@ func setup(
}
func TestReactor_Sync(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
const snapshotHeight = 7
rts := setup(t, nil, nil, nil, 2)
rts := setup(ctx, t, nil, nil, nil, 2)
chain := buildLightBlockChain(t, 1, 10, time.Now())
// app accepts any snapshot
rts.conn.On("OfferSnapshotSync", ctx, mock.AnythingOfType("types.RequestOfferSnapshot")).
@@ -200,7 +204,7 @@ func TestReactor_Sync(t *testing.T) {
Return(&abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}, nil)
// app query returns valid state app hash
rts.connQuery.On("InfoSync", ctx, proxy.RequestInfo).Return(&abci.ResponseInfo{
rts.connQuery.On("InfoSync", mock.Anything, proxy.RequestInfo).Return(&abci.ResponseInfo{
AppVersion: 9,
LastBlockHeight: snapshotHeight,
LastBlockAppHash: chain[snapshotHeight+1].AppHash,
@@ -213,7 +217,7 @@ func TestReactor_Sync(t *testing.T) {
closeCh := make(chan struct{})
defer close(closeCh)
go handleLightBlockRequests(t, chain, rts.blockOutCh,
go handleLightBlockRequests(ctx, t, chain, rts.blockOutCh,
rts.blockInCh, closeCh, 0)
go graduallyAddPeers(rts.peerUpdateCh, closeCh, 1*time.Second)
go handleSnapshotRequests(t, rts.snapshotOutCh, rts.snapshotInCh, closeCh, []snapshot{
@@ -226,7 +230,7 @@ func TestReactor_Sync(t *testing.T) {
go handleChunkRequests(t, rts.chunkOutCh, rts.chunkInCh, closeCh, []byte("abc"))
go handleConsensusParamsRequest(t, rts.paramsOutCh, rts.paramsInCh, closeCh)
go handleConsensusParamsRequest(ctx, t, rts.paramsOutCh, rts.paramsInCh, closeCh)
// update the config to use the p2p provider
rts.reactor.cfg.UseP2P = true
@@ -235,12 +239,15 @@ func TestReactor_Sync(t *testing.T) {
rts.reactor.cfg.DiscoveryTime = 1 * time.Second
// Run state sync
_, err := rts.reactor.Sync(context.Background())
_, err := rts.reactor.Sync(ctx)
require.NoError(t, err)
}
func TestReactor_ChunkRequest_InvalidRequest(t *testing.T) {
rts := setup(t, nil, nil, nil, 2)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, nil, nil, nil, 2)
rts.chunkInCh <- p2p.Envelope{
From: types.NodeID("aa"),
@@ -282,19 +289,23 @@ func TestReactor_ChunkRequest(t *testing.T) {
},
}
for name, tc := range testcases {
tc := tc
bctx, bcancel := context.WithCancel(context.Background())
defer bcancel()
for name, tc := range testcases {
t.Run(name, func(t *testing.T) {
ctx, cancel := context.WithCancel(bctx)
defer cancel()
// mock ABCI connection to return local snapshots
conn := &proxymocks.AppConnSnapshot{}
conn.On("LoadSnapshotChunkSync", context.Background(), abci.RequestLoadSnapshotChunk{
conn.On("LoadSnapshotChunkSync", mock.Anything, abci.RequestLoadSnapshotChunk{
Height: tc.request.Height,
Format: tc.request.Format,
Chunk: tc.request.Index,
}).Return(&abci.ResponseLoadSnapshotChunk{Chunk: tc.chunk}, nil)
rts := setup(t, conn, nil, nil, 2)
rts := setup(ctx, t, conn, nil, nil, 2)
rts.chunkInCh <- p2p.Envelope{
From: types.NodeID("aa"),
@@ -311,7 +322,10 @@ func TestReactor_ChunkRequest(t *testing.T) {
}
func TestReactor_SnapshotsRequest_InvalidRequest(t *testing.T) {
rts := setup(t, nil, nil, nil, 2)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, nil, nil, nil, 2)
rts.snapshotInCh <- p2p.Envelope{
From: types.NodeID("aa"),
@@ -360,18 +374,23 @@ func TestReactor_SnapshotsRequest(t *testing.T) {
},
},
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for name, tc := range testcases {
tc := tc
t.Run(name, func(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// mock ABCI connection to return local snapshots
conn := &proxymocks.AppConnSnapshot{}
conn.On("ListSnapshotsSync", context.Background(), abci.RequestListSnapshots{}).Return(&abci.ResponseListSnapshots{
conn.On("ListSnapshotsSync", mock.Anything, abci.RequestListSnapshots{}).Return(&abci.ResponseListSnapshots{
Snapshots: tc.snapshots,
}, nil)
rts := setup(t, conn, nil, nil, 100)
rts := setup(ctx, t, conn, nil, nil, 100)
rts.snapshotInCh <- p2p.Envelope{
From: types.NodeID("aa"),
@@ -379,7 +398,7 @@ func TestReactor_SnapshotsRequest(t *testing.T) {
}
if len(tc.expectResponses) > 0 {
retryUntil(t, func() bool { return len(rts.snapshotOutCh) == len(tc.expectResponses) }, time.Second)
retryUntil(ctx, t, func() bool { return len(rts.snapshotOutCh) == len(tc.expectResponses) }, time.Second)
}
responses := make([]*ssproto.SnapshotsResponse, len(tc.expectResponses))
@@ -395,7 +414,10 @@ func TestReactor_SnapshotsRequest(t *testing.T) {
}
func TestReactor_LightBlockResponse(t *testing.T) {
rts := setup(t, nil, nil, nil, 2)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, nil, nil, nil, 2)
var height int64 = 10
h := factory.MakeRandomHeader()
@@ -448,7 +470,10 @@ func TestReactor_LightBlockResponse(t *testing.T) {
}
func TestReactor_BlockProviders(t *testing.T) {
rts := setup(t, nil, nil, nil, 2)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, nil, nil, nil, 2)
rts.peerUpdateCh <- p2p.PeerUpdate{
NodeID: types.NodeID("aa"),
Status: p2p.PeerStatusUp,
@@ -462,7 +487,7 @@ func TestReactor_BlockProviders(t *testing.T) {
defer close(closeCh)
chain := buildLightBlockChain(t, 1, 10, time.Now())
go handleLightBlockRequests(t, chain, rts.blockOutCh, rts.blockInCh, closeCh, 0)
go handleLightBlockRequests(ctx, t, chain, rts.blockOutCh, rts.blockInCh, closeCh, 0)
peers := rts.reactor.peers.All()
require.Len(t, peers, 2)
@@ -479,7 +504,7 @@ func TestReactor_BlockProviders(t *testing.T) {
go func(t *testing.T, p provider.Provider) {
defer wg.Done()
for height := 2; height < 10; height++ {
lb, err := p.LightBlock(context.Background(), int64(height))
lb, err := p.LightBlock(ctx, int64(height))
require.NoError(t, err)
require.NotNil(t, lb)
require.Equal(t, height, int(lb.Height))
@@ -487,7 +512,6 @@ func TestReactor_BlockProviders(t *testing.T) {
}(t, p)
}
ctx, cancel := context.WithCancel(context.Background())
go func() { wg.Wait(); cancel() }()
select {
@@ -501,7 +525,10 @@ func TestReactor_BlockProviders(t *testing.T) {
}
func TestReactor_StateProviderP2P(t *testing.T) {
rts := setup(t, nil, nil, nil, 2)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, nil, nil, nil, 2)
// make syncer non nil else test won't think we are state syncing
rts.reactor.syncer = rts.syncer
peerA := types.NodeID(strings.Repeat("a", 2*types.NodeIDByteLength))
@@ -519,8 +546,8 @@ func TestReactor_StateProviderP2P(t *testing.T) {
defer close(closeCh)
chain := buildLightBlockChain(t, 1, 10, time.Now())
go handleLightBlockRequests(t, chain, rts.blockOutCh, rts.blockInCh, closeCh, 0)
go handleConsensusParamsRequest(t, rts.paramsOutCh, rts.paramsInCh, closeCh)
go handleLightBlockRequests(ctx, t, chain, rts.blockOutCh, rts.blockInCh, closeCh, 0)
go handleConsensusParamsRequest(ctx, t, rts.paramsOutCh, rts.paramsInCh, closeCh)
rts.reactor.cfg.UseP2P = true
rts.reactor.cfg.TrustHeight = 1
@@ -533,10 +560,7 @@ func TestReactor_StateProviderP2P(t *testing.T) {
}
require.True(t, rts.reactor.peers.Len() >= 2, "peer network not configured")
bctx, cancel := context.WithCancel(context.Background())
defer cancel()
ictx, cancel := context.WithTimeout(bctx, time.Second)
ictx, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
rts.reactor.mtx.Lock()
@@ -545,7 +569,7 @@ func TestReactor_StateProviderP2P(t *testing.T) {
require.NoError(t, err)
rts.reactor.syncer.stateProvider = rts.reactor.stateProvider
actx, cancel := context.WithTimeout(bctx, 10*time.Second)
actx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
appHash, err := rts.reactor.stateProvider.AppHash(actx, 5)
@@ -569,13 +593,19 @@ func TestReactor_StateProviderP2P(t *testing.T) {
}
func TestReactor_Backfill(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// test backfill algorithm with varying failure rates [0, 10]
failureRates := []int{0, 2, 9}
for _, failureRate := range failureRates {
failureRate := failureRate
t.Run(fmt.Sprintf("failure rate: %d", failureRate), func(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
t.Cleanup(leaktest.CheckTimeout(t, 1*time.Minute))
rts := setup(t, nil, nil, nil, 21)
rts := setup(ctx, t, nil, nil, nil, 21)
var (
startHeight int64 = 20
@@ -605,11 +635,11 @@ func TestReactor_Backfill(t *testing.T) {
closeCh := make(chan struct{})
defer close(closeCh)
go handleLightBlockRequests(t, chain, rts.blockOutCh,
go handleLightBlockRequests(ctx, t, chain, rts.blockOutCh,
rts.blockInCh, closeCh, failureRate)
err := rts.reactor.backfill(
context.Background(),
ctx,
factory.DefaultTestChainID,
startHeight,
stopHeight,
@@ -644,8 +674,8 @@ func TestReactor_Backfill(t *testing.T) {
// retryUntil will continue to evaluate fn and will return successfully when true
// or fail when the timeout is reached.
func retryUntil(t *testing.T, fn func() bool, timeout time.Duration) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
func retryUntil(ctx context.Context, t *testing.T, fn func() bool, timeout time.Duration) {
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
for {
@@ -656,7 +686,9 @@ func retryUntil(t *testing.T, fn func() bool, timeout time.Duration) {
}
}
func handleLightBlockRequests(t *testing.T,
func handleLightBlockRequests(
ctx context.Context,
t *testing.T,
chain map[int64]*types.LightBlock,
receiving chan p2p.Envelope,
sending chan p2p.Envelope,
@@ -666,6 +698,8 @@ func handleLightBlockRequests(t *testing.T,
errorCount := 0
for {
select {
case <-ctx.Done():
return
case envelope := <-receiving:
if msg, ok := envelope.Message.(*ssproto.LightBlockRequest); ok {
if requests%10 >= failureRate {
@@ -709,13 +743,24 @@ func handleLightBlockRequests(t *testing.T,
}
}
func handleConsensusParamsRequest(t *testing.T, receiving, sending chan p2p.Envelope, closeCh chan struct{}) {
func handleConsensusParamsRequest(
ctx context.Context,
t *testing.T,
receiving, sending chan p2p.Envelope,
closeCh chan struct{},
) {
t.Helper()
params := types.DefaultConsensusParams()
paramsProto := params.ToProto()
for {
select {
case <-ctx.Done():
return
case envelope := <-receiving:
if ctx.Err() != nil {
return
}
t.Log("received consensus params request")
msg, ok := envelope.Message.(*ssproto.ParamsRequest)
require.True(t, ok)
+1 -1
View File
@@ -565,7 +565,7 @@ func (s *syncer) requestChunk(snapshot *snapshot, chunk uint32) {
// verifyApp verifies the sync, checking the app hash and last block height. It returns the
// app version, which should be returned as part of the initial state.
func (s *syncer) verifyApp(snapshot *snapshot) (uint64, error) {
resp, err := s.connQuery.InfoSync(context.Background(), proxy.RequestInfo)
resp, err := s.connQuery.InfoSync(context.TODO(), proxy.RequestInfo)
if err != nil {
return 0, fmt.Errorf("failed to query ABCI app for appHash: %w", err)
}
+92 -41
View File
@@ -22,9 +22,10 @@ import (
"github.com/tendermint/tendermint/version"
)
var ctx = context.Background()
func TestSyncer_SyncAny(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
state := sm.State{
ChainID: "chain",
Version: sm.Version{
@@ -68,7 +69,7 @@ func TestSyncer_SyncAny(t *testing.T) {
peerAID := types.NodeID("aa")
peerBID := types.NodeID("bb")
peerCID := types.NodeID("cc")
rts := setup(t, connSnapshot, connQuery, stateProvider, 3)
rts := setup(ctx, t, connSnapshot, connQuery, stateProvider, 3)
rts.reactor.syncer = rts.syncer
@@ -110,7 +111,7 @@ func TestSyncer_SyncAny(t *testing.T) {
// We start a sync, with peers sending back chunks when requested. We first reject the snapshot
// with height 2 format 2, and accept the snapshot at height 1.
connSnapshot.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
connSnapshot.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: &abci.Snapshot{
Height: 2,
Format: 2,
@@ -119,7 +120,7 @@ func TestSyncer_SyncAny(t *testing.T) {
},
AppHash: []byte("app_hash_2"),
}).Return(&abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT_FORMAT}, nil)
connSnapshot.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
connSnapshot.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: &abci.Snapshot{
Height: s.Height,
Format: s.Format,
@@ -160,7 +161,7 @@ func TestSyncer_SyncAny(t *testing.T) {
// The first time we're applying chunk 2 we tell it to retry the snapshot and discard chunk 1,
// which should cause it to keep the existing chunk 0 and 2, and restart restoration from
// beginning. We also wait for a little while, to exercise the retry logic in fetchChunks().
connSnapshot.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
connSnapshot.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 2, Chunk: []byte{1, 1, 2},
}).Once().Run(func(args mock.Arguments) { time.Sleep(2 * time.Second) }).Return(
&abci.ResponseApplySnapshotChunk{
@@ -168,16 +169,16 @@ func TestSyncer_SyncAny(t *testing.T) {
RefetchChunks: []uint32{1},
}, nil)
connSnapshot.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
connSnapshot.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 0, Chunk: []byte{1, 1, 0},
}).Times(2).Return(&abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}, nil)
connSnapshot.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
connSnapshot.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 1, Chunk: []byte{1, 1, 1},
}).Times(2).Return(&abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}, nil)
connSnapshot.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
connSnapshot.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 2, Chunk: []byte{1, 1, 2},
}).Once().Return(&abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}, nil)
connQuery.On("InfoSync", ctx, proxy.RequestInfo).Return(&abci.ResponseInfo{
connQuery.On("InfoSync", mock.Anything, proxy.RequestInfo).Return(&abci.ResponseInfo{
AppVersion: 9,
LastBlockHeight: 1,
LastBlockAppHash: []byte("app_hash"),
@@ -217,7 +218,10 @@ func TestSyncer_SyncAny_noSnapshots(t *testing.T) {
stateProvider := &mocks.StateProvider{}
stateProvider.On("AppHash", mock.Anything, mock.Anything).Return([]byte("app_hash"), nil)
rts := setup(t, nil, nil, stateProvider, 2)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, nil, nil, stateProvider, 2)
_, _, err := rts.syncer.SyncAny(ctx, 0, func() {})
require.Equal(t, errNoSnapshots, err)
@@ -227,7 +231,10 @@ func TestSyncer_SyncAny_abort(t *testing.T) {
stateProvider := &mocks.StateProvider{}
stateProvider.On("AppHash", mock.Anything, mock.Anything).Return([]byte("app_hash"), nil)
rts := setup(t, nil, nil, stateProvider, 2)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, nil, nil, stateProvider, 2)
s := &snapshot{Height: 1, Format: 1, Chunks: 3, Hash: []byte{1, 2, 3}}
peerID := types.NodeID("aa")
@@ -235,7 +242,7 @@ func TestSyncer_SyncAny_abort(t *testing.T) {
_, err := rts.syncer.AddSnapshot(peerID, s)
require.NoError(t, err)
rts.conn.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
rts.conn.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: toABCI(s), AppHash: []byte("app_hash"),
}).Once().Return(&abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ABORT}, nil)
@@ -248,7 +255,10 @@ func TestSyncer_SyncAny_reject(t *testing.T) {
stateProvider := &mocks.StateProvider{}
stateProvider.On("AppHash", mock.Anything, mock.Anything).Return([]byte("app_hash"), nil)
rts := setup(t, nil, nil, stateProvider, 2)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, nil, nil, stateProvider, 2)
// s22 is tried first, then s12, then s11, then errNoSnapshots
s22 := &snapshot{Height: 2, Format: 2, Chunks: 3, Hash: []byte{1, 2, 3}}
@@ -266,15 +276,15 @@ func TestSyncer_SyncAny_reject(t *testing.T) {
_, err = rts.syncer.AddSnapshot(peerID, s11)
require.NoError(t, err)
rts.conn.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
rts.conn.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: toABCI(s22), AppHash: []byte("app_hash"),
}).Once().Return(&abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}, nil)
rts.conn.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
rts.conn.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: toABCI(s12), AppHash: []byte("app_hash"),
}).Once().Return(&abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}, nil)
rts.conn.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
rts.conn.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: toABCI(s11), AppHash: []byte("app_hash"),
}).Once().Return(&abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}, nil)
@@ -287,7 +297,10 @@ func TestSyncer_SyncAny_reject_format(t *testing.T) {
stateProvider := &mocks.StateProvider{}
stateProvider.On("AppHash", mock.Anything, mock.Anything).Return([]byte("app_hash"), nil)
rts := setup(t, nil, nil, stateProvider, 2)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, nil, nil, stateProvider, 2)
// s22 is tried first, which reject s22 and s12, then s11 will abort.
s22 := &snapshot{Height: 2, Format: 2, Chunks: 3, Hash: []byte{1, 2, 3}}
@@ -305,11 +318,11 @@ func TestSyncer_SyncAny_reject_format(t *testing.T) {
_, err = rts.syncer.AddSnapshot(peerID, s11)
require.NoError(t, err)
rts.conn.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
rts.conn.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: toABCI(s22), AppHash: []byte("app_hash"),
}).Once().Return(&abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT_FORMAT}, nil)
rts.conn.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
rts.conn.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: toABCI(s11), AppHash: []byte("app_hash"),
}).Once().Return(&abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ABORT}, nil)
@@ -322,7 +335,10 @@ func TestSyncer_SyncAny_reject_sender(t *testing.T) {
stateProvider := &mocks.StateProvider{}
stateProvider.On("AppHash", mock.Anything, mock.Anything).Return([]byte("app_hash"), nil)
rts := setup(t, nil, nil, stateProvider, 2)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, nil, nil, stateProvider, 2)
peerAID := types.NodeID("aa")
peerBID := types.NodeID("bb")
@@ -351,11 +367,11 @@ func TestSyncer_SyncAny_reject_sender(t *testing.T) {
_, err = rts.syncer.AddSnapshot(peerCID, sbc)
require.NoError(t, err)
rts.conn.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
rts.conn.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: toABCI(sbc), AppHash: []byte("app_hash"),
}).Once().Return(&abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT_SENDER}, nil)
rts.conn.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
rts.conn.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: toABCI(sa), AppHash: []byte("app_hash"),
}).Once().Return(&abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}, nil)
@@ -368,7 +384,10 @@ func TestSyncer_SyncAny_abciError(t *testing.T) {
stateProvider := &mocks.StateProvider{}
stateProvider.On("AppHash", mock.Anything, mock.Anything).Return([]byte("app_hash"), nil)
rts := setup(t, nil, nil, stateProvider, 2)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rts := setup(ctx, t, nil, nil, stateProvider, 2)
errBoom := errors.New("boom")
s := &snapshot{Height: 1, Format: 1, Chunks: 3, Hash: []byte{1, 2, 3}}
@@ -378,7 +397,7 @@ func TestSyncer_SyncAny_abciError(t *testing.T) {
_, err := rts.syncer.AddSnapshot(peerID, s)
require.NoError(t, err)
rts.conn.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
rts.conn.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: toABCI(s), AppHash: []byte("app_hash"),
}).Once().Return(nil, errBoom)
@@ -405,16 +424,23 @@ func TestSyncer_offerSnapshot(t *testing.T) {
"error": {0, boom, boom},
"unknown non-zero": {9, nil, unknownErr},
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for name, tc := range testcases {
tc := tc
t.Run(name, func(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
stateProvider := &mocks.StateProvider{}
stateProvider.On("AppHash", mock.Anything, mock.Anything).Return([]byte("app_hash"), nil)
rts := setup(t, nil, nil, stateProvider, 2)
rts := setup(ctx, t, nil, nil, stateProvider, 2)
s := &snapshot{Height: 1, Format: 1, Chunks: 3, Hash: []byte{1, 2, 3}, trustedAppHash: []byte("app_hash")}
rts.conn.On("OfferSnapshotSync", ctx, abci.RequestOfferSnapshot{
rts.conn.On("OfferSnapshotSync", mock.Anything, abci.RequestOfferSnapshot{
Snapshot: toABCI(s),
AppHash: []byte("app_hash"),
}).Return(&abci.ResponseOfferSnapshot{Result: tc.result}, tc.err)
@@ -451,13 +477,20 @@ func TestSyncer_applyChunks_Results(t *testing.T) {
"error": {0, boom, boom},
"unknown non-zero": {9, nil, unknownErr},
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for name, tc := range testcases {
tc := tc
t.Run(name, func(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
stateProvider := &mocks.StateProvider{}
stateProvider.On("AppHash", mock.Anything, mock.Anything).Return([]byte("app_hash"), nil)
rts := setup(t, nil, nil, stateProvider, 2)
rts := setup(ctx, t, nil, nil, stateProvider, 2)
body := []byte{1, 2, 3}
chunks, err := newChunkQueue(&snapshot{Height: 1, Format: 1, Chunks: 1}, "")
@@ -468,11 +501,11 @@ func TestSyncer_applyChunks_Results(t *testing.T) {
_, err = chunks.Add(&chunk{Height: 1, Format: 1, Index: 0, Chunk: body})
require.NoError(t, err)
rts.conn.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
rts.conn.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 0, Chunk: body,
}).Once().Return(&abci.ResponseApplySnapshotChunk{Result: tc.result}, tc.err)
if tc.result == abci.ResponseApplySnapshotChunk_RETRY {
rts.conn.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
rts.conn.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 0, Chunk: body,
}).Once().Return(&abci.ResponseApplySnapshotChunk{
Result: abci.ResponseApplySnapshotChunk_ACCEPT}, nil)
@@ -505,13 +538,19 @@ func TestSyncer_applyChunks_RefetchChunks(t *testing.T) {
"retry_snapshot": {abci.ResponseApplySnapshotChunk_RETRY_SNAPSHOT},
"reject_snapshot": {abci.ResponseApplySnapshotChunk_REJECT_SNAPSHOT},
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for name, tc := range testcases {
tc := tc
t.Run(name, func(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
stateProvider := &mocks.StateProvider{}
stateProvider.On("AppHash", mock.Anything, mock.Anything).Return([]byte("app_hash"), nil)
rts := setup(t, nil, nil, stateProvider, 2)
rts := setup(ctx, t, nil, nil, stateProvider, 2)
chunks, err := newChunkQueue(&snapshot{Height: 1, Format: 1, Chunks: 3}, "")
require.NoError(t, err)
@@ -529,13 +568,13 @@ func TestSyncer_applyChunks_RefetchChunks(t *testing.T) {
require.NoError(t, err)
// The first two chunks are accepted, before the last one asks for 1 to be refetched
rts.conn.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
rts.conn.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 0, Chunk: []byte{0},
}).Once().Return(&abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}, nil)
rts.conn.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
rts.conn.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 1, Chunk: []byte{1},
}).Once().Return(&abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}, nil)
rts.conn.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
rts.conn.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 2, Chunk: []byte{2},
}).Once().Return(&abci.ResponseApplySnapshotChunk{
Result: tc.result,
@@ -570,13 +609,19 @@ func TestSyncer_applyChunks_RejectSenders(t *testing.T) {
"retry_snapshot": {abci.ResponseApplySnapshotChunk_RETRY_SNAPSHOT},
"reject_snapshot": {abci.ResponseApplySnapshotChunk_REJECT_SNAPSHOT},
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for name, tc := range testcases {
tc := tc
t.Run(name, func(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
stateProvider := &mocks.StateProvider{}
stateProvider.On("AppHash", mock.Anything, mock.Anything).Return([]byte("app_hash"), nil)
rts := setup(t, nil, nil, stateProvider, 2)
rts := setup(ctx, t, nil, nil, stateProvider, 2)
// Set up three peers across two snapshots, and ask for one of them to be banned.
// It should be banned from all snapshots.
@@ -623,13 +668,13 @@ func TestSyncer_applyChunks_RejectSenders(t *testing.T) {
require.NoError(t, err)
// The first two chunks are accepted, before the last one asks for b sender to be rejected
rts.conn.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
rts.conn.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 0, Chunk: []byte{0}, Sender: "aa",
}).Once().Return(&abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}, nil)
rts.conn.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
rts.conn.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 1, Chunk: []byte{1}, Sender: "bb",
}).Once().Return(&abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}, nil)
rts.conn.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
rts.conn.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 2, Chunk: []byte{2}, Sender: "cc",
}).Once().Return(&abci.ResponseApplySnapshotChunk{
Result: tc.result,
@@ -638,7 +683,7 @@ func TestSyncer_applyChunks_RejectSenders(t *testing.T) {
// On retry, the last chunk will be tried again, so we just accept it then.
if tc.result == abci.ResponseApplySnapshotChunk_RETRY {
rts.conn.On("ApplySnapshotChunkSync", ctx, abci.RequestApplySnapshotChunk{
rts.conn.On("ApplySnapshotChunkSync", mock.Anything, abci.RequestApplySnapshotChunk{
Index: 2, Chunk: []byte{2}, Sender: "cc",
}).Once().Return(&abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}, nil)
}
@@ -693,12 +738,18 @@ func TestSyncer_verifyApp(t *testing.T) {
}, nil, errVerifyFailed},
"error": {nil, boom, boom},
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for name, tc := range testcases {
tc := tc
t.Run(name, func(t *testing.T) {
rts := setup(t, nil, nil, nil, 2)
ctx, cancel := context.WithCancel(ctx)
defer cancel()
rts.connQuery.On("InfoSync", ctx, proxy.RequestInfo).Return(tc.response, tc.err)
rts := setup(ctx, t, nil, nil, nil, 2)
rts.connQuery.On("InfoSync", mock.Anything, proxy.RequestInfo).Return(tc.response, tc.err)
version, err := rts.syncer.verifyApp(s)
unwrapped := errors.Unwrap(err)
if unwrapped != nil {
+5 -1
View File
@@ -1,6 +1,7 @@
package events
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
@@ -8,8 +9,11 @@ import (
)
func TestEventCache_Flush(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
evsw := NewEventSwitch()
err := evsw.Start()
err := evsw.Start(ctx)
require.NoError(t, err)
err = evsw.AddListenerForEvent("nothingness", "", func(data EventData) {
+3 -1
View File
@@ -2,6 +2,7 @@
package events
import (
"context"
"fmt"
tmsync "github.com/tendermint/tendermint/internal/libs/sync"
@@ -45,6 +46,7 @@ type Fireable interface {
type EventSwitch interface {
service.Service
Fireable
Stop() error
AddListenerForEvent(listenerID, eventValue string, cb EventCallback) error
RemoveListenerForEvent(event string, listenerID string)
@@ -68,7 +70,7 @@ func NewEventSwitch() EventSwitch {
return evsw
}
func (evsw *eventSwitch) OnStart() error {
func (evsw *eventSwitch) OnStart(ctx context.Context) error {
return nil
}
+80 -118
View File
@@ -1,6 +1,7 @@
package events
import (
"context"
"fmt"
"testing"
"time"
@@ -14,23 +15,20 @@ import (
// TestAddListenerForEventFireOnce sets up an EventSwitch, subscribes a single
// listener to an event, and sends a string "data".
func TestAddListenerForEventFireOnce(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
evsw := NewEventSwitch()
err := evsw.Start()
require.NoError(t, err)
t.Cleanup(func() {
if err := evsw.Stop(); err != nil {
t.Error(err)
}
})
require.NoError(t, evsw.Start(ctx))
t.Cleanup(evsw.Wait)
messages := make(chan EventData)
err = evsw.AddListenerForEvent("listener", "event",
require.NoError(t, evsw.AddListenerForEvent("listener", "event",
func(data EventData) {
// test there's no deadlock if we remove the listener inside a callback
evsw.RemoveListener("listener")
messages <- data
})
require.NoError(t, err)
}))
go evsw.FireEvent("event", "data")
received := <-messages
if received != "data" {
@@ -41,24 +39,21 @@ func TestAddListenerForEventFireOnce(t *testing.T) {
// TestAddListenerForEventFireMany sets up an EventSwitch, subscribes a single
// listener to an event, and sends a thousand integers.
func TestAddListenerForEventFireMany(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
evsw := NewEventSwitch()
err := evsw.Start()
require.NoError(t, err)
t.Cleanup(func() {
if err := evsw.Stop(); err != nil {
t.Error(err)
}
})
require.NoError(t, evsw.Start(ctx))
t.Cleanup(evsw.Wait)
doneSum := make(chan uint64)
doneSending := make(chan uint64)
numbers := make(chan uint64, 4)
// subscribe one listener for one event
err = evsw.AddListenerForEvent("listener", "event",
require.NoError(t, evsw.AddListenerForEvent("listener", "event",
func(data EventData) {
numbers <- data.(uint64)
})
require.NoError(t, err)
}))
// collect received events
go sumReceivedNumbers(numbers, doneSum)
// go fire events
@@ -75,14 +70,12 @@ func TestAddListenerForEventFireMany(t *testing.T) {
// listener to three different events and sends a thousand integers for each
// of the three events.
func TestAddListenerForDifferentEvents(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
evsw := NewEventSwitch()
err := evsw.Start()
require.NoError(t, err)
t.Cleanup(func() {
if err := evsw.Stop(); err != nil {
t.Error(err)
}
})
require.NoError(t, evsw.Start(ctx))
t.Cleanup(evsw.Wait)
doneSum := make(chan uint64)
doneSending1 := make(chan uint64)
@@ -90,21 +83,18 @@ func TestAddListenerForDifferentEvents(t *testing.T) {
doneSending3 := make(chan uint64)
numbers := make(chan uint64, 4)
// subscribe one listener to three events
err = evsw.AddListenerForEvent("listener", "event1",
require.NoError(t, evsw.AddListenerForEvent("listener", "event1",
func(data EventData) {
numbers <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener", "event2",
}))
require.NoError(t, evsw.AddListenerForEvent("listener", "event2",
func(data EventData) {
numbers <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener", "event3",
}))
require.NoError(t, evsw.AddListenerForEvent("listener", "event3",
func(data EventData) {
numbers <- data.(uint64)
})
require.NoError(t, err)
}))
// collect received events
go sumReceivedNumbers(numbers, doneSum)
// go fire events
@@ -127,15 +117,13 @@ func TestAddListenerForDifferentEvents(t *testing.T) {
// listener to two of those three events, and then sends a thousand integers
// for each of the three events.
func TestAddDifferentListenerForDifferentEvents(t *testing.T) {
evsw := NewEventSwitch()
err := evsw.Start()
require.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
t.Cleanup(func() {
if err := evsw.Stop(); err != nil {
t.Error(err)
}
})
evsw := NewEventSwitch()
require.NoError(t, evsw.Start(ctx))
t.Cleanup(evsw.Wait)
doneSum1 := make(chan uint64)
doneSum2 := make(chan uint64)
@@ -145,31 +133,26 @@ func TestAddDifferentListenerForDifferentEvents(t *testing.T) {
numbers1 := make(chan uint64, 4)
numbers2 := make(chan uint64, 4)
// subscribe two listener to three events
err = evsw.AddListenerForEvent("listener1", "event1",
require.NoError(t, evsw.AddListenerForEvent("listener1", "event1",
func(data EventData) {
numbers1 <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener1", "event2",
}))
require.NoError(t, evsw.AddListenerForEvent("listener1", "event2",
func(data EventData) {
numbers1 <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener1", "event3",
}))
require.NoError(t, evsw.AddListenerForEvent("listener1", "event3",
func(data EventData) {
numbers1 <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener2", "event2",
}))
require.NoError(t, evsw.AddListenerForEvent("listener2", "event2",
func(data EventData) {
numbers2 <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener2", "event3",
}))
require.NoError(t, evsw.AddListenerForEvent("listener2", "event3",
func(data EventData) {
numbers2 <- data.(uint64)
})
require.NoError(t, err)
}))
// collect received events for listener1
go sumReceivedNumbers(numbers1, doneSum1)
// collect received events for listener2
@@ -199,14 +182,12 @@ func TestAddAndRemoveListenerConcurrency(t *testing.T) {
roundCount = 2000
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
evsw := NewEventSwitch()
err := evsw.Start()
require.NoError(t, err)
t.Cleanup(func() {
if err := evsw.Stop(); err != nil {
t.Error(err)
}
})
require.NoError(t, evsw.Start(ctx))
t.Cleanup(evsw.Wait)
done1 := make(chan struct{})
done2 := make(chan struct{})
@@ -249,14 +230,12 @@ func TestAddAndRemoveListenerConcurrency(t *testing.T) {
// two events, fires a thousand integers for the first event, then unsubscribes
// the listener and fires a thousand integers for the second event.
func TestAddAndRemoveListener(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
evsw := NewEventSwitch()
err := evsw.Start()
require.NoError(t, err)
t.Cleanup(func() {
if err := evsw.Stop(); err != nil {
t.Error(err)
}
})
require.NoError(t, evsw.Start(ctx))
t.Cleanup(evsw.Wait)
doneSum1 := make(chan uint64)
doneSum2 := make(chan uint64)
@@ -265,16 +244,14 @@ func TestAddAndRemoveListener(t *testing.T) {
numbers1 := make(chan uint64, 4)
numbers2 := make(chan uint64, 4)
// subscribe two listener to three events
err = evsw.AddListenerForEvent("listener", "event1",
require.NoError(t, evsw.AddListenerForEvent("listener", "event1",
func(data EventData) {
numbers1 <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener", "event2",
}))
require.NoError(t, evsw.AddListenerForEvent("listener", "event2",
func(data EventData) {
numbers2 <- data.(uint64)
})
require.NoError(t, err)
}))
// collect received events for event1
go sumReceivedNumbers(numbers1, doneSum1)
// collect received events for event2
@@ -300,29 +277,23 @@ func TestAddAndRemoveListener(t *testing.T) {
// TestRemoveListener does basic tests on adding and removing
func TestRemoveListener(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
evsw := NewEventSwitch()
err := evsw.Start()
require.NoError(t, err)
t.Cleanup(func() {
if err := evsw.Stop(); err != nil {
t.Error(err)
}
})
require.NoError(t, evsw.Start(ctx))
t.Cleanup(evsw.Wait)
count := 10
sum1, sum2 := 0, 0
// add some listeners and make sure they work
err = evsw.AddListenerForEvent("listener", "event1",
require.NoError(t, evsw.AddListenerForEvent("listener", "event1",
func(data EventData) {
sum1++
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener", "event2",
}))
require.NoError(t, evsw.AddListenerForEvent("listener", "event2",
func(data EventData) {
sum2++
})
require.NoError(t, err)
}))
for i := 0; i < count; i++ {
evsw.FireEvent("event1", true)
@@ -361,14 +332,11 @@ func TestRemoveListener(t *testing.T) {
// NOTE: it is important to run this test with race conditions tracking on,
// `go test -race`, to examine for possible race conditions.
func TestRemoveListenersAsync(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
evsw := NewEventSwitch()
err := evsw.Start()
require.NoError(t, err)
t.Cleanup(func() {
if err := evsw.Stop(); err != nil {
t.Error(err)
}
})
require.NoError(t, evsw.Start(ctx))
t.Cleanup(evsw.Wait)
doneSum1 := make(chan uint64)
doneSum2 := make(chan uint64)
@@ -378,36 +346,30 @@ func TestRemoveListenersAsync(t *testing.T) {
numbers1 := make(chan uint64, 4)
numbers2 := make(chan uint64, 4)
// subscribe two listener to three events
err = evsw.AddListenerForEvent("listener1", "event1",
require.NoError(t, evsw.AddListenerForEvent("listener1", "event1",
func(data EventData) {
numbers1 <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener1", "event2",
}))
require.NoError(t, evsw.AddListenerForEvent("listener1", "event2",
func(data EventData) {
numbers1 <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener1", "event3",
}))
require.NoError(t, evsw.AddListenerForEvent("listener1", "event3",
func(data EventData) {
numbers1 <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener2", "event1",
}))
require.NoError(t, evsw.AddListenerForEvent("listener2", "event1",
func(data EventData) {
numbers2 <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener2", "event2",
}))
require.NoError(t, evsw.AddListenerForEvent("listener2", "event2",
func(data EventData) {
numbers2 <- data.(uint64)
})
require.NoError(t, err)
err = evsw.AddListenerForEvent("listener2", "event3",
}))
require.NoError(t, evsw.AddListenerForEvent("listener2", "event3",
func(data EventData) {
numbers2 <- data.(uint64)
})
require.NoError(t, err)
}))
// collect received events for event1
go sumReceivedNumbers(numbers1, doneSum1)
// collect received events for event2
+3 -2
View File
@@ -12,8 +12,9 @@ import (
)
func TestExample(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
sub := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
ClientID: "example-client",
+1 -1
View File
@@ -341,7 +341,7 @@ func (s *Server) OnStop() { s.stop() }
func (s *Server) Wait() { <-s.exited; s.BaseService.Wait() }
// OnStart implements Service.OnStart by starting the server.
func (s *Server) OnStart() error { s.run(); return nil }
func (s *Server) OnStart(ctx context.Context) error { s.run(); return nil }
// OnReset implements Service.OnReset. It has no effect for this service.
func (s *Server) OnReset() error { return nil }
+58 -34
View File
@@ -7,7 +7,6 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
@@ -20,8 +19,10 @@ const (
)
func TestSubscribeWithArgs(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
t.Run("DefaultLimit", func(t *testing.T) {
sub := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
@@ -47,8 +48,10 @@ func TestSubscribeWithArgs(t *testing.T) {
}
func TestObserver(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
done := make(chan struct{})
var got interface{}
@@ -65,8 +68,10 @@ func TestObserver(t *testing.T) {
}
func TestObserverErrors(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
require.Error(t, s.Observe(ctx, nil, query.Empty{}))
require.NoError(t, s.Observe(ctx, func(pubsub.Message) error { return nil }))
@@ -74,8 +79,10 @@ func TestObserverErrors(t *testing.T) {
}
func TestPublishDoesNotBlock(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
sub := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
ClientID: clientID,
@@ -100,8 +107,10 @@ func TestPublishDoesNotBlock(t *testing.T) {
}
func TestSubscribeErrors(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
t.Run("EmptyQueryErr", func(t *testing.T) {
_, err := s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{ClientID: clientID})
@@ -118,8 +127,10 @@ func TestSubscribeErrors(t *testing.T) {
}
func TestSlowSubscriber(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
sub := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
ClientID: clientID,
@@ -137,8 +148,10 @@ func TestSlowSubscriber(t *testing.T) {
}
func TestDifferentClients(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
sub1 := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
ClientID: "client-1",
@@ -188,8 +201,10 @@ func TestDifferentClients(t *testing.T) {
}
func TestSubscribeDuplicateKeys(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
testCases := []struct {
query string
@@ -241,8 +256,10 @@ func TestSubscribeDuplicateKeys(t *testing.T) {
}
func TestClientSubscribesTwice(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
q := query.MustParse("tm.events.type='NewBlock'")
events := []abci.Event{{
@@ -274,8 +291,10 @@ func TestClientSubscribesTwice(t *testing.T) {
}
func TestUnsubscribe(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
sub := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
ClientID: clientID,
@@ -296,8 +315,10 @@ func TestUnsubscribe(t *testing.T) {
}
func TestClientUnsubscribesTwice(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
ClientID: clientID,
@@ -315,8 +336,10 @@ func TestClientUnsubscribesTwice(t *testing.T) {
}
func TestResubscribe(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
args := pubsub.SubscribeArgs{
ClientID: clientID,
@@ -336,8 +359,10 @@ func TestResubscribe(t *testing.T) {
}
func TestUnsubscribeAll(t *testing.T) {
s := newTestServer(t)
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := newTestServer(ctx, t)
sub1 := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
ClientID: clientID,
@@ -364,28 +389,27 @@ func TestBufferCapacity(t *testing.T) {
require.Equal(t, 2, s.BufferCapacity())
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
require.NoError(t, s.Publish(ctx, "Nighthawk"))
require.NoError(t, s.Publish(ctx, "Sage"))
ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
ctx, cancel = context.WithTimeout(ctx, 100*time.Millisecond)
defer cancel()
require.ErrorIs(t, s.Publish(ctx, "Ironclad"), context.DeadlineExceeded)
}
func newTestServer(t testing.TB) *pubsub.Server {
func newTestServer(ctx context.Context, t testing.TB) *pubsub.Server {
t.Helper()
s := pubsub.NewServer(func(s *pubsub.Server) {
s.Logger = log.TestingLogger()
})
require.NoError(t, s.Start())
t.Cleanup(func() {
assert.NoError(t, s.Stop())
})
require.NoError(t, s.Start(ctx))
t.Cleanup(s.Wait)
return s
}
+44 -55
View File
@@ -1,8 +1,8 @@
package service
import (
"context"
"errors"
"fmt"
"sync/atomic"
"github.com/tendermint/tendermint/libs/log"
@@ -22,22 +22,10 @@ var (
// Service defines a service that can be started, stopped, and reset.
type Service interface {
// Start the service.
// If it's already started or stopped, will return an error.
// If OnStart() returns an error, it's returned by Start()
Start() error
OnStart() error
// Stop the service.
// If it's already stopped, will return an error.
// OnStop must never error.
Stop() error
OnStop()
// Reset the service.
// Panics by default - must be overwritten to enable reset.
Reset() error
OnReset() error
// Start is called to start the service, which should run until
// the context terminates. If the service is already running, Start
// must report an error.
Start(context.Context) error
// Return true if the service is running
IsRunning() bool
@@ -52,6 +40,18 @@ type Service interface {
Wait()
}
// Implementation describes the implementation that the
// BaseService implementation wraps.
type Implementation interface {
Service
// Called by the Services Start Method
OnStart(context.Context) error
// Called when the service's context is canceled.
OnStop()
}
/*
Classical-inheritance-style service declarations. Services can be started, then
stopped, then optionally restarted.
@@ -82,7 +82,7 @@ Typical usage:
return fs
}
func (fs *FooService) OnStart() error {
func (fs *FooService) OnStart(ctx context.Context) error {
fs.BaseService.OnStart() // Always call the overridden method.
// initialize private fields
// start subroutines, etc.
@@ -102,11 +102,11 @@ type BaseService struct {
quit chan struct{}
// The "subclass" of BaseService
impl Service
impl Implementation
}
// NewBaseService creates a new BaseService.
func NewBaseService(logger log.Logger, name string, impl Service) *BaseService {
func NewBaseService(logger log.Logger, name string, impl Implementation) *BaseService {
if logger == nil {
logger = log.NewNopLogger()
}
@@ -119,10 +119,10 @@ func NewBaseService(logger log.Logger, name string, impl Service) *BaseService {
}
}
// Start implements Service by calling OnStart (if defined). An error will be
// returned if the service is already running or stopped. Not to start the
// stopped service, you need to call Reset.
func (bs *BaseService) Start() error {
// Start starts the Service and calls its OnStart method. An error will be
// returned if the service is already running or stopped. To restart a
// stopped service, call Reset.
func (bs *BaseService) Start(ctx context.Context) error {
if atomic.CompareAndSwapUint32(&bs.started, 0, 1) {
if atomic.LoadUint32(&bs.stopped) == 1 {
bs.Logger.Error("not starting service; already stopped", "service", bs.name, "impl", bs.impl.String())
@@ -132,11 +132,26 @@ func (bs *BaseService) Start() error {
bs.Logger.Info("starting service", "service", bs.name, "impl", bs.impl.String())
if err := bs.impl.OnStart(); err != nil {
if err := bs.impl.OnStart(ctx); err != nil {
// revert flag
atomic.StoreUint32(&bs.started, 0)
return err
}
go func(ctx context.Context) {
<-ctx.Done()
if err := bs.Stop(); err != nil {
bs.Logger.Error("stopped service",
"err", err.Error(),
"service", bs.name,
"impl", bs.impl.String())
}
bs.Logger.Info("stopped service",
"service", bs.name,
"impl", bs.impl.String())
}(ctx)
return nil
}
@@ -147,7 +162,7 @@ func (bs *BaseService) Start() error {
// OnStart implements Service by doing nothing.
// NOTE: Do not put anything in here,
// that way users don't need to call BaseService.OnStart()
func (bs *BaseService) OnStart() error { return nil }
func (bs *BaseService) OnStart(ctx context.Context) error { return nil }
// Stop implements Service by calling OnStop (if defined) and closing quit
// channel. An error will be returned if the service is already stopped.
@@ -175,26 +190,6 @@ func (bs *BaseService) Stop() error {
// that way users don't need to call BaseService.OnStop()
func (bs *BaseService) OnStop() {}
// Reset implements Service by calling OnReset callback (if defined). An error
// will be returned if the service is running.
func (bs *BaseService) Reset() error {
if !atomic.CompareAndSwapUint32(&bs.stopped, 1, 0) {
bs.Logger.Debug("cannot reset service; not stopped", "service", bs.name, "impl", bs.impl.String())
return fmt.Errorf("can't reset running %s", bs.name)
}
// whether or not we've started, we can reset
atomic.CompareAndSwapUint32(&bs.started, 1, 0)
bs.quit = make(chan struct{})
return bs.impl.OnReset()
}
// OnReset implements Service by panicking.
func (bs *BaseService) OnReset() error {
panic("The service cannot be reset")
}
// IsRunning implements Service by returning true or false depending on the
// service's state.
func (bs *BaseService) IsRunning() bool {
@@ -202,16 +197,10 @@ func (bs *BaseService) IsRunning() bool {
}
// Wait blocks until the service is stopped.
func (bs *BaseService) Wait() {
<-bs.quit
}
func (bs *BaseService) Wait() { <-bs.quit }
// String implements Service by returning a string representation of the service.
func (bs *BaseService) String() string {
return bs.name
}
func (bs *BaseService) String() string { return bs.name }
// Quit Implements Service by returning a quit channel.
func (bs *BaseService) Quit() <-chan struct{} {
return bs.quit
}
func (bs *BaseService) Quit() <-chan struct{} { return bs.quit }
+5 -20
View File
@@ -1,6 +1,7 @@
package service
import (
"context"
"testing"
"time"
@@ -16,9 +17,12 @@ func (testService) OnReset() error {
}
func TestBaseServiceWait(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ts := &testService{}
ts.BaseService = *NewBaseService(nil, "TestService", ts)
err := ts.Start()
err := ts.Start(ctx)
require.NoError(t, err)
waitFinished := make(chan struct{})
@@ -36,22 +40,3 @@ func TestBaseServiceWait(t *testing.T) {
t.Fatal("expected Wait() to finish within 100 ms.")
}
}
func TestBaseServiceReset(t *testing.T) {
ts := &testService{}
ts.BaseService = *NewBaseService(nil, "TestService", ts)
err := ts.Start()
require.NoError(t, err)
err = ts.Reset()
require.Error(t, err, "expected cant reset service error")
err = ts.Stop()
require.NoError(t, err)
err = ts.Reset()
require.NoError(t, err)
err = ts.Start()
require.NoError(t, err)
}
+4
View File
@@ -55,6 +55,10 @@ func SplitAndTrim(s, sep, cutset string) []string {
return spl
}
// TrimSpace removes all leading and trailing whitespace from the
// string.
func TrimSpace(s string) string { return strings.TrimSpace(s) }
// Returns true if s is a non-empty printable non-tab ascii character.
func IsASCIIText(s string) bool {
if len(s) == 0 {
+6 -6
View File
@@ -49,8 +49,8 @@ func NewProxy(
// routes to proxy via Client, and starts up an HTTP server on the TCP network
// address p.Addr.
// See http#Server#ListenAndServe.
func (p *Proxy) ListenAndServe() error {
listener, mux, err := p.listen()
func (p *Proxy) ListenAndServe(ctx context.Context) error {
listener, mux, err := p.listen(ctx)
if err != nil {
return err
}
@@ -67,8 +67,8 @@ func (p *Proxy) ListenAndServe() error {
// ListenAndServeTLS acts identically to ListenAndServe, except that it expects
// HTTPS connections.
// See http#Server#ListenAndServeTLS.
func (p *Proxy) ListenAndServeTLS(certFile, keyFile string) error {
listener, mux, err := p.listen()
func (p *Proxy) ListenAndServeTLS(ctx context.Context, certFile, keyFile string) error {
listener, mux, err := p.listen(ctx)
if err != nil {
return err
}
@@ -84,7 +84,7 @@ func (p *Proxy) ListenAndServeTLS(certFile, keyFile string) error {
)
}
func (p *Proxy) listen() (net.Listener, *http.ServeMux, error) {
func (p *Proxy) listen(ctx context.Context) (net.Listener, *http.ServeMux, error) {
mux := http.NewServeMux()
// 1) Register regular routes.
@@ -107,7 +107,7 @@ func (p *Proxy) listen() (net.Listener, *http.ServeMux, error) {
// 3) Start a client.
if !p.Client.IsRunning() {
if err := p.Client.Start(); err != nil {
if err := p.Client.Start(ctx); err != nil {
return nil, mux, fmt.Errorf("can't start client: %w", err)
}
}
+2 -2
View File
@@ -98,9 +98,9 @@ func NewClient(next rpcclient.Client, lc LightClient, opts ...Option) *Client {
return c
}
func (c *Client) OnStart() error {
func (c *Client) OnStart(ctx context.Context) error {
if !c.next.IsRunning() {
return c.next.Start()
return c.next.Start(ctx)
}
return nil
}
+61 -77
View File
@@ -82,7 +82,11 @@ type nodeImpl struct {
// newDefaultNode returns a Tendermint node with default settings for the
// PrivValidator, ClientCreator, GenesisDoc, and DBProvider.
// It implements NodeProvider.
func newDefaultNode(cfg *config.Config, logger log.Logger) (service.Service, error) {
func newDefaultNode(
ctx context.Context,
cfg *config.Config,
logger log.Logger,
) (service.Service, error) {
nodeKey, err := types.LoadOrGenNodeKey(cfg.NodeKeyFile())
if err != nil {
return nil, fmt.Errorf("failed to load or gen node key %s: %w", cfg.NodeKeyFile(), err)
@@ -108,7 +112,9 @@ func newDefaultNode(cfg *config.Config, logger log.Logger) (service.Service, err
appClient, _ := proxy.DefaultClientCreator(logger, cfg.ProxyApp, cfg.ABCI, cfg.DBDir())
return makeNode(cfg,
return makeNode(
ctx,
cfg,
pval,
nodeKey,
appClient,
@@ -119,7 +125,9 @@ func newDefaultNode(cfg *config.Config, logger log.Logger) (service.Service, err
}
// makeNode returns a new, ready to go, Tendermint Node.
func makeNode(cfg *config.Config,
func makeNode(
ctx context.Context,
cfg *config.Config,
privValidator types.PrivValidator,
nodeKey types.NodeKey,
clientCreator abciclient.Creator,
@@ -127,7 +135,10 @@ func makeNode(cfg *config.Config,
dbProvider config.DBProvider,
logger log.Logger,
) (service.Service, error) {
closers := []closer{}
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
closers := []closer{convertCancelCloser(cancel)}
blockStore, stateDB, dbCloser, err := initDBs(cfg, dbProvider)
if err != nil {
@@ -157,7 +168,7 @@ func makeNode(cfg *config.Config,
nodeMetrics := defaultMetricsProvider(cfg.Instrumentation)(genDoc.ChainID)
// Create the proxyApp and establish connections to the ABCI app (consensus, mempool, query).
proxyApp, err := createAndStartProxyAppConns(clientCreator, logger, nodeMetrics.proxy)
proxyApp, err := createAndStartProxyAppConns(ctx, clientCreator, logger, nodeMetrics.proxy)
if err != nil {
return nil, combineCloseError(err, makeCloser(closers))
}
@@ -166,12 +177,13 @@ func makeNode(cfg *config.Config,
// we might need to index the txs of the replayed block as this might not have happened
// when the node stopped last time (i.e. the node stopped after it saved the block
// but before it indexed the txs, or, endblocker panicked)
eventBus, err := createAndStartEventBus(logger)
eventBus, err := createAndStartEventBus(ctx, logger)
if err != nil {
return nil, combineCloseError(err, makeCloser(closers))
}
indexerService, eventSinks, err := createAndStartIndexerService(cfg, dbProvider, eventBus,
indexerService, eventSinks, err := createAndStartIndexerService(
ctx, cfg, dbProvider, eventBus,
logger, genDoc.ChainID, nodeMetrics.indexer)
if err != nil {
return nil, combineCloseError(err, makeCloser(closers))
@@ -184,14 +196,19 @@ func makeNode(cfg *config.Config,
// FIXME: we should start services inside OnStart
switch protocol {
case "grpc":
privValidator, err = createAndStartPrivValidatorGRPCClient(cfg, genDoc.ChainID, logger)
privValidator, err = createAndStartPrivValidatorGRPCClient(ctx, cfg, genDoc.ChainID, logger)
if err != nil {
return nil, combineCloseError(
fmt.Errorf("error with private validator grpc client: %w", err),
makeCloser(closers))
}
default:
privValidator, err = createAndStartPrivValidatorSocketClient(cfg.PrivValidator.ListenAddr, genDoc.ChainID, logger)
privValidator, err = createAndStartPrivValidatorSocketClient(
ctx,
cfg.PrivValidator.ListenAddr,
genDoc.ChainID,
logger,
)
if err != nil {
return nil, combineCloseError(
fmt.Errorf("error with private validator socket client: %w", err),
@@ -201,7 +218,7 @@ func makeNode(cfg *config.Config,
}
var pubKey crypto.PubKey
if cfg.Mode == config.ModeValidator {
pubKey, err = privValidator.GetPubKey(context.TODO())
pubKey, err = privValidator.GetPubKey(ctx)
if err != nil {
return nil, combineCloseError(fmt.Errorf("can't get pubkey: %w", err),
makeCloser(closers))
@@ -227,7 +244,7 @@ func makeNode(cfg *config.Config,
if err := consensus.NewHandshaker(
logger.With("module", "handshaker"),
stateStore, state, blockStore, eventBus, genDoc,
).Handshake(proxyApp); err != nil {
).Handshake(ctx, proxyApp); err != nil {
return nil, combineCloseError(err, makeCloser(closers))
}
@@ -253,7 +270,6 @@ func makeNode(cfg *config.Config,
nodeInfo, err := makeNodeInfo(cfg, nodeKey, eventSinks, genDoc, state)
if err != nil {
return nil, combineCloseError(err, makeCloser(closers))
}
peerManager, peerCloser, err := createPeerManager(cfg, dbProvider, nodeKey.ID)
@@ -492,7 +508,7 @@ func makeSeedNode(cfg *config.Config,
}
// OnStart starts the Node. It implements service.Service.
func (n *nodeImpl) OnStart() error {
func (n *nodeImpl) OnStart(ctx context.Context) error {
if n.config.RPC.PprofListenAddress != "" {
// this service is not cleaned up (I believe that we'd
// need to have another thread and a potentially a
@@ -513,7 +529,7 @@ func (n *nodeImpl) OnStart() error {
// Start the RPC server before the P2P server
// so we can eg. receive txs for the first block
if n.config.RPC.ListenAddress != "" && n.config.Mode != config.ModeSeed {
listeners, err := n.startRPC()
listeners, err := n.startRPC(ctx)
if err != nil {
return err
}
@@ -526,39 +542,39 @@ func (n *nodeImpl) OnStart() error {
}
// Start the transport.
if err := n.router.Start(); err != nil {
if err := n.router.Start(ctx); err != nil {
return err
}
n.isListening = true
if n.config.Mode != config.ModeSeed {
if err := n.bcReactor.Start(); err != nil {
if err := n.bcReactor.Start(ctx); err != nil {
return err
}
// Start the real consensus reactor separately since the switch uses the shim.
if err := n.consensusReactor.Start(); err != nil {
if err := n.consensusReactor.Start(ctx); err != nil {
return err
}
// Start the real state sync reactor separately since the switch uses the shim.
if err := n.stateSyncReactor.Start(); err != nil {
if err := n.stateSyncReactor.Start(ctx); err != nil {
return err
}
// Start the real mempool reactor separately since the switch uses the shim.
if err := n.mempoolReactor.Start(); err != nil {
if err := n.mempoolReactor.Start(ctx); err != nil {
return err
}
// Start the real evidence reactor separately since the switch uses the shim.
if err := n.evidenceReactor.Start(); err != nil {
if err := n.evidenceReactor.Start(ctx); err != nil {
return err
}
}
if n.config.P2P.PexReactor {
if err := n.pexReactor.Start(); err != nil {
if err := n.pexReactor.Start(ctx); err != nil {
return err
}
}
@@ -591,7 +607,7 @@ func (n *nodeImpl) OnStart() error {
// bubbling up the error and gracefully shutting down the rest of the node
go func() {
n.Logger.Info("starting state sync")
state, err := n.stateSyncReactor.Sync(context.TODO())
state, err := n.stateSyncReactor.Sync(ctx)
if err != nil {
n.Logger.Error("state sync failed; shutting down this node", "err", err)
// stop the node
@@ -617,7 +633,7 @@ func (n *nodeImpl) OnStart() error {
// is running
// FIXME Very ugly to have these metrics bleed through here.
n.consensusReactor.SetBlockSyncingMetrics(1)
if err := bcR.SwitchToBlockSync(state); err != nil {
if err := bcR.SwitchToBlockSync(ctx, state); err != nil {
n.Logger.Error("failed to switch to block sync", "err", err)
return
}
@@ -638,19 +654,13 @@ func (n *nodeImpl) OnStart() error {
// OnStop stops the Node. It implements service.Service.
func (n *nodeImpl) OnStop() {
n.Logger.Info("Stopping Node")
if n.eventBus != nil {
// first stop the non-reactor services
if err := n.eventBus.Stop(); err != nil {
n.Logger.Error("Error closing eventBus", "err", err)
}
n.eventBus.Wait()
}
if n.indexerService != nil {
if err := n.indexerService.Stop(); err != nil {
n.Logger.Error("Error closing indexerService", "err", err)
}
n.indexerService.Wait()
}
for _, es := range n.eventSinks {
@@ -660,41 +670,14 @@ func (n *nodeImpl) OnStop() {
}
if n.config.Mode != config.ModeSeed {
// now stop the reactors
// Stop the real blockchain reactor separately since the switch uses the shim.
if err := n.bcReactor.Stop(); err != nil {
n.Logger.Error("failed to stop the blockchain reactor", "err", err)
}
// Stop the real consensus reactor separately since the switch uses the shim.
if err := n.consensusReactor.Stop(); err != nil {
n.Logger.Error("failed to stop the consensus reactor", "err", err)
}
// Stop the real state sync reactor separately since the switch uses the shim.
if err := n.stateSyncReactor.Stop(); err != nil {
n.Logger.Error("failed to stop the state sync reactor", "err", err)
}
// Stop the real mempool reactor separately since the switch uses the shim.
if err := n.mempoolReactor.Stop(); err != nil {
n.Logger.Error("failed to stop the mempool reactor", "err", err)
}
// Stop the real evidence reactor separately since the switch uses the shim.
if err := n.evidenceReactor.Stop(); err != nil {
n.Logger.Error("failed to stop the evidence reactor", "err", err)
}
}
if err := n.pexReactor.Stop(); err != nil {
n.Logger.Error("failed to stop the PEX v2 reactor", "err", err)
}
if err := n.router.Stop(); err != nil {
n.Logger.Error("failed to stop router", "err", err)
n.bcReactor.Wait()
n.consensusReactor.Wait()
n.stateSyncReactor.Wait()
n.mempoolReactor.Wait()
n.evidenceReactor.Wait()
}
n.pexReactor.Wait()
n.router.Wait()
n.isListening = false
// finally stop the listeners / external services
@@ -706,9 +689,7 @@ func (n *nodeImpl) OnStop() {
}
if pvsc, ok := n.privValidator.(service.Service); ok {
if err := pvsc.Stop(); err != nil {
n.Logger.Error("Error closing private validator", "err", err)
}
pvsc.Wait()
}
if n.prometheusSrv != nil {
@@ -719,13 +700,15 @@ func (n *nodeImpl) OnStop() {
}
if err := n.shutdownOps(); err != nil {
n.Logger.Error("problem shutting down additional services", "err", err)
if strings.TrimSpace(err.Error()) != "" {
n.Logger.Error("problem shutting down additional services", "err", err)
}
}
}
func (n *nodeImpl) startRPC() ([]net.Listener, error) {
func (n *nodeImpl) startRPC(ctx context.Context) ([]net.Listener, error) {
if n.config.Mode == config.ModeValidator {
pubKey, err := n.privValidator.GetPubKey(context.TODO())
pubKey, err := n.privValidator.GetPubKey(ctx)
if pubKey == nil || err != nil {
return nil, fmt.Errorf("can't get pubkey: %w", err)
}
@@ -970,8 +953,8 @@ func loadStateFromDBOrGenesisDocProvider(
}
func createAndStartPrivValidatorSocketClient(
listenAddr,
chainID string,
ctx context.Context,
listenAddr, chainID string,
logger log.Logger,
) (types.PrivValidator, error) {
@@ -980,13 +963,13 @@ func createAndStartPrivValidatorSocketClient(
return nil, fmt.Errorf("failed to start private validator: %w", err)
}
pvsc, err := privval.NewSignerClient(pve, chainID)
pvsc, err := privval.NewSignerClient(ctx, pve, chainID)
if err != nil {
return nil, fmt.Errorf("failed to start private validator: %w", err)
}
// try to get a pubkey from private validate first time
_, err = pvsc.GetPubKey(context.TODO())
_, err = pvsc.GetPubKey(ctx)
if err != nil {
return nil, fmt.Errorf("can't get pubkey: %w", err)
}
@@ -1001,6 +984,7 @@ func createAndStartPrivValidatorSocketClient(
}
func createAndStartPrivValidatorGRPCClient(
ctx context.Context,
cfg *config.Config,
chainID string,
logger log.Logger,
@@ -1016,7 +1000,7 @@ func createAndStartPrivValidatorGRPCClient(
}
// try to get a pubkey from private validate first time
_, err = pvsc.GetPubKey(context.TODO())
_, err = pvsc.GetPubKey(ctx)
if err != nil {
return nil, fmt.Errorf("can't get pubkey: %w", err)
}
@@ -1031,7 +1015,7 @@ func getRouterConfig(conf *config.Config, proxyApp proxy.AppConns) p2p.RouterOpt
if conf.FilterPeers && proxyApp != nil {
opts.FilterPeerByID = func(ctx context.Context, id types.NodeID) error {
res, err := proxyApp.Query().QuerySync(context.Background(), abci.RequestQuery{
res, err := proxyApp.Query().QuerySync(ctx, abci.RequestQuery{
Path: fmt.Sprintf("/p2p/filter/id/%s", id),
})
if err != nil {
+69 -48
View File
@@ -7,7 +7,6 @@ import (
"math"
"net"
"os"
"syscall"
"testing"
"time"
@@ -43,14 +42,17 @@ func TestNodeStartStop(t *testing.T) {
defer os.RemoveAll(cfg.RootDir)
ctx, bcancel := context.WithCancel(context.Background())
defer bcancel()
// create & start node
ns, err := newDefaultNode(cfg, log.TestingLogger())
ns, err := newDefaultNode(ctx, cfg, log.TestingLogger())
require.NoError(t, err)
require.NoError(t, ns.Start())
require.NoError(t, ns.Start(ctx))
t.Cleanup(func() {
if ns.IsRunning() {
assert.NoError(t, ns.Stop())
bcancel()
ns.Wait()
}
})
@@ -58,9 +60,6 @@ func TestNodeStartStop(t *testing.T) {
n, ok := ns.(*nodeImpl)
require.True(t, ok)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// wait for the node to produce a block
blocksSub, err := n.EventBus().SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
ClientID: "node_test",
@@ -75,35 +74,35 @@ func TestNodeStartStop(t *testing.T) {
// stop the node
go func() {
err = n.Stop()
require.NoError(t, err)
bcancel()
n.Wait()
}()
select {
case <-n.Quit():
case <-time.After(5 * time.Second):
pid := os.Getpid()
p, err := os.FindProcess(pid)
if err != nil {
panic(err)
return
case <-time.After(10 * time.Second):
if n.IsRunning() {
t.Fatal("timed out waiting for shutdown")
}
err = p.Signal(syscall.SIGABRT)
fmt.Println(err)
t.Fatal("timed out waiting for shutdown")
}
}
func getTestNode(t *testing.T, conf *config.Config, logger log.Logger) *nodeImpl {
func getTestNode(ctx context.Context, t *testing.T, conf *config.Config, logger log.Logger) *nodeImpl {
t.Helper()
ns, err := newDefaultNode(conf, logger)
ctx, cancel := context.WithCancel(ctx)
defer cancel()
ns, err := newDefaultNode(ctx, conf, logger)
require.NoError(t, err)
n, ok := ns.(*nodeImpl)
require.True(t, ok)
t.Cleanup(func() {
if ns.IsRunning() {
assert.NoError(t, ns.Stop())
cancel()
if n.IsRunning() {
ns.Wait()
}
})
@@ -118,11 +117,14 @@ func TestNodeDelayedStart(t *testing.T) {
defer os.RemoveAll(cfg.RootDir)
now := tmtime.Now()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// create & start node
n := getTestNode(t, cfg, log.TestingLogger())
n := getTestNode(ctx, t, cfg, log.TestingLogger())
n.GenesisDoc().GenesisTime = now.Add(2 * time.Second)
require.NoError(t, n.Start())
require.NoError(t, n.Start(ctx))
startTime := tmtime.Now()
assert.Equal(t, true, startTime.After(n.GenesisDoc().GenesisTime))
@@ -133,8 +135,11 @@ func TestNodeSetAppVersion(t *testing.T) {
require.NoError(t, err)
defer os.RemoveAll(cfg.RootDir)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// create node
n := getTestNode(t, cfg, log.TestingLogger())
n := getTestNode(ctx, t, cfg, log.TestingLogger())
// default config uses the kvstore app
appVersion := kvstore.ProtocolVersion
@@ -151,6 +156,9 @@ func TestNodeSetAppVersion(t *testing.T) {
func TestNodeSetPrivValTCP(t *testing.T) {
addr := "tcp://" + testFreeAddr(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg, err := config.ResetTestRoot("node_priv_val_tcp_test")
require.NoError(t, err)
defer os.RemoveAll(cfg.RootDir)
@@ -170,31 +178,34 @@ func TestNodeSetPrivValTCP(t *testing.T) {
)
go func() {
err := signerServer.Start()
err := signerServer.Start(ctx)
if err != nil {
panic(err)
}
}()
defer signerServer.Stop() //nolint:errcheck // ignore for tests
n := getTestNode(t, cfg, log.TestingLogger())
n := getTestNode(ctx, t, cfg, log.TestingLogger())
assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
}
// address without a protocol must result in error
func TestPrivValidatorListenAddrNoProtocol(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
addrNoPrefix := testFreeAddr(t)
cfg, err := config.ResetTestRoot("node_priv_val_tcp_test")
require.NoError(t, err)
defer os.RemoveAll(cfg.RootDir)
cfg.PrivValidator.ListenAddr = addrNoPrefix
n, err := newDefaultNode(ctx, cfg, log.TestingLogger())
n, err := newDefaultNode(cfg, log.TestingLogger())
assert.Error(t, err)
if n != nil && n.IsRunning() {
assert.NoError(t, n.Stop())
cancel()
n.Wait()
}
}
@@ -203,6 +214,9 @@ func TestNodeSetPrivValIPC(t *testing.T) {
tmpfile := "/tmp/kms." + tmrand.Str(6) + ".sock"
defer os.Remove(tmpfile) // clean up
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg, err := config.ResetTestRoot("node_priv_val_tcp_test")
require.NoError(t, err)
defer os.RemoveAll(cfg.RootDir)
@@ -222,11 +236,11 @@ func TestNodeSetPrivValIPC(t *testing.T) {
)
go func() {
err := pvsc.Start()
err := pvsc.Start(ctx)
require.NoError(t, err)
}()
defer pvsc.Stop() //nolint:errcheck // ignore for tests
n := getTestNode(t, cfg, log.TestingLogger())
n := getTestNode(ctx, t, cfg, log.TestingLogger())
assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
}
@@ -248,11 +262,11 @@ func TestCreateProposalBlock(t *testing.T) {
cfg, err := config.ResetTestRoot("node_create_proposal")
require.NoError(t, err)
defer os.RemoveAll(cfg.RootDir)
cc := abciclient.NewLocalCreator(kvstore.NewApplication())
proxyApp := proxy.NewAppConns(cc, log.TestingLogger(), proxy.NopMetrics())
err = proxyApp.Start()
err = proxyApp.Start(ctx)
require.Nil(t, err)
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
logger := log.TestingLogger()
@@ -344,9 +358,8 @@ func TestMaxTxsProposalBlockSize(t *testing.T) {
defer os.RemoveAll(cfg.RootDir)
cc := abciclient.NewLocalCreator(kvstore.NewApplication())
proxyApp := proxy.NewAppConns(cc, log.TestingLogger(), proxy.NopMetrics())
err = proxyApp.Start()
err = proxyApp.Start(ctx)
require.Nil(t, err)
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
logger := log.TestingLogger()
@@ -408,9 +421,8 @@ func TestMaxProposalBlockSize(t *testing.T) {
defer os.RemoveAll(cfg.RootDir)
cc := abciclient.NewLocalCreator(kvstore.NewApplication())
proxyApp := proxy.NewAppConns(cc, log.TestingLogger(), proxy.NopMetrics())
err = proxyApp.Start()
err = proxyApp.Start(ctx)
require.Nil(t, err)
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
logger := log.TestingLogger()
@@ -432,7 +444,7 @@ func TestMaxProposalBlockSize(t *testing.T) {
// fill the mempool with one txs just below the maximum size
txLength := int(types.MaxDataBytesNoEvidence(maxBytes, types.MaxVotesCount))
tx := tmrand.Bytes(txLength - 6) // to account for the varint
err = mp.CheckTx(context.Background(), tx, nil, mempool.TxInfo{})
err = mp.CheckTx(ctx, tx, nil, mempool.TxInfo{})
assert.NoError(t, err)
// now produce more txs than what a normal block can hold with 10 smaller txs
// At the end of the test, only the single big tx should be added
@@ -521,6 +533,9 @@ func TestNodeNewSeedNode(t *testing.T) {
cfg.Mode = config.ModeSeed
defer os.RemoveAll(cfg.RootDir)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
nodeKey, err := types.LoadOrGenNodeKey(cfg.NodeKeyFile())
require.NoError(t, err)
@@ -530,17 +545,20 @@ func TestNodeNewSeedNode(t *testing.T) {
defaultGenesisDocProviderFunc(cfg),
log.TestingLogger(),
)
t.Cleanup(ns.Wait)
require.NoError(t, err)
n, ok := ns.(*nodeImpl)
require.True(t, ok)
err = n.Start()
err = n.Start(ctx)
require.NoError(t, err)
assert.True(t, n.pexReactor.IsRunning())
require.NoError(t, n.Stop())
cancel()
n.Wait()
assert.False(t, n.pexReactor.IsRunning())
}
func TestNodeSetEventSink(t *testing.T) {
@@ -549,19 +567,22 @@ func TestNodeSetEventSink(t *testing.T) {
defer os.RemoveAll(cfg.RootDir)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger := log.TestingLogger()
setupTest := func(t *testing.T, conf *config.Config) []indexer.EventSink {
eventBus, err := createAndStartEventBus(logger)
eventBus, err := createAndStartEventBus(ctx, logger)
require.NoError(t, err)
t.Cleanup(func() { require.NoError(t, eventBus.Stop()) })
t.Cleanup(eventBus.Wait)
genDoc, err := types.GenesisDocFromFile(cfg.GenesisFile())
require.NoError(t, err)
indexService, eventSinks, err := createAndStartIndexerService(cfg,
indexService, eventSinks, err := createAndStartIndexerService(ctx, cfg,
config.DefaultDBProvider, eventBus, logger, genDoc.ChainID,
indexer.NopMetrics())
require.NoError(t, err)
t.Cleanup(func() { require.NoError(t, indexService.Stop()) })
t.Cleanup(indexService.Wait)
return eventSinks
}
cleanup := func(ns service.Service) func() {
@@ -576,7 +597,7 @@ func TestNodeSetEventSink(t *testing.T) {
if !n.IsRunning() {
return
}
assert.NoError(t, n.Stop())
cancel()
n.Wait()
}
}
@@ -598,7 +619,7 @@ func TestNodeSetEventSink(t *testing.T) {
assert.Equal(t, indexer.NULL, eventSinks[0].Type())
cfg.TxIndex.Indexer = []string{"kvv"}
ns, err := newDefaultNode(cfg, logger)
ns, err := newDefaultNode(ctx, cfg, logger)
assert.Nil(t, ns)
assert.Contains(t, err.Error(), "unsupported event sink type")
t.Cleanup(cleanup(ns))
@@ -610,7 +631,7 @@ func TestNodeSetEventSink(t *testing.T) {
assert.Equal(t, indexer.NULL, eventSinks[0].Type())
cfg.TxIndex.Indexer = []string{"psql"}
ns, err = newDefaultNode(cfg, logger)
ns, err = newDefaultNode(ctx, cfg, logger)
assert.Nil(t, ns)
assert.Contains(t, err.Error(), "the psql connection settings cannot be empty")
t.Cleanup(cleanup(ns))
@@ -652,14 +673,14 @@ func TestNodeSetEventSink(t *testing.T) {
var e = errors.New("found duplicated sinks, please check the tx-index section in the config.toml")
cfg.TxIndex.Indexer = []string{"psql", "kv", "Kv"}
cfg.TxIndex.PsqlConn = psqlConn
ns, err = newDefaultNode(cfg, logger)
ns, err = newDefaultNode(ctx, cfg, logger)
require.Error(t, err)
assert.Contains(t, err.Error(), e.Error())
t.Cleanup(cleanup(ns))
cfg.TxIndex.Indexer = []string{"Psql", "kV", "kv", "pSql"}
cfg.TxIndex.PsqlConn = psqlConn
ns, err = newDefaultNode(cfg, logger)
ns, err = newDefaultNode(ctx, cfg, logger)
require.Error(t, err)
assert.Contains(t, err.Error(), e.Error())
t.Cleanup(cleanup(ns))
+13 -4
View File
@@ -2,6 +2,7 @@
package node
import (
"context"
"fmt"
abciclient "github.com/tendermint/tendermint/abci/client"
@@ -16,8 +17,12 @@ import (
// process that host their own process-local tendermint node. This is
// equivalent to running tendermint in it's own process communicating
// to an external ABCI application.
func NewDefault(conf *config.Config, logger log.Logger) (service.Service, error) {
return newDefaultNode(conf, logger)
func NewDefault(
ctx context.Context,
conf *config.Config,
logger log.Logger,
) (service.Service, error) {
return newDefaultNode(ctx, conf, logger)
}
// New constructs a tendermint node. The ClientCreator makes it
@@ -26,7 +31,9 @@ func NewDefault(conf *config.Config, logger log.Logger) (service.Service, error)
// Genesis document: if the value is nil, the genesis document is read
// from the file specified in the config, and otherwise the node uses
// value of the final argument.
func New(conf *config.Config,
func New(
ctx context.Context,
conf *config.Config,
logger log.Logger,
cf abciclient.Creator,
gen *types.GenesisDoc,
@@ -51,7 +58,9 @@ func New(conf *config.Config,
return nil, err
}
return makeNode(conf,
return makeNode(
ctx,
conf,
pval,
nodeKey,
cf,
+16 -6
View File
@@ -2,6 +2,7 @@ package node
import (
"bytes"
"context"
"errors"
"fmt"
"strings"
@@ -52,6 +53,10 @@ func makeCloser(cs []closer) closer {
}
}
func convertCancelCloser(cancel context.CancelFunc) closer {
return func() error { cancel(); return nil }
}
func combineCloseError(err error, cl closer) error {
if err == nil {
return cl()
@@ -88,26 +93,31 @@ func initDBs(
return blockStore, stateDB, makeCloser(closers), nil
}
// nolint:lll
func createAndStartProxyAppConns(clientCreator abciclient.Creator, logger log.Logger, metrics *proxy.Metrics) (proxy.AppConns, error) {
func createAndStartProxyAppConns(
ctx context.Context,
clientCreator abciclient.Creator,
logger log.Logger,
metrics *proxy.Metrics,
) (proxy.AppConns, error) {
proxyApp := proxy.NewAppConns(clientCreator, logger.With("module", "proxy"), metrics)
if err := proxyApp.Start(); err != nil {
if err := proxyApp.Start(ctx); err != nil {
return nil, fmt.Errorf("error starting proxy app connections: %v", err)
}
return proxyApp, nil
}
func createAndStartEventBus(logger log.Logger) (*eventbus.EventBus, error) {
func createAndStartEventBus(ctx context.Context, logger log.Logger) (*eventbus.EventBus, error) {
eventBus := eventbus.NewDefault(logger.With("module", "events"))
if err := eventBus.Start(); err != nil {
if err := eventBus.Start(ctx); err != nil {
return nil, err
}
return eventBus, nil
}
func createAndStartIndexerService(
ctx context.Context,
cfg *config.Config,
dbProvider config.DBProvider,
eventBus *eventbus.EventBus,
@@ -127,7 +137,7 @@ func createAndStartIndexerService(
Metrics: metrics,
})
if err := indexerService.Start(); err != nil {
if err := indexerService.Start(ctx); err != nil {
return nil, nil, err
}
+1 -1
View File
@@ -109,7 +109,7 @@ func DialRemoteSigner(
dialOptions = append(dialOptions, transportSecurity)
ctx := context.Background()
ctx := context.TODO()
_, address := tmnet.ProtocolAndAddress(cfg.ListenAddr)
conn, err := grpc.DialContext(ctx, address, dialOptions...)
if err != nil {
+2 -2
View File
@@ -23,9 +23,9 @@ var _ types.PrivValidator = (*SignerClient)(nil)
// NewSignerClient returns an instance of SignerClient.
// it will start the endpoint (if not already started)
func NewSignerClient(endpoint *SignerListenerEndpoint, chainID string) (*SignerClient, error) {
func NewSignerClient(ctx context.Context, endpoint *SignerListenerEndpoint, chainID string) (*SignerClient, error) {
if !endpoint.IsRunning() {
if err := endpoint.Start(); err != nil {
if err := endpoint.Start(ctx); err != nil {
return nil, fmt.Errorf("failed to start listener endpoint: %w", err)
}
}
+259 -298
View File
@@ -23,370 +23,336 @@ type signerTestCase struct {
mockPV types.PrivValidator
signerClient *SignerClient
signerServer *SignerServer
name string
closer context.CancelFunc
}
func getSignerTestCases(t *testing.T) []signerTestCase {
func getSignerTestCases(ctx context.Context, t *testing.T) []signerTestCase {
t.Helper()
testCases := make([]signerTestCase, 0)
// Get test cases for each possible dialer (DialTCP / DialUnix / etc)
for _, dtc := range getDialerTestCases(t) {
for idx, dtc := range getDialerTestCases(t) {
chainID := tmrand.Str(12)
mockPV := types.NewMockPV()
cctx, ccancel := context.WithCancel(ctx)
// get a pair of signer listener, signer dialer endpoints
sl, sd := getMockEndpoints(t, dtc.addr, dtc.dialer)
sc, err := NewSignerClient(sl, chainID)
sl, sd := getMockEndpoints(cctx, t, dtc.addr, dtc.dialer)
sc, err := NewSignerClient(cctx, sl, chainID)
require.NoError(t, err)
ss := NewSignerServer(sd, chainID, mockPV)
err = ss.Start()
require.NoError(t, err)
require.NoError(t, ss.Start(cctx))
tc := signerTestCase{
testCases = append(testCases, signerTestCase{
name: fmt.Sprintf("Case%d%T_%s", idx, dtc.dialer, chainID),
closer: ccancel,
chainID: chainID,
mockPV: mockPV,
signerClient: sc,
signerServer: ss,
}
testCases = append(testCases, tc)
})
}
return testCases
}
func TestSignerClose(t *testing.T) {
for _, tc := range getSignerTestCases(t) {
err := tc.signerClient.Close()
assert.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
err = tc.signerServer.Stop()
assert.NoError(t, err)
for _, tc := range getSignerTestCases(ctx, t) {
t.Run(tc.name, func(t *testing.T) {
defer tc.closer()
assert.NoError(t, tc.signerClient.Close())
assert.NoError(t, tc.signerServer.Stop())
})
}
}
func TestSignerPing(t *testing.T) {
for _, tc := range getSignerTestCases(t) {
tc := tc
t.Cleanup(func() {
if err := tc.signerServer.Stop(); err != nil {
t.Error(err)
}
})
t.Cleanup(func() {
if err := tc.signerClient.Close(); err != nil {
t.Error(err)
}
})
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for _, tc := range getSignerTestCases(ctx, t) {
err := tc.signerClient.Ping()
assert.NoError(t, err)
}
}
func TestSignerGetPubKey(t *testing.T) {
for _, tc := range getSignerTestCases(t) {
tc := tc
t.Cleanup(func() {
if err := tc.signerServer.Stop(); err != nil {
t.Error(err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for _, tc := range getSignerTestCases(ctx, t) {
t.Run(tc.name, func(t *testing.T) {
defer tc.closer()
pubKey, err := tc.signerClient.GetPubKey(ctx)
require.NoError(t, err)
expectedPubKey, err := tc.mockPV.GetPubKey(ctx)
require.NoError(t, err)
assert.Equal(t, expectedPubKey, pubKey)
pubKey, err = tc.signerClient.GetPubKey(ctx)
require.NoError(t, err)
expectedpk, err := tc.mockPV.GetPubKey(ctx)
require.NoError(t, err)
expectedAddr := expectedpk.Address()
assert.Equal(t, expectedAddr, pubKey.Address())
})
t.Cleanup(func() {
if err := tc.signerClient.Close(); err != nil {
t.Error(err)
}
})
pubKey, err := tc.signerClient.GetPubKey(context.Background())
require.NoError(t, err)
expectedPubKey, err := tc.mockPV.GetPubKey(context.Background())
require.NoError(t, err)
assert.Equal(t, expectedPubKey, pubKey)
pubKey, err = tc.signerClient.GetPubKey(context.Background())
require.NoError(t, err)
expectedpk, err := tc.mockPV.GetPubKey(context.Background())
require.NoError(t, err)
expectedAddr := expectedpk.Address()
assert.Equal(t, expectedAddr, pubKey.Address())
}
}
func TestSignerProposal(t *testing.T) {
for _, tc := range getSignerTestCases(t) {
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
have := &types.Proposal{
Type: tmproto.ProposalType,
Height: 1,
Round: 2,
POLRound: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
}
want := &types.Proposal{
Type: tmproto.ProposalType,
Height: 1,
Round: 2,
POLRound: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
tc := tc
t.Cleanup(func() {
if err := tc.signerServer.Stop(); err != nil {
t.Error(err)
for _, tc := range getSignerTestCases(ctx, t) {
t.Run(tc.name, func(t *testing.T) {
defer tc.closer()
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
have := &types.Proposal{
Type: tmproto.ProposalType,
Height: 1,
Round: 2,
POLRound: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
}
})
t.Cleanup(func() {
if err := tc.signerClient.Close(); err != nil {
t.Error(err)
want := &types.Proposal{
Type: tmproto.ProposalType,
Height: 1,
Round: 2,
POLRound: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
}
require.NoError(t, tc.mockPV.SignProposal(ctx, tc.chainID, want.ToProto()))
require.NoError(t, tc.signerClient.SignProposal(ctx, tc.chainID, have.ToProto()))
assert.Equal(t, want.Signature, have.Signature)
})
require.NoError(t, tc.mockPV.SignProposal(context.Background(), tc.chainID, want.ToProto()))
require.NoError(t, tc.signerClient.SignProposal(context.Background(), tc.chainID, have.ToProto()))
assert.Equal(t, want.Signature, have.Signature)
}
}
func TestSignerVote(t *testing.T) {
for _, tc := range getSignerTestCases(t) {
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
valAddr := tmrand.Bytes(crypto.AddressSize)
want := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
have := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
for _, tc := range getSignerTestCases(ctx, t) {
t.Run(tc.name, func(t *testing.T) {
defer tc.closer()
tc := tc
t.Cleanup(func() {
if err := tc.signerServer.Stop(); err != nil {
t.Error(err)
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
valAddr := tmrand.Bytes(crypto.AddressSize)
want := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
})
t.Cleanup(func() {
if err := tc.signerClient.Close(); err != nil {
t.Error(err)
have := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
require.NoError(t, tc.mockPV.SignVote(ctx, tc.chainID, want.ToProto()))
require.NoError(t, tc.signerClient.SignVote(ctx, tc.chainID, have.ToProto()))
assert.Equal(t, want.Signature, have.Signature)
})
require.NoError(t, tc.mockPV.SignVote(context.Background(), tc.chainID, want.ToProto()))
require.NoError(t, tc.signerClient.SignVote(context.Background(), tc.chainID, have.ToProto()))
assert.Equal(t, want.Signature, have.Signature)
}
}
func TestSignerVoteResetDeadline(t *testing.T) {
for _, tc := range getSignerTestCases(t) {
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
valAddr := tmrand.Bytes(crypto.AddressSize)
want := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
have := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
tc := tc
t.Cleanup(func() {
if err := tc.signerServer.Stop(); err != nil {
t.Error(err)
for _, tc := range getSignerTestCases(ctx, t) {
t.Run(tc.name, func(t *testing.T) {
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
valAddr := tmrand.Bytes(crypto.AddressSize)
want := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
})
t.Cleanup(func() {
if err := tc.signerClient.Close(); err != nil {
t.Error(err)
have := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
time.Sleep(testTimeoutReadWrite2o3)
require.NoError(t, tc.mockPV.SignVote(ctx, tc.chainID, want.ToProto()))
require.NoError(t, tc.signerClient.SignVote(ctx, tc.chainID, have.ToProto()))
assert.Equal(t, want.Signature, have.Signature)
// TODO(jleni): Clarify what is actually being tested
// This would exceed the deadline if it was not extended by the previous message
time.Sleep(testTimeoutReadWrite2o3)
require.NoError(t, tc.mockPV.SignVote(ctx, tc.chainID, want.ToProto()))
require.NoError(t, tc.signerClient.SignVote(ctx, tc.chainID, have.ToProto()))
assert.Equal(t, want.Signature, have.Signature)
})
time.Sleep(testTimeoutReadWrite2o3)
require.NoError(t, tc.mockPV.SignVote(context.Background(), tc.chainID, want.ToProto()))
require.NoError(t, tc.signerClient.SignVote(context.Background(), tc.chainID, have.ToProto()))
assert.Equal(t, want.Signature, have.Signature)
// TODO(jleni): Clarify what is actually being tested
// This would exceed the deadline if it was not extended by the previous message
time.Sleep(testTimeoutReadWrite2o3)
require.NoError(t, tc.mockPV.SignVote(context.Background(), tc.chainID, want.ToProto()))
require.NoError(t, tc.signerClient.SignVote(context.Background(), tc.chainID, have.ToProto()))
assert.Equal(t, want.Signature, have.Signature)
}
}
func TestSignerVoteKeepAlive(t *testing.T) {
for _, tc := range getSignerTestCases(t) {
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
valAddr := tmrand.Bytes(crypto.AddressSize)
want := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
have := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
for _, tc := range getSignerTestCases(ctx, t) {
t.Run(tc.name, func(t *testing.T) {
defer tc.closer()
tc := tc
t.Cleanup(func() {
if err := tc.signerServer.Stop(); err != nil {
t.Error(err)
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
valAddr := tmrand.Bytes(crypto.AddressSize)
want := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
})
t.Cleanup(func() {
if err := tc.signerClient.Close(); err != nil {
t.Error(err)
have := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
}
// Check that even if the client does not request a
// signature for a long time. The service is still available
// in this particular case, we use the dialer logger to ensure that
// test messages are properly interleaved in the test logs
tc.signerServer.Logger.Debug("TEST: Forced Wait -------------------------------------------------")
time.Sleep(testTimeoutReadWrite * 3)
tc.signerServer.Logger.Debug("TEST: Forced Wait DONE---------------------------------------------")
require.NoError(t, tc.mockPV.SignVote(ctx, tc.chainID, want.ToProto()))
require.NoError(t, tc.signerClient.SignVote(ctx, tc.chainID, have.ToProto()))
assert.Equal(t, want.Signature, have.Signature)
})
// Check that even if the client does not request a
// signature for a long time. The service is still available
// in this particular case, we use the dialer logger to ensure that
// test messages are properly interleaved in the test logs
tc.signerServer.Logger.Debug("TEST: Forced Wait -------------------------------------------------")
time.Sleep(testTimeoutReadWrite * 3)
tc.signerServer.Logger.Debug("TEST: Forced Wait DONE---------------------------------------------")
require.NoError(t, tc.mockPV.SignVote(context.Background(), tc.chainID, want.ToProto()))
require.NoError(t, tc.signerClient.SignVote(context.Background(), tc.chainID, have.ToProto()))
assert.Equal(t, want.Signature, have.Signature)
}
}
func TestSignerSignProposalErrors(t *testing.T) {
for _, tc := range getSignerTestCases(t) {
// Replace service with a mock that always fails
tc.signerServer.privVal = types.NewErroringMockPV()
tc.mockPV = types.NewErroringMockPV()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
tc := tc
t.Cleanup(func() {
if err := tc.signerServer.Stop(); err != nil {
t.Error(err)
for _, tc := range getSignerTestCases(ctx, t) {
t.Run(tc.name, func(t *testing.T) {
defer tc.closer()
// Replace service with a mock that always fails
tc.signerServer.privVal = types.NewErroringMockPV()
tc.mockPV = types.NewErroringMockPV()
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
proposal := &types.Proposal{
Type: tmproto.ProposalType,
Height: 1,
Round: 2,
POLRound: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
Signature: []byte("signature"),
}
err := tc.signerClient.SignProposal(ctx, tc.chainID, proposal.ToProto())
rserr, ok := err.(*RemoteSignerError)
require.True(t, ok, "%T", err)
require.Contains(t, rserr.Error(), types.ErroringMockPVErr.Error())
err = tc.mockPV.SignProposal(ctx, tc.chainID, proposal.ToProto())
require.Error(t, err)
err = tc.signerClient.SignProposal(ctx, tc.chainID, proposal.ToProto())
require.Error(t, err)
})
t.Cleanup(func() {
if err := tc.signerClient.Close(); err != nil {
t.Error(err)
}
})
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
proposal := &types.Proposal{
Type: tmproto.ProposalType,
Height: 1,
Round: 2,
POLRound: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
Signature: []byte("signature"),
}
err := tc.signerClient.SignProposal(context.Background(), tc.chainID, proposal.ToProto())
require.Equal(t, err.(*RemoteSignerError).Description, types.ErroringMockPVErr.Error())
err = tc.mockPV.SignProposal(context.Background(), tc.chainID, proposal.ToProto())
require.Error(t, err)
err = tc.signerClient.SignProposal(context.Background(), tc.chainID, proposal.ToProto())
require.Error(t, err)
}
}
func TestSignerSignVoteErrors(t *testing.T) {
for _, tc := range getSignerTestCases(t) {
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
valAddr := tmrand.Bytes(crypto.AddressSize)
vote := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
Signature: []byte("signature"),
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Replace signer service privval with one that always fails
tc.signerServer.privVal = types.NewErroringMockPV()
tc.mockPV = types.NewErroringMockPV()
for _, tc := range getSignerTestCases(ctx, t) {
t.Run(tc.name, func(t *testing.T) {
defer tc.closer()
tc := tc
t.Cleanup(func() {
if err := tc.signerServer.Stop(); err != nil {
t.Error(err)
ts := time.Now()
hash := tmrand.Bytes(tmhash.Size)
valAddr := tmrand.Bytes(crypto.AddressSize)
vote := &types.Vote{
Type: tmproto.PrecommitType,
Height: 1,
Round: 2,
BlockID: types.BlockID{Hash: hash, PartSetHeader: types.PartSetHeader{Hash: hash, Total: 2}},
Timestamp: ts,
ValidatorAddress: valAddr,
ValidatorIndex: 1,
Signature: []byte("signature"),
}
// Replace signer service privval with one that always fails
tc.signerServer.privVal = types.NewErroringMockPV()
tc.mockPV = types.NewErroringMockPV()
err := tc.signerClient.SignVote(ctx, tc.chainID, vote.ToProto())
rserr, ok := err.(*RemoteSignerError)
require.True(t, ok, "%T", err)
require.Contains(t, rserr.Error(), types.ErroringMockPVErr.Error())
err = tc.mockPV.SignVote(ctx, tc.chainID, vote.ToProto())
require.Error(t, err)
err = tc.signerClient.SignVote(ctx, tc.chainID, vote.ToProto())
require.Error(t, err)
})
t.Cleanup(func() {
if err := tc.signerClient.Close(); err != nil {
t.Error(err)
}
})
err := tc.signerClient.SignVote(context.Background(), tc.chainID, vote.ToProto())
require.Equal(t, err.(*RemoteSignerError).Description, types.ErroringMockPVErr.Error())
err = tc.mockPV.SignVote(context.Background(), tc.chainID, vote.ToProto())
require.Error(t, err)
err = tc.signerClient.SignVote(context.Background(), tc.chainID, vote.ToProto())
require.Error(t, err)
}
}
@@ -413,28 +379,23 @@ func brokenHandler(ctx context.Context, privVal types.PrivValidator, request pri
}
func TestSignerUnexpectedResponse(t *testing.T) {
for _, tc := range getSignerTestCases(t) {
tc.signerServer.privVal = types.NewMockPV()
tc.mockPV = types.NewMockPV()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
tc.signerServer.SetRequestHandler(brokenHandler)
for _, tc := range getSignerTestCases(ctx, t) {
t.Run(tc.name, func(t *testing.T) {
defer tc.closer()
tc := tc
t.Cleanup(func() {
if err := tc.signerServer.Stop(); err != nil {
t.Error(err)
}
tc.signerServer.privVal = types.NewMockPV()
tc.mockPV = types.NewMockPV()
tc.signerServer.SetRequestHandler(brokenHandler)
ts := time.Now()
want := &types.Vote{Timestamp: ts, Type: tmproto.PrecommitType}
e := tc.signerClient.SignVote(ctx, tc.chainID, want.ToProto())
assert.EqualError(t, e, "empty response")
})
t.Cleanup(func() {
if err := tc.signerClient.Close(); err != nil {
t.Error(err)
}
})
ts := time.Now()
want := &types.Vote{Timestamp: ts, Type: tmproto.PrecommitType}
e := tc.signerClient.SignVote(context.Background(), tc.chainID, want.ToProto())
assert.EqualError(t, e, "empty response")
}
}

Some files were not shown because too many files have changed in this diff Show More