|
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.Diagnostics; |
| 4 | +using System.Threading; |
| 5 | +using System.Runtime.InteropServices; |
4 | 6 | using org.ldk.enums; |
5 | 7 | using org.ldk.util; |
6 | 8 | using org.ldk.structs; |
@@ -350,12 +352,107 @@ static void Bolt12ParseTest() { |
350 | 352 | Assert(offer.to_str() == offerStr, 109); |
351 | 353 | } |
352 | 354 |
|
| 355 | + static Offer BuildOffer(Nonce nonce, KeysManager keys) { |
| 356 | + Result_PublicKeyNoneZ id_res = keys.as_NodeSigner().get_node_id(Recipient.LDKRecipient_Node); |
| 357 | + byte[] node_id = ((Result_PublicKeyNoneZ.Result_PublicKeyNoneZ_OK)id_res).res; |
| 358 | + ExpandedKey inb_key = ExpandedKey.of(keys.as_NodeSigner().get_inbound_payment_key_material()); |
| 359 | + OfferWithDerivedMetadataBuilder builder = OfferWithDerivedMetadataBuilder.deriving_signing_pubkey(node_id, inb_key, nonce); |
| 360 | + Result_OfferBolt12SemanticErrorZ res = builder.build(); |
| 361 | + return ((Result_OfferBolt12SemanticErrorZ.Result_OfferBolt12SemanticErrorZ_OK) res).res; |
| 362 | + } |
| 363 | + |
| 364 | + static InvoiceRequestWithDerivedPayerIdBuilder InvReqBuilderFromOffer(Offer offer, KeysManager keys) { |
| 365 | + ExpandedKey inb_key = ExpandedKey.of(keys.as_NodeSigner().get_inbound_payment_key_material()); |
| 366 | + Nonce nonce = Nonce.from_entropy_source(keys.as_EntropySource()); |
| 367 | + Result_InvoiceRequestWithDerivedPayerIdBuilderBolt12SemanticErrorZ builder_res = |
| 368 | + offer.request_invoice_deriving_payer_id(inb_key, nonce, new byte[32]); |
| 369 | + InvoiceRequestWithDerivedPayerIdBuilder builder = |
| 370 | + ((Result_InvoiceRequestWithDerivedPayerIdBuilderBolt12SemanticErrorZ.Result_InvoiceRequestWithDerivedPayerIdBuilderBolt12SemanticErrorZ_OK)builder_res).res; |
| 371 | + return builder; |
| 372 | + } |
| 373 | + |
| 374 | + static InvoiceRequest BuildInvReq(InvoiceRequestWithDerivedPayerIdBuilder builder) { |
| 375 | + Result_InvoiceRequestBolt12SemanticErrorZ res = builder.build_and_sign(); |
| 376 | + return ((Result_InvoiceRequestBolt12SemanticErrorZ.Result_InvoiceRequestBolt12SemanticErrorZ_OK)res).res; |
| 377 | + } |
| 378 | + |
| 379 | + static InvoiceWithDerivedSigningPubkeyBuilder InvBuilderFromInvReq(Nonce receiver_nonce, InvoiceRequest invreq, KeysManager keys) { |
| 380 | + ExpandedKey inb_key = ExpandedKey.of(keys.as_NodeSigner().get_inbound_payment_key_material()); |
| 381 | + Result_VerifiedInvoiceRequestNoneZ verified_res = invreq.verify_using_recipient_data(receiver_nonce, inb_key); |
| 382 | + VerifiedInvoiceRequest verified_invreq = |
| 383 | + ((Result_VerifiedInvoiceRequestNoneZ.Result_VerifiedInvoiceRequestNoneZ_OK)verified_res).res; |
| 384 | + Result_InvoiceWithDerivedSigningPubkeyBuilderBolt12SemanticErrorZ builder_res = |
| 385 | + verified_invreq.respond_using_derived_keys(new BlindedPaymentPath[0], new byte[32]); |
| 386 | + InvoiceWithDerivedSigningPubkeyBuilder builder = |
| 387 | + ((Result_InvoiceWithDerivedSigningPubkeyBuilderBolt12SemanticErrorZ.Result_InvoiceWithDerivedSigningPubkeyBuilderBolt12SemanticErrorZ_OK)builder_res).res; |
| 388 | + return builder; |
| 389 | + } |
| 390 | + |
| 391 | + static InvoiceRequestWithDerivedPayerIdBuilder InvReqBuilder(Nonce receiver_nonce, KeysManager payer, KeysManager recipient) { |
| 392 | + // Under the hood, InvoiceRequestWithDerivedPayerIdBuilder holds a reference to some |
| 393 | + // fields in the Offer. Thus, we build an Offer here, then return only the builder, |
| 394 | + // hoping the GC will cause us to free the Offer and use-after-free. |
| 395 | + Offer offer = BuildOffer(receiver_nonce, payer); |
| 396 | + return InvReqBuilderFromOffer(offer, recipient); |
| 397 | + } |
| 398 | + |
| 399 | + static InvoiceWithDerivedSigningPubkeyBuilder InvBuilderFromInvReqBuilder(Nonce receiver_nonce, InvoiceRequestWithDerivedPayerIdBuilder builder, KeysManager payer, KeysManager recipient) { |
| 400 | + // Same as above, but for the Invoice itself |
| 401 | + InvoiceRequest invreq = BuildInvReq(builder); |
| 402 | + return InvBuilderFromInvReq(receiver_nonce, invreq, recipient); |
| 403 | + } |
| 404 | + |
| 405 | + static void Bolt12RespondTest() { |
| 406 | + // Build an Invoice out of an Offer, step by step. We do each step in its own function |
| 407 | + // to give the background GC a chance to free things out from under us. |
| 408 | + KeysManager sender = KeysManager.of(new byte[32], 42, 42); |
| 409 | + byte[] receiver_keys = new byte[32]; |
| 410 | + receiver_keys[10] = 42; |
| 411 | + KeysManager receiver = KeysManager.of(receiver_keys, 42, 42); |
| 412 | + |
| 413 | + // Run the GC between each step to see if the reference the builders hold to the |
| 414 | + // original Offer/InvoiceRequest is freed out from under us before building. |
| 415 | + Nonce receiver_nonce = Nonce.from_entropy_source(receiver.as_EntropySource()); |
| 416 | + InvoiceRequestWithDerivedPayerIdBuilder invreq_builder = InvReqBuilder(receiver_nonce, sender, receiver); |
| 417 | + System.GC.Collect(); |
| 418 | + GC.WaitForPendingFinalizers(); |
| 419 | + InvoiceWithDerivedSigningPubkeyBuilder inv_builder = InvBuilderFromInvReqBuilder(receiver_nonce, invreq_builder, sender, receiver); |
| 420 | + System.GC.Collect(); |
| 421 | + GC.WaitForPendingFinalizers(); |
| 422 | + Result_Bolt12InvoiceBolt12SemanticErrorZ inv_res = inv_builder.build_and_sign(); |
| 423 | + Assert(inv_res.is_ok(), 200); |
| 424 | + } |
| 425 | + |
| 426 | + static void GCLoop() { |
| 427 | + while (Thread.CurrentThread.IsAlive) { |
| 428 | + System.GC.Collect(); |
| 429 | + GC.WaitForPendingFinalizers(); |
| 430 | + try { |
| 431 | + Thread.Sleep(new TimeSpan(1)); |
| 432 | + } catch (ThreadInterruptedException _) { |
| 433 | + break; |
| 434 | + } |
| 435 | + } |
| 436 | + } |
| 437 | + |
353 | 438 | static void Main(string[] args) { |
| 439 | + Thread gc_thread = null; |
| 440 | + if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { |
| 441 | + // No idea why this dies on macOS, but it does, so disable it. |
| 442 | + gc_thread = new Thread(GCLoop); |
| 443 | + gc_thread.Start(); |
| 444 | + } |
| 445 | + |
354 | 446 | SimpleConstructionTest(); |
355 | 447 | SimpleTraitTest(); |
356 | 448 | NodeTest(); |
357 | 449 | Bolt12ParseTest(); |
358 | 450 |
|
| 451 | + if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { |
| 452 | + gc_thread.Interrupt(); |
| 453 | + gc_thread.Join(); |
| 454 | + } |
| 455 | + |
359 | 456 | Console.WriteLine("\n\nTESTS PASSED\n\n"); |
360 | 457 | System.GC.Collect(); |
361 | 458 | GC.WaitForPendingFinalizers(); |
|
0 commit comments