github.com/decred/dcrlnd@v0.7.6/routing/control_tower_test.go (about)

     1  package routing
     2  
     3  import (
     4  	"crypto/rand"
     5  	"crypto/sha256"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"reflect"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/davecgh/go-spew/spew"
    14  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    15  	"github.com/decred/dcrlnd/channeldb"
    16  	"github.com/decred/dcrlnd/routing/route"
    17  
    18  	"github.com/decred/dcrlnd/lntypes"
    19  )
    20  
    21  var (
    22  	priv, _ = secp256k1.GeneratePrivateKey()
    23  	pub     = priv.PubKey()
    24  
    25  	testHop = &route.Hop{
    26  		PubKeyBytes:      route.NewVertex(pub),
    27  		ChannelID:        12345,
    28  		OutgoingTimeLock: 111,
    29  		AmtToForward:     555,
    30  		LegacyPayload:    true,
    31  	}
    32  
    33  	testRoute = route.Route{
    34  		TotalTimeLock: 123,
    35  		TotalAmount:   1234567,
    36  		SourcePubKey:  route.NewVertex(pub),
    37  		Hops: []*route.Hop{
    38  			testHop,
    39  			testHop,
    40  		},
    41  	}
    42  
    43  	testTimeout = 5 * time.Second
    44  )
    45  
    46  // TestControlTowerSubscribeUnknown tests that subscribing to an unknown
    47  // payment fails.
    48  func TestControlTowerSubscribeUnknown(t *testing.T) {
    49  	t.Parallel()
    50  
    51  	db, err := initDB()
    52  	if err != nil {
    53  		t.Fatalf("unable to init db: %v", err)
    54  	}
    55  
    56  	pControl := NewControlTower(channeldb.NewPaymentControl(db))
    57  
    58  	// Subscription should fail when the payment is not known.
    59  	_, err = pControl.SubscribePayment(lntypes.Hash{1})
    60  	if err != channeldb.ErrPaymentNotInitiated {
    61  		t.Fatal("expected subscribe to fail for unknown payment")
    62  	}
    63  }
    64  
    65  // TestControlTowerSubscribeSuccess tests that payment updates for a
    66  // successful payment are properly sent to subscribers.
    67  func TestControlTowerSubscribeSuccess(t *testing.T) {
    68  	t.Parallel()
    69  
    70  	db, err := initDB()
    71  	if err != nil {
    72  		t.Fatalf("unable to init db: %v", err)
    73  	}
    74  
    75  	pControl := NewControlTower(channeldb.NewPaymentControl(db))
    76  
    77  	// Initiate a payment.
    78  	info, attempt, preimg, err := genInfo()
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  
    83  	err = pControl.InitPayment(info.PaymentIdentifier, info)
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  
    88  	// Subscription should succeed and immediately report the InFlight
    89  	// status.
    90  	subscriber1, err := pControl.SubscribePayment(info.PaymentIdentifier)
    91  	if err != nil {
    92  		t.Fatalf("expected subscribe to succeed, but got: %v", err)
    93  	}
    94  
    95  	// Register an attempt.
    96  	err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  
   101  	// Register a second subscriber after the first attempt has started.
   102  	subscriber2, err := pControl.SubscribePayment(info.PaymentIdentifier)
   103  	if err != nil {
   104  		t.Fatalf("expected subscribe to succeed, but got: %v", err)
   105  	}
   106  
   107  	// Mark the payment as successful.
   108  	settleInfo := channeldb.HTLCSettleInfo{
   109  		Preimage: preimg,
   110  	}
   111  	htlcAttempt, err := pControl.SettleAttempt(
   112  		info.PaymentIdentifier, attempt.AttemptID, &settleInfo,
   113  	)
   114  	if err != nil {
   115  		t.Fatal(err)
   116  	}
   117  	if *htlcAttempt.Settle != settleInfo {
   118  		t.Fatalf("unexpected settle info returned")
   119  	}
   120  
   121  	// Register a third subscriber after the payment succeeded.
   122  	subscriber3, err := pControl.SubscribePayment(info.PaymentIdentifier)
   123  	if err != nil {
   124  		t.Fatalf("expected subscribe to succeed, but got: %v", err)
   125  	}
   126  
   127  	// We expect all subscribers to now report the final outcome followed by
   128  	// no other events.
   129  	subscribers := []*ControlTowerSubscriber{
   130  		subscriber1, subscriber2, subscriber3,
   131  	}
   132  
   133  	for _, s := range subscribers {
   134  		var result *channeldb.MPPayment
   135  		for result == nil || result.Status == channeldb.StatusInFlight {
   136  			select {
   137  			case item := <-s.Updates:
   138  				result = item.(*channeldb.MPPayment)
   139  			case <-time.After(testTimeout):
   140  				t.Fatal("timeout waiting for payment result")
   141  			}
   142  		}
   143  
   144  		if result.Status != channeldb.StatusSucceeded {
   145  			t.Fatal("unexpected payment state")
   146  		}
   147  		settle, _ := result.TerminalInfo()
   148  		if settle.Preimage != preimg {
   149  			t.Fatal("unexpected preimage")
   150  		}
   151  		if len(result.HTLCs) != 1 {
   152  			t.Fatalf("expected one htlc, got %d", len(result.HTLCs))
   153  		}
   154  		htlc := result.HTLCs[0]
   155  		if !reflect.DeepEqual(htlc.Route, attempt.Route) {
   156  			t.Fatalf("unexpected htlc route: %v vs %v",
   157  				spew.Sdump(htlc.Route),
   158  				spew.Sdump(attempt.Route))
   159  		}
   160  
   161  		// After the final event, we expect the channel to be closed.
   162  		select {
   163  		case _, ok := <-s.Updates:
   164  			if ok {
   165  				t.Fatal("expected channel to be closed")
   166  			}
   167  		case <-time.After(testTimeout):
   168  			t.Fatal("timeout waiting for result channel close")
   169  		}
   170  	}
   171  }
   172  
   173  // TestPaymentControlSubscribeFail tests that payment updates for a
   174  // failed payment are properly sent to subscribers.
   175  func TestPaymentControlSubscribeFail(t *testing.T) {
   176  	t.Parallel()
   177  
   178  	t.Run("register attempt", func(t *testing.T) {
   179  		testPaymentControlSubscribeFail(t, true)
   180  	})
   181  	t.Run("no register attempt", func(t *testing.T) {
   182  		testPaymentControlSubscribeFail(t, false)
   183  	})
   184  }
   185  
   186  func testPaymentControlSubscribeFail(t *testing.T, registerAttempt bool) {
   187  	db, err := initDB()
   188  	if err != nil {
   189  		t.Fatalf("unable to init db: %v", err)
   190  	}
   191  
   192  	pControl := NewControlTower(channeldb.NewPaymentControl(db))
   193  
   194  	// Initiate a payment.
   195  	info, attempt, _, err := genInfo()
   196  	if err != nil {
   197  		t.Fatal(err)
   198  	}
   199  
   200  	err = pControl.InitPayment(info.PaymentIdentifier, info)
   201  	if err != nil {
   202  		t.Fatal(err)
   203  	}
   204  
   205  	// Subscription should succeed.
   206  	subscriber1, err := pControl.SubscribePayment(info.PaymentIdentifier)
   207  	if err != nil {
   208  		t.Fatalf("expected subscribe to succeed, but got: %v", err)
   209  	}
   210  
   211  	// Conditionally register the attempt based on the test type. This
   212  	// allows us to simulate failing after attempting with an htlc or before
   213  	// making any attempts at all.
   214  	if registerAttempt {
   215  		// Register an attempt.
   216  		err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
   217  		if err != nil {
   218  			t.Fatal(err)
   219  		}
   220  
   221  		// Fail the payment attempt.
   222  		failInfo := channeldb.HTLCFailInfo{
   223  			Reason: channeldb.HTLCFailInternal,
   224  		}
   225  		htlcAttempt, err := pControl.FailAttempt(
   226  			info.PaymentIdentifier, attempt.AttemptID, &failInfo,
   227  		)
   228  		if err != nil {
   229  			t.Fatalf("unable to fail htlc: %v", err)
   230  		}
   231  		if *htlcAttempt.Failure != failInfo {
   232  			t.Fatalf("unexpected fail info returned")
   233  		}
   234  	}
   235  
   236  	// Mark the payment as failed.
   237  	if err := pControl.Fail(info.PaymentIdentifier, channeldb.FailureReasonTimeout); err != nil {
   238  		t.Fatal(err)
   239  	}
   240  
   241  	// Register a second subscriber after the payment failed.
   242  	subscriber2, err := pControl.SubscribePayment(info.PaymentIdentifier)
   243  	if err != nil {
   244  		t.Fatalf("expected subscribe to succeed, but got: %v", err)
   245  	}
   246  
   247  	// We expect all subscribers to now report the final outcome followed by
   248  	// no other events.
   249  	subscribers := []*ControlTowerSubscriber{
   250  		subscriber1, subscriber2,
   251  	}
   252  
   253  	for _, s := range subscribers {
   254  		var result *channeldb.MPPayment
   255  		for result == nil || result.Status == channeldb.StatusInFlight {
   256  			select {
   257  			case item := <-s.Updates:
   258  				result = item.(*channeldb.MPPayment)
   259  			case <-time.After(testTimeout):
   260  				t.Fatal("timeout waiting for payment result")
   261  			}
   262  		}
   263  
   264  		if result.Status == channeldb.StatusSucceeded {
   265  			t.Fatal("unexpected payment state")
   266  		}
   267  
   268  		// There will either be one or zero htlcs depending on whether
   269  		// or not the attempt was registered. Assert the correct number
   270  		// is present, and the route taken if the attempt was
   271  		// registered.
   272  		if registerAttempt {
   273  			if len(result.HTLCs) != 1 {
   274  				t.Fatalf("expected 1 htlc, got: %d",
   275  					len(result.HTLCs))
   276  			}
   277  
   278  			htlc := result.HTLCs[0]
   279  			if !reflect.DeepEqual(htlc.Route, testRoute) {
   280  				t.Fatalf("unexpected htlc route: %v vs %v",
   281  					spew.Sdump(htlc.Route),
   282  					spew.Sdump(testRoute))
   283  			}
   284  		} else if len(result.HTLCs) != 0 {
   285  			t.Fatalf("expected 0 htlcs, got: %d",
   286  				len(result.HTLCs))
   287  		}
   288  
   289  		if *result.FailureReason != channeldb.FailureReasonTimeout {
   290  			t.Fatal("unexpected failure reason")
   291  		}
   292  
   293  		// After the final event, we expect the channel to be closed.
   294  		select {
   295  		case _, ok := <-s.Updates:
   296  			if ok {
   297  				t.Fatal("expected channel to be closed")
   298  			}
   299  		case <-time.After(testTimeout):
   300  			t.Fatal("timeout waiting for result channel close")
   301  		}
   302  	}
   303  }
   304  
   305  func initDB() (*channeldb.DB, error) {
   306  	tempPath, err := ioutil.TempDir("", "routingdb")
   307  	if err != nil {
   308  		return nil, err
   309  	}
   310  
   311  	db, err := channeldb.Open(tempPath)
   312  	if err != nil {
   313  		return nil, err
   314  	}
   315  
   316  	return db, err
   317  }
   318  
   319  func genInfo() (*channeldb.PaymentCreationInfo, *channeldb.HTLCAttemptInfo,
   320  	lntypes.Preimage, error) {
   321  
   322  	preimage, err := genPreimage()
   323  	if err != nil {
   324  		return nil, nil, preimage, fmt.Errorf("unable to "+
   325  			"generate preimage: %v", err)
   326  	}
   327  
   328  	rhash := sha256.Sum256(preimage[:])
   329  	return &channeldb.PaymentCreationInfo{
   330  			PaymentIdentifier: rhash,
   331  			Value:             testRoute.ReceiverAmt(),
   332  			CreationTime:      time.Unix(time.Now().Unix(), 0),
   333  			PaymentRequest:    []byte("hola"),
   334  		},
   335  		channeldb.NewHtlcAttemptInfo(
   336  			1, priv, testRoute, time.Time{}, nil,
   337  		), preimage, nil
   338  }
   339  
   340  func genPreimage() ([32]byte, error) {
   341  	var preimage [32]byte
   342  	if _, err := io.ReadFull(rand.Reader, preimage[:]); err != nil {
   343  		return preimage, err
   344  	}
   345  	return preimage, nil
   346  }