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 }