htlcswitch/switch test: add TestSwitchGetPaymentResult
TestSwitchGetPaymentResult tests that the switch interacts as expected with the circuit map and network result store when looking up the result of a payment ID. This is important for not to lose results under concurrent lookup and receiving results.
This commit is contained in:
parent
dd3abbc4ef
commit
dd88015985
@ -916,3 +916,58 @@ func (m *mockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint, _ []byte,
|
|||||||
Spend: make(chan *chainntnfs.SpendDetail),
|
Spend: make(chan *chainntnfs.SpendDetail),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockCircuitMap struct {
|
||||||
|
lookup chan *PaymentCircuit
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ CircuitMap = (*mockCircuitMap)(nil)
|
||||||
|
|
||||||
|
func (m *mockCircuitMap) OpenCircuits(...Keystone) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockCircuitMap) TrimOpenCircuits(chanID lnwire.ShortChannelID,
|
||||||
|
start uint64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockCircuitMap) DeleteCircuits(inKeys ...CircuitKey) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockCircuitMap) CommitCircuits(
|
||||||
|
circuit ...*PaymentCircuit) (*CircuitFwdActions, error) {
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockCircuitMap) CloseCircuit(outKey CircuitKey) (*PaymentCircuit,
|
||||||
|
error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockCircuitMap) FailCircuit(inKey CircuitKey) (*PaymentCircuit,
|
||||||
|
error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockCircuitMap) LookupCircuit(inKey CircuitKey) *PaymentCircuit {
|
||||||
|
return <-m.lookup
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockCircuitMap) LookupOpenCircuit(outKey CircuitKey) *PaymentCircuit {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockCircuitMap) LookupByPaymentHash(hash [32]byte) []*PaymentCircuit {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockCircuitMap) NumPending() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockCircuitMap) NumOpen() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/btcsuite/fastsha256"
|
"github.com/btcsuite/fastsha256"
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/ticker"
|
"github.com/lightningnetwork/lnd/ticker"
|
||||||
)
|
)
|
||||||
@ -2125,3 +2126,115 @@ func TestUpdateFailMalformedHTLCErrorConversion(t *testing.T) {
|
|||||||
assertPaymentFailure(t)
|
assertPaymentFailure(t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSwitchGetPaymentResult tests that the switch interacts as expected with
|
||||||
|
// the circuit map and network result store when looking up the result of a
|
||||||
|
// payment ID. This is important for not to lose results under concurrent
|
||||||
|
// lookup and receiving results.
|
||||||
|
func TestSwitchGetPaymentResult(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
const paymentID = 123
|
||||||
|
var preimg lntypes.Preimage
|
||||||
|
preimg[0] = 3
|
||||||
|
|
||||||
|
s, err := initSwitchWithDB(testStartingHeight, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to init switch: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.Start(); err != nil {
|
||||||
|
t.Fatalf("unable to start switch: %v", err)
|
||||||
|
}
|
||||||
|
defer s.Stop()
|
||||||
|
|
||||||
|
lookup := make(chan *PaymentCircuit, 1)
|
||||||
|
s.circuits = &mockCircuitMap{
|
||||||
|
lookup: lookup,
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the payment circuit is not found in the circuit map, the payment
|
||||||
|
// result must be found in the store if available. Since we haven't
|
||||||
|
// added anything to the store yet, ErrPaymentIDNotFound should be
|
||||||
|
// returned.
|
||||||
|
lookup <- nil
|
||||||
|
_, err = s.GetPaymentResult(
|
||||||
|
paymentID, lntypes.Hash{}, newMockDeobfuscator(),
|
||||||
|
)
|
||||||
|
if err != ErrPaymentIDNotFound {
|
||||||
|
t.Fatalf("expected ErrPaymentIDNotFound, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next let the lookup find the circuit in the circuit map. It should
|
||||||
|
// subscribe to payment results, and return the result when available.
|
||||||
|
lookup <- &PaymentCircuit{}
|
||||||
|
resultChan, err := s.GetPaymentResult(
|
||||||
|
paymentID, lntypes.Hash{}, newMockDeobfuscator(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to get payment result: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the result to the store.
|
||||||
|
n := &networkResult{
|
||||||
|
msg: &lnwire.UpdateFulfillHTLC{
|
||||||
|
PaymentPreimage: preimg,
|
||||||
|
},
|
||||||
|
unencrypted: true,
|
||||||
|
isResolution: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.networkResults.storeResult(paymentID, n)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to store result: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The result should be availble.
|
||||||
|
select {
|
||||||
|
case res, ok := <-resultChan:
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("channel was closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Error != nil {
|
||||||
|
t.Fatalf("got unexpected error result")
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Preimage != preimg {
|
||||||
|
t.Fatalf("expected preimg %v, got %v",
|
||||||
|
preimg, res.Preimage)
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
t.Fatalf("result not received")
|
||||||
|
}
|
||||||
|
|
||||||
|
// As a final test, try to get the result again. Now that is no longer
|
||||||
|
// in the circuit map, it should be immediately available from the
|
||||||
|
// store.
|
||||||
|
lookup <- nil
|
||||||
|
resultChan, err = s.GetPaymentResult(
|
||||||
|
paymentID, lntypes.Hash{}, newMockDeobfuscator(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to get payment result: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case res, ok := <-resultChan:
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("channel was closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Error != nil {
|
||||||
|
t.Fatalf("got unexpected error result")
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Preimage != preimg {
|
||||||
|
t.Fatalf("expected preimg %v, got %v",
|
||||||
|
preimg, res.Preimage)
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
t.Fatalf("result not received")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user