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

     1  package route
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"testing"
     7  
     8  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
     9  	"github.com/decred/dcrlnd/lnwire"
    10  	"github.com/decred/dcrlnd/record"
    11  )
    12  
    13  var (
    14  	testPrivKeyBytes, _ = hex.DecodeString("e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734")
    15  	testPubKey          = secp256k1.PrivKeyFromBytes(testPrivKeyBytes).PubKey()
    16  	testPubKeyBytes, _  = NewVertexFromBytes(testPubKey.SerializeCompressed())
    17  )
    18  
    19  // TestRouteTotalFees checks that a route reports the expected total fee.
    20  func TestRouteTotalFees(t *testing.T) {
    21  	t.Parallel()
    22  
    23  	// Make sure empty route returns a 0 fee, and zero amount.
    24  	r := &Route{}
    25  	if r.TotalFees() != 0 {
    26  		t.Fatalf("expected 0 fees, got %v", r.TotalFees())
    27  	}
    28  	if r.ReceiverAmt() != 0 {
    29  		t.Fatalf("expected 0 amt, got %v", r.ReceiverAmt())
    30  	}
    31  
    32  	// Make sure empty route won't be allowed in the constructor.
    33  	amt := lnwire.MilliAtom(1000)
    34  	_, err := NewRouteFromHops(amt, 100, Vertex{}, []*Hop{})
    35  	if err != ErrNoRouteHopsProvided {
    36  		t.Fatalf("expected ErrNoRouteHopsProvided, got %v", err)
    37  	}
    38  
    39  	// For one-hop routes the fee should be 0, since the last node will
    40  	// receive the full amount.
    41  	hops := []*Hop{
    42  		{
    43  			PubKeyBytes:      Vertex{},
    44  			ChannelID:        1,
    45  			OutgoingTimeLock: 44,
    46  			AmtToForward:     amt,
    47  		},
    48  	}
    49  	r, err = NewRouteFromHops(amt, 100, Vertex{}, hops)
    50  	if err != nil {
    51  		t.Fatal(err)
    52  	}
    53  
    54  	if r.TotalFees() != 0 {
    55  		t.Fatalf("expected 0 fees, got %v", r.TotalFees())
    56  	}
    57  
    58  	if r.ReceiverAmt() != amt {
    59  		t.Fatalf("expected %v amt, got %v", amt, r.ReceiverAmt())
    60  	}
    61  
    62  	// Append the route with a node, making the first one take a fee.
    63  	fee := lnwire.MilliAtom(100)
    64  	hops = append(hops, &Hop{
    65  		PubKeyBytes:      Vertex{},
    66  		ChannelID:        2,
    67  		OutgoingTimeLock: 33,
    68  		AmtToForward:     amt - fee,
    69  	},
    70  	)
    71  
    72  	r, err = NewRouteFromHops(amt, 100, Vertex{}, hops)
    73  	if err != nil {
    74  		t.Fatal(err)
    75  	}
    76  
    77  	if r.TotalFees() != fee {
    78  		t.Fatalf("expected %v fees, got %v", fee, r.TotalFees())
    79  	}
    80  
    81  	if r.ReceiverAmt() != amt-fee {
    82  		t.Fatalf("expected %v amt, got %v", amt-fee, r.ReceiverAmt())
    83  	}
    84  }
    85  
    86  var (
    87  	testAmt  = lnwire.MilliAtom(1000)
    88  	testAddr = [32]byte{0x01, 0x02}
    89  )
    90  
    91  // TestMPPHop asserts that a Hop will encode a non-nil MPP to final nodes, and
    92  // fail when trying to send to intermediaries.
    93  func TestMPPHop(t *testing.T) {
    94  	t.Parallel()
    95  
    96  	hop := Hop{
    97  		ChannelID:        1,
    98  		OutgoingTimeLock: 44,
    99  		AmtToForward:     testAmt,
   100  		LegacyPayload:    false,
   101  		MPP:              record.NewMPP(testAmt, testAddr),
   102  	}
   103  
   104  	// Encoding an MPP record to an intermediate hop should result in a
   105  	// failure.
   106  	var b bytes.Buffer
   107  	err := hop.PackHopPayload(&b, 2)
   108  	if err != ErrIntermediateMPPHop {
   109  		t.Fatalf("expected err: %v, got: %v",
   110  			ErrIntermediateMPPHop, err)
   111  	}
   112  
   113  	// Encoding an MPP record to a final hop should be successful.
   114  	b.Reset()
   115  	err = hop.PackHopPayload(&b, 0)
   116  	if err != nil {
   117  		t.Fatalf("expected err: %v, got: %v", nil, err)
   118  	}
   119  }
   120  
   121  // TestAMPHop asserts that a Hop will encode a non-nil AMP to final nodes of an
   122  // MPP record is also present, and fail otherwise.
   123  func TestAMPHop(t *testing.T) {
   124  	t.Parallel()
   125  
   126  	hop := Hop{
   127  		ChannelID:        1,
   128  		OutgoingTimeLock: 44,
   129  		AmtToForward:     testAmt,
   130  		LegacyPayload:    false,
   131  		AMP:              record.NewAMP([32]byte{}, [32]byte{}, 3),
   132  	}
   133  
   134  	// Encoding an AMP record to an intermediate hop w/o an MPP record
   135  	// should result in a failure.
   136  	var b bytes.Buffer
   137  	err := hop.PackHopPayload(&b, 2)
   138  	if err != ErrAMPMissingMPP {
   139  		t.Fatalf("expected err: %v, got: %v",
   140  			ErrAMPMissingMPP, err)
   141  	}
   142  
   143  	// Encoding an AMP record to a final hop w/o an MPP record should result
   144  	// in a failure.
   145  	b.Reset()
   146  	err = hop.PackHopPayload(&b, 0)
   147  	if err != ErrAMPMissingMPP {
   148  		t.Fatalf("expected err: %v, got: %v",
   149  			ErrAMPMissingMPP, err)
   150  	}
   151  
   152  	// Encoding an AMP record to a final hop w/ an MPP record should be
   153  	// successful.
   154  	hop.MPP = record.NewMPP(testAmt, testAddr)
   155  	b.Reset()
   156  	err = hop.PackHopPayload(&b, 0)
   157  	if err != nil {
   158  		t.Fatalf("expected err: %v, got: %v", nil, err)
   159  	}
   160  }
   161  
   162  // TestPayloadSize tests the payload size calculation that is provided by Hop
   163  // structs.
   164  func TestPayloadSize(t *testing.T) {
   165  	hops := []*Hop{
   166  		{
   167  			PubKeyBytes:      testPubKeyBytes,
   168  			AmtToForward:     1000,
   169  			OutgoingTimeLock: 600000,
   170  			ChannelID:        3432483437438,
   171  			LegacyPayload:    true,
   172  		},
   173  		{
   174  			PubKeyBytes:      testPubKeyBytes,
   175  			AmtToForward:     1200,
   176  			OutgoingTimeLock: 700000,
   177  			ChannelID:        63584534844,
   178  		},
   179  		{
   180  			PubKeyBytes:      testPubKeyBytes,
   181  			AmtToForward:     1200,
   182  			OutgoingTimeLock: 700000,
   183  			MPP:              record.NewMPP(500, [32]byte{}),
   184  			AMP:              record.NewAMP([32]byte{}, [32]byte{}, 8),
   185  			CustomRecords: map[uint64][]byte{
   186  				100000:  {1, 2, 3},
   187  				1000000: {4, 5},
   188  			},
   189  		},
   190  	}
   191  
   192  	rt := Route{
   193  		Hops: hops,
   194  	}
   195  	path, err := rt.ToSphinxPath()
   196  	if err != nil {
   197  		t.Fatal(err)
   198  	}
   199  
   200  	for i, onionHop := range path[:path.TrueRouteLength()] {
   201  		hop := hops[i]
   202  		var nextChan uint64
   203  		if i < len(hops)-1 {
   204  			nextChan = hops[i+1].ChannelID
   205  		}
   206  
   207  		expected := uint64(onionHop.HopPayload.NumBytes())
   208  		actual := hop.PayloadSize(nextChan)
   209  		if expected != actual {
   210  			t.Fatalf("unexpected payload size at hop %v: "+
   211  				"expected %v, got %v",
   212  				i, expected, actual)
   213  		}
   214  	}
   215  }