2019-08-27 07:32:36 +03:00
|
|
|
package chanacceptor
|
|
|
|
|
|
|
|
import (
|
2020-11-09 10:34:49 +03:00
|
|
|
"errors"
|
|
|
|
"math/big"
|
2019-08-27 07:32:36 +03:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/btcsuite/btcd/btcec"
|
2020-11-09 10:34:49 +03:00
|
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
2019-08-27 07:32:36 +03:00
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
2020-11-09 10:34:49 +03:00
|
|
|
"github.com/stretchr/testify/assert"
|
2019-08-27 07:32:36 +03:00
|
|
|
)
|
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
const testTimeout = time.Second
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
type channelAcceptorCtx struct {
|
|
|
|
t *testing.T
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// extRequests is the channel that we send our channel accept requests
|
|
|
|
// into, this channel mocks sending of a request to the rpc acceptor.
|
|
|
|
// This channel should be buffered with the number of requests we want
|
|
|
|
// to send so that it does not block (like a rpc stream).
|
|
|
|
extRequests chan []byte
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// responses is a map of pending channel IDs to the response which we
|
|
|
|
// wish to mock the remote channel acceptor sending.
|
|
|
|
responses map[[32]byte]*lnrpc.ChannelAcceptResponse
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// acceptor is the channel acceptor we create for the test.
|
|
|
|
acceptor *RPCAcceptor
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// errChan is a channel that the error the channel acceptor exits with
|
|
|
|
// is sent into.
|
|
|
|
errChan chan error
|
|
|
|
|
|
|
|
// quit is a channel that can be used to shutdown the channel acceptor
|
|
|
|
// and return errShuttingDown.
|
|
|
|
quit chan struct{}
|
|
|
|
}
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
func newChanAcceptorCtx(t *testing.T, acceptCallCount int,
|
|
|
|
responses map[[32]byte]*lnrpc.ChannelAcceptResponse) *channelAcceptorCtx {
|
|
|
|
|
|
|
|
testCtx := &channelAcceptorCtx{
|
|
|
|
t: t,
|
|
|
|
extRequests: make(chan []byte, acceptCallCount),
|
|
|
|
responses: responses,
|
|
|
|
errChan: make(chan error),
|
|
|
|
quit: make(chan struct{}),
|
2019-08-27 07:32:36 +03:00
|
|
|
}
|
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
testCtx.acceptor = NewRPCAcceptor(
|
|
|
|
testCtx.receiveResponse, testCtx.sendRequest, testTimeout*5,
|
|
|
|
testCtx.quit,
|
|
|
|
)
|
|
|
|
|
|
|
|
return testCtx
|
|
|
|
}
|
|
|
|
|
|
|
|
// sendRequest mocks sending a request to the channel acceptor.
|
|
|
|
func (c *channelAcceptorCtx) sendRequest(request *lnrpc.ChannelAcceptRequest) error {
|
|
|
|
select {
|
|
|
|
case c.extRequests <- request.PendingChanId:
|
|
|
|
|
|
|
|
case <-time.After(testTimeout):
|
|
|
|
c.t.Fatalf("timeout sending request: %v", request.PendingChanId)
|
2019-08-27 07:32:36 +03:00
|
|
|
}
|
2020-11-09 10:34:49 +03:00
|
|
|
|
|
|
|
return nil
|
2019-08-27 07:32:36 +03:00
|
|
|
}
|
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// receiveResponse mocks sending of a response from the channel acceptor.
|
|
|
|
func (c *channelAcceptorCtx) receiveResponse() (*lnrpc.ChannelAcceptResponse,
|
|
|
|
error) {
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
select {
|
|
|
|
case id := <-c.extRequests:
|
|
|
|
scratch := [32]byte{}
|
|
|
|
copy(scratch[:], id)
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
resp, ok := c.responses[scratch]
|
|
|
|
assert.True(c.t, ok)
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
return resp, nil
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
case <-time.After(testTimeout):
|
|
|
|
c.t.Fatalf("timeout receiving request")
|
|
|
|
return nil, errors.New("receiveResponse timeout")
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// Exit if our test acceptor closes the done channel, which indicates
|
|
|
|
// that the acceptor is shutting down.
|
|
|
|
case <-c.acceptor.done:
|
|
|
|
return nil, errors.New("acceptor shutting down")
|
|
|
|
}
|
|
|
|
}
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// start runs our channel acceptor in a goroutine which sends its exit error
|
|
|
|
// into our test error channel.
|
|
|
|
func (c *channelAcceptorCtx) start() {
|
|
|
|
go func() {
|
|
|
|
c.errChan <- c.acceptor.Run()
|
|
|
|
}()
|
|
|
|
}
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// stop shuts down the test's channel acceptor and asserts that it exits with
|
|
|
|
// our expected error.
|
|
|
|
func (c *channelAcceptorCtx) stop() {
|
|
|
|
close(c.quit)
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
select {
|
|
|
|
case actual := <-c.errChan:
|
|
|
|
assert.Equal(c.t, errShuttingDown, actual)
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
case <-time.After(testTimeout):
|
|
|
|
c.t.Fatal("timeout waiting for acceptor to exit")
|
|
|
|
}
|
|
|
|
}
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// queryAndAssert takes a map of open channel requests which we want to call
|
|
|
|
// Accept for to the outcome we expect from the acceptor, dispatches each
|
|
|
|
// request in a goroutine and then asserts that we get the outcome we expect.
|
|
|
|
func (c *channelAcceptorCtx) queryAndAssert(queries map[*lnwire.OpenChannel]bool) {
|
|
|
|
var (
|
|
|
|
node = &btcec.PublicKey{
|
|
|
|
X: big.NewInt(1),
|
|
|
|
Y: big.NewInt(1),
|
2019-08-27 07:32:36 +03:00
|
|
|
}
|
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
responses = make(chan struct{})
|
|
|
|
)
|
|
|
|
|
|
|
|
for request, expected := range queries {
|
|
|
|
request := request
|
|
|
|
expected := expected
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
resp := c.acceptor.Accept(&ChannelAcceptRequest{
|
|
|
|
Node: node,
|
|
|
|
OpenChanMsg: request,
|
|
|
|
})
|
|
|
|
assert.Equal(c.t, expected, resp)
|
|
|
|
responses <- struct{}{}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for each of our requests to return a response before we exit.
|
|
|
|
for i := 0; i < len(queries); i++ {
|
2019-08-27 07:32:36 +03:00
|
|
|
select {
|
2020-11-09 10:34:49 +03:00
|
|
|
case <-responses:
|
|
|
|
case <-time.After(testTimeout):
|
|
|
|
c.t.Fatalf("did not receive response")
|
2019-08-27 07:32:36 +03:00
|
|
|
}
|
|
|
|
}
|
2020-11-09 10:34:49 +03:00
|
|
|
}
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// TestMultipleAcceptClients tests that the RPC acceptor is capable of handling
|
|
|
|
// multiple requests to its Accept function and responding to them correctly.
|
|
|
|
func TestMultipleAcceptClients(t *testing.T) {
|
|
|
|
var (
|
|
|
|
chan1 = &lnwire.OpenChannel{
|
|
|
|
PendingChannelID: [32]byte{1},
|
|
|
|
}
|
|
|
|
chan2 = &lnwire.OpenChannel{
|
|
|
|
PendingChannelID: [32]byte{2},
|
|
|
|
}
|
|
|
|
chan3 = &lnwire.OpenChannel{
|
|
|
|
PendingChannelID: [32]byte{3},
|
|
|
|
}
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// Queries is a map of the channel IDs we will query Accept
|
|
|
|
// with, and the set of outcomes we expect.
|
|
|
|
queries = map[*lnwire.OpenChannel]bool{
|
|
|
|
chan1: true,
|
|
|
|
chan2: false,
|
|
|
|
chan3: false,
|
|
|
|
}
|
2019-08-27 07:32:36 +03:00
|
|
|
|
2020-11-09 10:34:49 +03:00
|
|
|
// Responses is a mocked set of responses from the remote
|
|
|
|
// channel acceptor.
|
|
|
|
responses = map[[32]byte]*lnrpc.ChannelAcceptResponse{
|
|
|
|
chan1.PendingChannelID: {
|
|
|
|
PendingChanId: chan1.PendingChannelID[:],
|
2019-08-27 07:32:36 +03:00
|
|
|
Accept: true,
|
2020-11-09 10:34:49 +03:00
|
|
|
},
|
|
|
|
chan2.PendingChannelID: {
|
|
|
|
PendingChanId: chan2.PendingChannelID[:],
|
|
|
|
Accept: false,
|
|
|
|
},
|
|
|
|
chan3.PendingChannelID: {
|
|
|
|
PendingChanId: chan3.PendingChannelID[:],
|
|
|
|
Accept: false,
|
|
|
|
},
|
2019-08-27 07:32:36 +03:00
|
|
|
}
|
2020-11-09 10:34:49 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
// Create and start our channel acceptor.
|
|
|
|
testCtx := newChanAcceptorCtx(t, len(queries), responses)
|
|
|
|
testCtx.start()
|
|
|
|
|
|
|
|
// Dispatch three queries and assert that we get our expected response.
|
|
|
|
// for each.
|
|
|
|
testCtx.queryAndAssert(queries)
|
|
|
|
|
|
|
|
// Shutdown our acceptor.
|
|
|
|
testCtx.stop()
|
2019-08-27 07:32:36 +03:00
|
|
|
}
|