script_utils_test.go
1 package input 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "encoding/hex" 7 "fmt" 8 "testing" 9 10 "github.com/btcsuite/btcd/btcec/v2" 11 "github.com/btcsuite/btcd/btcec/v2/ecdsa" 12 "github.com/btcsuite/btcd/btcutil" 13 "github.com/btcsuite/btcd/chaincfg/chainhash" 14 "github.com/btcsuite/btcd/txscript" 15 "github.com/btcsuite/btcd/wire" 16 "github.com/lightningnetwork/lnd/keychain" 17 "github.com/stretchr/testify/require" 18 ) 19 20 // assertEngineExecution executes the VM returned by the newEngine closure, 21 // asserting the result matches the validity expectation. In the case where it 22 // doesn't match the expectation, it executes the script step-by-step and 23 // prints debug information to stdout. 24 func assertEngineExecution(t *testing.T, testNum int, valid bool, 25 newEngine func() (*txscript.Engine, error)) { 26 27 t.Helper() 28 29 // Get a new VM to execute. 30 vm, err := newEngine() 31 require.NoError(t, err, "unable to create engine") 32 33 // Execute the VM, only go on to the step-by-step execution if 34 // it doesn't validate as expected. 35 vmErr := vm.Execute() 36 if valid == (vmErr == nil) { 37 return 38 } 39 40 // Now that the execution didn't match what we expected, fetch a new VM 41 // to step through. 42 vm, err = newEngine() 43 require.NoError(t, err, "unable to create engine") 44 45 // This buffer will trace execution of the Script, dumping out 46 // to stdout. 47 var debugBuf bytes.Buffer 48 49 done := false 50 for !done { 51 dis, err := vm.DisasmPC() 52 if err != nil { 53 t.Fatalf("stepping (%v)\n", err) 54 } 55 debugBuf.WriteString(fmt.Sprintf("Stepping %v\n", dis)) 56 57 done, err = vm.Step() 58 if err != nil && valid { 59 t.Log(debugBuf.String()) 60 t.Fatalf("spend test case #%v failed, spend "+ 61 "should be valid: %v", testNum, err) 62 } else if err == nil && !valid && done { 63 t.Log(debugBuf.String()) 64 t.Fatalf("spend test case #%v succeed, spend "+ 65 "should be invalid: %v", testNum, err) 66 } 67 68 debugBuf.WriteString(fmt.Sprintf("Stack: %v\n", 69 vm.GetStack())) 70 debugBuf.WriteString(fmt.Sprintf("AltStack: %v\n", 71 vm.GetAltStack())) 72 debugBuf.WriteString("-----\n") 73 } 74 75 // If we get to this point the unexpected case was not reached 76 // during step execution, which happens for some checks, like 77 // the clean-stack rule. 78 validity := "invalid" 79 if valid { 80 validity = "valid" 81 } 82 83 t.Log(debugBuf.String()) 84 t.Fatalf("%v spend test case #%v execution ended with: %v", validity, testNum, vmErr) 85 } 86 87 // TestRevocationKeyDerivation tests that given a public key, and a revocation 88 // hash, the homomorphic revocation public and private key derivation work 89 // properly. 90 func TestRevocationKeyDerivation(t *testing.T) { 91 t.Parallel() 92 93 // First, we'll generate a commitment point, and a commitment secret. 94 // These will be used to derive the ultimate revocation keys. 95 revocationPreimage := testHdSeed.CloneBytes() 96 commitSecret, commitPoint := btcec.PrivKeyFromBytes(revocationPreimage) 97 98 // With the commitment secrets generated, we'll now create the base 99 // keys we'll use to derive the revocation key from. 100 basePriv, basePub := btcec.PrivKeyFromBytes(testWalletPrivKey) 101 102 // With the point and key obtained, we can now derive the revocation 103 // key itself. 104 revocationPub := DeriveRevocationPubkey(basePub, commitPoint) 105 106 // The revocation public key derived from the original public key, and 107 // the one derived from the private key should be identical. 108 revocationPriv := DeriveRevocationPrivKey(basePriv, commitSecret) 109 if !revocationPub.IsEqual(revocationPriv.PubKey()) { 110 t.Fatalf("derived public keys don't match!") 111 } 112 } 113 114 // TestTweakKeyDerivation tests that given a public key, and commitment tweak, 115 // then we're able to properly derive a tweaked private key that corresponds to 116 // the computed tweak public key. This scenario ensure that our key derivation 117 // for any of the non revocation keys on the commitment transaction is correct. 118 func TestTweakKeyDerivation(t *testing.T) { 119 t.Parallel() 120 121 // First, we'll generate a base public key that we'll be "tweaking". 122 baseSecret := testHdSeed.CloneBytes() 123 basePriv, basePub := btcec.PrivKeyFromBytes(baseSecret) 124 125 // With the base key create, we'll now create a commitment point, and 126 // from that derive the bytes we'll used to tweak the base public key. 127 commitPoint := ComputeCommitmentPoint(bobsPrivKey) 128 commitTweak := SingleTweakBytes(commitPoint, basePub) 129 130 // Next, we'll modify the public key. When we apply the same operation 131 // to the private key we should get a key that matches. 132 tweakedPub := TweakPubKey(basePub, commitPoint) 133 134 // Finally, attempt to re-generate the private key that matches the 135 // tweaked public key. The derived key should match exactly. 136 derivedPriv := TweakPrivKey(basePriv, commitTweak) 137 if !derivedPriv.PubKey().IsEqual(tweakedPub) { 138 t.Fatalf("pub keys don't match") 139 } 140 } 141 142 // makeWitnessTestCase is a helper function used within test cases involving 143 // the validity of a crafted witness. This function is a wrapper function which 144 // allows constructing table-driven tests. In the case of an error while 145 // constructing the witness, the test fails fatally. 146 func makeWitnessTestCase(t *testing.T, 147 f func() (wire.TxWitness, error)) func() wire.TxWitness { 148 149 return func() wire.TxWitness { 150 witness, err := f() 151 if err != nil { 152 t.Fatalf("unable to create witness test case: %v", err) 153 } 154 155 return witness 156 } 157 } 158 159 // TestHTLCSenderSpendValidation tests all possible valid+invalid redemption 160 // paths in the script used within the sender's commitment transaction for an 161 // outgoing HTLC. 162 // 163 // The following cases are exercised by this test: 164 // sender script: 165 // - receiver spends 166 // - revoke w/ sig 167 // - HTLC with invalid preimage size 168 // - HTLC with valid preimage size + sig 169 // - sender spends 170 // - invalid lock-time for CLTV 171 // - invalid sequence for CSV 172 // - valid lock-time+sequence, valid sig 173 func TestHTLCSenderSpendValidation(t *testing.T) { 174 t.Parallel() 175 176 // We generate a fake output, and the corresponding txin. This output 177 // doesn't need to exist, as we'll only be validating spending from the 178 // transaction that references this. 179 txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) 180 require.NoError(t, err, "unable to create txid") 181 fundingOut := &wire.OutPoint{ 182 Hash: *txid, 183 Index: 50, 184 } 185 fakeFundingTxIn := wire.NewTxIn(fundingOut, nil, nil) 186 187 // Next we'll the commitment secret for our commitment tx and also the 188 // revocation key that we'll use as well. 189 revokePreimage := testHdSeed.CloneBytes() 190 commitSecret, commitPoint := btcec.PrivKeyFromBytes(revokePreimage) 191 192 // Generate a payment preimage to be used below. 193 paymentPreimage := revokePreimage 194 paymentPreimage[0] ^= 1 195 paymentHash := sha256.Sum256(paymentPreimage[:]) 196 197 // We'll also need some tests keys for alice and bob, and metadata of 198 // the HTLC output. 199 aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(testWalletPrivKey) 200 bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(bobsPrivKey) 201 paymentAmt := btcutil.Amount(1 * 10e8) 202 203 aliceLocalKey := TweakPubKey(aliceKeyPub, commitPoint) 204 bobLocalKey := TweakPubKey(bobKeyPub, commitPoint) 205 206 // As we'll be modeling spends from Alice's commitment transaction, 207 // we'll be using Bob's base point for the revocation key. 208 revocationKey := DeriveRevocationPubkey(bobKeyPub, commitPoint) 209 210 bobCommitTweak := SingleTweakBytes(commitPoint, bobKeyPub) 211 aliceCommitTweak := SingleTweakBytes(commitPoint, aliceKeyPub) 212 213 // Finally, we'll create mock signers for both of them based on their 214 // private keys. This test simplifies a bit and uses the same key as 215 // the base point for all scripts and derivations. 216 bobSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{bobKeyPriv}} 217 aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}} 218 219 var ( 220 htlcWitnessScript, htlcPkScript []byte 221 htlcOutput *wire.TxOut 222 sweepTxSigHashes *txscript.TxSigHashes 223 senderCommitTx, sweepTx *wire.MsgTx 224 bobRecvrSig *ecdsa.Signature 225 bobSigHash txscript.SigHashType 226 ) 227 228 // genCommitTx generates a commitment tx where the htlc output requires 229 // confirmation to be spent according to 'confirmed'. 230 genCommitTx := func(confirmed bool) { 231 // Generate the raw HTLC redemption scripts, and its p2wsh 232 // counterpart. 233 htlcWitnessScript, err = SenderHTLCScript( 234 aliceLocalKey, bobLocalKey, revocationKey, 235 paymentHash[:], confirmed, 236 ) 237 if err != nil { 238 t.Fatalf("unable to create htlc sender script: %v", err) 239 } 240 htlcPkScript, err = WitnessScriptHash(htlcWitnessScript) 241 if err != nil { 242 t.Fatalf("unable to create p2wsh htlc script: %v", err) 243 } 244 245 // This will be Alice's commitment transaction. In this 246 // scenario Alice is sending an HTLC to a node she has a path 247 // to (could be Bob, could be multiple hops down, it doesn't 248 // really matter). 249 htlcOutput = &wire.TxOut{ 250 Value: int64(paymentAmt), 251 PkScript: htlcPkScript, 252 } 253 senderCommitTx = wire.NewMsgTx(2) 254 senderCommitTx.AddTxIn(fakeFundingTxIn) 255 senderCommitTx.AddTxOut(htlcOutput) 256 } 257 258 // genSweepTx generates a sweep of the senderCommitTx, and sets the 259 // sequence and sighash single|anyonecanspend if confirmed is true. 260 genSweepTx := func(confirmed bool) { 261 prevOut := &wire.OutPoint{ 262 Hash: senderCommitTx.TxHash(), 263 Index: 0, 264 } 265 266 sweepTx = wire.NewMsgTx(2) 267 268 sweepTx.AddTxIn(wire.NewTxIn(prevOut, nil, nil)) 269 if confirmed { 270 sweepTx.TxIn[0].Sequence = LockTimeToSequence(false, 1) 271 } 272 273 sweepTx.AddTxOut( 274 &wire.TxOut{ 275 PkScript: []byte("doesn't matter"), 276 Value: 1 * 10e8, 277 }, 278 ) 279 280 sweepTxSigHashes = NewTxSigHashesV0Only(sweepTx) 281 282 bobSigHash = txscript.SigHashAll 283 if confirmed { 284 bobSigHash = txscript.SigHashSingle | txscript.SigHashAnyOneCanPay 285 } 286 287 // We'll also generate a signature on the sweep transaction above 288 // that will act as Bob's signature to Alice for the second level HTLC 289 // transaction. 290 bobSignDesc := SignDescriptor{ 291 KeyDesc: keychain.KeyDescriptor{ 292 PubKey: bobKeyPub, 293 }, 294 SingleTweak: bobCommitTweak, 295 WitnessScript: htlcWitnessScript, 296 Output: htlcOutput, 297 HashType: bobSigHash, 298 SigHashes: sweepTxSigHashes, 299 InputIndex: 0, 300 } 301 bobSig, err := bobSigner.SignOutputRaw(sweepTx, &bobSignDesc) 302 if err != nil { 303 t.Fatalf("unable to generate alice signature: %v", err) 304 } 305 306 bobRecvrSig, err = ecdsa.ParseDERSignature(bobSig.Serialize()) 307 if err != nil { 308 t.Fatalf("unable to parse signature: %v", err) 309 } 310 } 311 312 testCases := []struct { 313 witness func() wire.TxWitness 314 valid bool 315 }{ 316 { 317 // revoke w/ sig 318 // TODO(roasbeef): test invalid revoke 319 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 320 genCommitTx(false) 321 genSweepTx(false) 322 323 signDesc := &SignDescriptor{ 324 KeyDesc: keychain.KeyDescriptor{ 325 PubKey: bobKeyPub, 326 }, 327 DoubleTweak: commitSecret, 328 WitnessScript: htlcWitnessScript, 329 Output: htlcOutput, 330 HashType: txscript.SigHashAll, 331 SigHashes: sweepTxSigHashes, 332 InputIndex: 0, 333 } 334 335 return SenderHtlcSpendRevokeWithKey(bobSigner, signDesc, 336 revocationKey, sweepTx) 337 }), 338 true, 339 }, 340 { 341 // HTLC with invalid preimage size 342 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 343 genCommitTx(false) 344 genSweepTx(false) 345 346 signDesc := &SignDescriptor{ 347 KeyDesc: keychain.KeyDescriptor{ 348 PubKey: bobKeyPub, 349 }, 350 SingleTweak: bobCommitTweak, 351 WitnessScript: htlcWitnessScript, 352 Output: htlcOutput, 353 HashType: txscript.SigHashAll, 354 SigHashes: sweepTxSigHashes, 355 InputIndex: 0, 356 } 357 358 return SenderHtlcSpendRedeem(bobSigner, signDesc, 359 sweepTx, 360 // Invalid preimage length 361 bytes.Repeat([]byte{1}, 45)) 362 }), 363 false, 364 }, 365 { 366 // HTLC with valid preimage size + sig 367 // TODO(roasbeef): invalid preimage 368 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 369 genCommitTx(false) 370 genSweepTx(false) 371 372 signDesc := &SignDescriptor{ 373 KeyDesc: keychain.KeyDescriptor{ 374 PubKey: bobKeyPub, 375 }, 376 SingleTweak: bobCommitTweak, 377 WitnessScript: htlcWitnessScript, 378 Output: htlcOutput, 379 HashType: txscript.SigHashAll, 380 SigHashes: sweepTxSigHashes, 381 InputIndex: 0, 382 } 383 384 return SenderHtlcSpendRedeem(bobSigner, signDesc, 385 sweepTx, paymentPreimage) 386 }), 387 true, 388 }, 389 { 390 // HTLC with valid preimage size + sig, and with 391 // enforced locktime in HTLC script. 392 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 393 // Make a commit tx that needs confirmation for 394 // HTLC output to be spent. 395 genCommitTx(true) 396 397 // Generate a sweep with the locktime set. 398 genSweepTx(true) 399 400 signDesc := &SignDescriptor{ 401 KeyDesc: keychain.KeyDescriptor{ 402 PubKey: bobKeyPub, 403 }, 404 SingleTweak: bobCommitTweak, 405 WitnessScript: htlcWitnessScript, 406 Output: htlcOutput, 407 HashType: txscript.SigHashAll, 408 SigHashes: sweepTxSigHashes, 409 InputIndex: 0, 410 } 411 412 return SenderHtlcSpendRedeem(bobSigner, signDesc, 413 sweepTx, paymentPreimage) 414 }), 415 true, 416 }, 417 { 418 // HTLC with valid preimage size + sig, but trying to 419 // spend CSV output without sequence set. 420 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 421 // Generate commitment tx with 1 CSV locked 422 // HTLC. 423 genCommitTx(true) 424 425 // Generate sweep tx that doesn't have locktime 426 // enabled. 427 genSweepTx(false) 428 429 signDesc := &SignDescriptor{ 430 KeyDesc: keychain.KeyDescriptor{ 431 PubKey: bobKeyPub, 432 }, 433 SingleTweak: bobCommitTweak, 434 WitnessScript: htlcWitnessScript, 435 Output: htlcOutput, 436 HashType: txscript.SigHashAll, 437 SigHashes: sweepTxSigHashes, 438 InputIndex: 0, 439 } 440 441 return SenderHtlcSpendRedeem(bobSigner, signDesc, 442 sweepTx, paymentPreimage) 443 }), 444 false, 445 }, 446 447 { 448 // valid spend to the transition the state of the HTLC 449 // output with the second level HTLC timeout 450 // transaction. 451 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 452 genCommitTx(false) 453 genSweepTx(false) 454 455 signDesc := &SignDescriptor{ 456 KeyDesc: keychain.KeyDescriptor{ 457 PubKey: aliceKeyPub, 458 }, 459 SingleTweak: aliceCommitTweak, 460 WitnessScript: htlcWitnessScript, 461 Output: htlcOutput, 462 HashType: txscript.SigHashAll, 463 SigHashes: sweepTxSigHashes, 464 InputIndex: 0, 465 } 466 467 return SenderHtlcSpendTimeout( 468 bobRecvrSig, bobSigHash, aliceSigner, 469 signDesc, sweepTx, 470 ) 471 }), 472 true, 473 }, 474 { 475 // valid spend to the transition the state of the HTLC 476 // output with the second level HTLC timeout 477 // transaction. 478 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 479 // Make a commit tx that needs confirmation for 480 // HTLC output to be spent. 481 genCommitTx(true) 482 483 // Generate a sweep with the locktime set. 484 genSweepTx(true) 485 486 signDesc := &SignDescriptor{ 487 KeyDesc: keychain.KeyDescriptor{ 488 PubKey: aliceKeyPub, 489 }, 490 SingleTweak: aliceCommitTweak, 491 WitnessScript: htlcWitnessScript, 492 Output: htlcOutput, 493 HashType: txscript.SigHashAll, 494 SigHashes: sweepTxSigHashes, 495 InputIndex: 0, 496 } 497 498 return SenderHtlcSpendTimeout( 499 bobRecvrSig, bobSigHash, aliceSigner, 500 signDesc, sweepTx, 501 ) 502 }), 503 true, 504 }, 505 { 506 // valid spend to the transition the state of the HTLC 507 // output with the second level HTLC timeout 508 // transaction. 509 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 510 // Generate commitment tx with 1 CSV locked 511 // HTLC. 512 genCommitTx(true) 513 514 // Generate sweep tx that doesn't have locktime 515 // enabled. 516 genSweepTx(false) 517 518 signDesc := &SignDescriptor{ 519 KeyDesc: keychain.KeyDescriptor{ 520 PubKey: aliceKeyPub, 521 }, 522 SingleTweak: aliceCommitTweak, 523 WitnessScript: htlcWitnessScript, 524 Output: htlcOutput, 525 HashType: txscript.SigHashAll, 526 SigHashes: sweepTxSigHashes, 527 InputIndex: 0, 528 } 529 530 return SenderHtlcSpendTimeout( 531 bobRecvrSig, bobSigHash, aliceSigner, 532 signDesc, sweepTx, 533 ) 534 }), 535 false, 536 }, 537 } 538 539 // TODO(roasbeef): set of cases to ensure able to sign w/ keypath and 540 // not 541 542 for i, testCase := range testCases { 543 sweepTx.TxIn[0].Witness = testCase.witness() 544 545 newEngine := func() (*txscript.Engine, error) { 546 return txscript.NewEngine( 547 htlcPkScript, sweepTx, 0, 548 txscript.StandardVerifyFlags, nil, nil, 549 int64(paymentAmt), 550 txscript.NewCannedPrevOutputFetcher( 551 htlcPkScript, int64(paymentAmt), 552 ), 553 ) 554 } 555 556 assertEngineExecution(t, i, testCase.valid, newEngine) 557 } 558 } 559 560 // TestHTLCReceiverSpendValidation tests all possible valid+invalid redemption 561 // paths in the script used within the receiver's commitment transaction for an 562 // incoming HTLC. 563 // 564 // The following cases are exercised by this test: 565 // - receiver spends 566 // 1. HTLC redemption w/ invalid preimage size 567 // 2. HTLC redemption w/ invalid sequence 568 // 3. HTLC redemption w/ valid preimage size 569 // - sender spends 570 // 1. revoke w/ sig 571 // 2. refund w/ invalid lock time 572 // 3. refund w/ valid lock time 573 func TestHTLCReceiverSpendValidation(t *testing.T) { 574 t.Parallel() 575 576 // We generate a fake output, and the corresponding txin. This output 577 // doesn't need to exist, as we'll only be validating spending from the 578 // transaction that references this. 579 txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) 580 require.NoError(t, err, "unable to create txid") 581 fundingOut := &wire.OutPoint{ 582 Hash: *txid, 583 Index: 50, 584 } 585 fakeFundingTxIn := wire.NewTxIn(fundingOut, nil, nil) 586 587 // Next we'll the commitment secret for our commitment tx and also the 588 // revocation key that we'll use as well. 589 revokePreimage := testHdSeed.CloneBytes() 590 commitSecret, commitPoint := btcec.PrivKeyFromBytes(revokePreimage) 591 592 // Generate a payment preimage to be used below. 593 paymentPreimage := revokePreimage 594 paymentPreimage[0] ^= 1 595 paymentHash := sha256.Sum256(paymentPreimage[:]) 596 597 // We'll also need some tests keys for alice and bob, and metadata of 598 // the HTLC output. 599 aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(testWalletPrivKey) 600 bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(bobsPrivKey) 601 paymentAmt := btcutil.Amount(1 * 10e8) 602 cltvTimeout := uint32(8) 603 604 aliceLocalKey := TweakPubKey(aliceKeyPub, commitPoint) 605 bobLocalKey := TweakPubKey(bobKeyPub, commitPoint) 606 607 // As we'll be modeling spends from Bob's commitment transaction, we'll 608 // be using Alice's base point for the revocation key. 609 revocationKey := DeriveRevocationPubkey(aliceKeyPub, commitPoint) 610 611 bobCommitTweak := SingleTweakBytes(commitPoint, bobKeyPub) 612 aliceCommitTweak := SingleTweakBytes(commitPoint, aliceKeyPub) 613 614 // Finally, we'll create mock signers for both of them based on their 615 // private keys. This test simplifies a bit and uses the same key as 616 // the base point for all scripts and derivations. 617 bobSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{bobKeyPriv}} 618 aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}} 619 620 var ( 621 htlcWitnessScript, htlcPkScript []byte 622 htlcOutput *wire.TxOut 623 receiverCommitTx, sweepTx *wire.MsgTx 624 sweepTxSigHashes *txscript.TxSigHashes 625 aliceSenderSig *ecdsa.Signature 626 aliceSigHash txscript.SigHashType 627 ) 628 629 genCommitTx := func(confirmed bool) { 630 // Generate the raw HTLC redemption scripts, and its p2wsh 631 // counterpart. 632 htlcWitnessScript, err = ReceiverHTLCScript( 633 cltvTimeout, aliceLocalKey, bobLocalKey, revocationKey, 634 paymentHash[:], confirmed, 635 ) 636 if err != nil { 637 t.Fatalf("unable to create htlc sender script: %v", err) 638 } 639 htlcPkScript, err = WitnessScriptHash(htlcWitnessScript) 640 if err != nil { 641 t.Fatalf("unable to create p2wsh htlc script: %v", err) 642 } 643 644 // This will be Bob's commitment transaction. In this scenario Alice is 645 // sending an HTLC to a node she has a path to (could be Bob, could be 646 // multiple hops down, it doesn't really matter). 647 htlcOutput = &wire.TxOut{ 648 Value: int64(paymentAmt), 649 PkScript: htlcWitnessScript, 650 } 651 652 receiverCommitTx = wire.NewMsgTx(2) 653 receiverCommitTx.AddTxIn(fakeFundingTxIn) 654 receiverCommitTx.AddTxOut(htlcOutput) 655 } 656 657 genSweepTx := func(confirmed bool) { 658 prevOut := &wire.OutPoint{ 659 Hash: receiverCommitTx.TxHash(), 660 Index: 0, 661 } 662 663 sweepTx = wire.NewMsgTx(2) 664 sweepTx.AddTxIn(&wire.TxIn{ 665 PreviousOutPoint: *prevOut, 666 }) 667 if confirmed { 668 sweepTx.TxIn[0].Sequence = LockTimeToSequence(false, 1) 669 } 670 671 sweepTx.AddTxOut( 672 &wire.TxOut{ 673 PkScript: []byte("doesn't matter"), 674 Value: 1 * 10e8, 675 }, 676 ) 677 sweepTxSigHashes = NewTxSigHashesV0Only(sweepTx) 678 679 aliceSigHash = txscript.SigHashAll 680 if confirmed { 681 aliceSigHash = txscript.SigHashSingle | txscript.SigHashAnyOneCanPay 682 } 683 684 // We'll also generate a signature on the sweep transaction above 685 // that will act as Alice's signature to Bob for the second level HTLC 686 // transaction. 687 aliceSignDesc := SignDescriptor{ 688 KeyDesc: keychain.KeyDescriptor{ 689 PubKey: aliceKeyPub, 690 }, 691 SingleTweak: aliceCommitTweak, 692 WitnessScript: htlcWitnessScript, 693 Output: htlcOutput, 694 HashType: aliceSigHash, 695 SigHashes: sweepTxSigHashes, 696 InputIndex: 0, 697 } 698 aliceSig, err := aliceSigner.SignOutputRaw(sweepTx, &aliceSignDesc) 699 if err != nil { 700 t.Fatalf("unable to generate alice signature: %v", err) 701 } 702 703 aliceSenderSig, err = ecdsa.ParseDERSignature( 704 aliceSig.Serialize(), 705 ) 706 if err != nil { 707 t.Fatalf("unable to parse signature: %v", err) 708 } 709 } 710 711 // TODO(roasbeef): modify valid to check precise script errors? 712 testCases := []struct { 713 witness func() wire.TxWitness 714 valid bool 715 }{ 716 { 717 // HTLC redemption w/ invalid preimage size 718 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 719 genCommitTx(false) 720 genSweepTx(false) 721 722 signDesc := &SignDescriptor{ 723 KeyDesc: keychain.KeyDescriptor{ 724 PubKey: bobKeyPub, 725 }, 726 SingleTweak: bobCommitTweak, 727 WitnessScript: htlcWitnessScript, 728 Output: htlcOutput, 729 HashType: txscript.SigHashAll, 730 SigHashes: sweepTxSigHashes, 731 InputIndex: 0, 732 } 733 734 return ReceiverHtlcSpendRedeem( 735 aliceSenderSig, aliceSigHash, 736 bytes.Repeat([]byte{1}, 45), bobSigner, 737 signDesc, sweepTx, 738 ) 739 740 }), 741 false, 742 }, 743 { 744 // HTLC redemption w/ valid preimage size 745 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 746 genCommitTx(false) 747 genSweepTx(false) 748 749 signDesc := &SignDescriptor{ 750 KeyDesc: keychain.KeyDescriptor{ 751 PubKey: bobKeyPub, 752 }, 753 SingleTweak: bobCommitTweak, 754 WitnessScript: htlcWitnessScript, 755 Output: htlcOutput, 756 HashType: txscript.SigHashAll, 757 SigHashes: sweepTxSigHashes, 758 InputIndex: 0, 759 } 760 761 return ReceiverHtlcSpendRedeem( 762 aliceSenderSig, aliceSigHash, 763 paymentPreimage, bobSigner, 764 signDesc, sweepTx, 765 ) 766 }), 767 true, 768 }, 769 { 770 // revoke w/ sig 771 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 772 genCommitTx(false) 773 genSweepTx(false) 774 775 signDesc := &SignDescriptor{ 776 KeyDesc: keychain.KeyDescriptor{ 777 PubKey: aliceKeyPub, 778 }, 779 DoubleTweak: commitSecret, 780 WitnessScript: htlcWitnessScript, 781 Output: htlcOutput, 782 HashType: txscript.SigHashAll, 783 SigHashes: sweepTxSigHashes, 784 InputIndex: 0, 785 } 786 787 return ReceiverHtlcSpendRevokeWithKey(aliceSigner, 788 signDesc, revocationKey, sweepTx) 789 }), 790 true, 791 }, 792 { 793 // HTLC redemption w/ valid preimage size, and with 794 // enforced locktime in HTLC scripts. 795 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 796 // Make a commit tx that needs confirmation for 797 // HTLC output to be spent. 798 genCommitTx(true) 799 800 // Generate a sweep with the locktime set. 801 genSweepTx(true) 802 803 signDesc := &SignDescriptor{ 804 KeyDesc: keychain.KeyDescriptor{ 805 PubKey: bobKeyPub, 806 }, 807 SingleTweak: bobCommitTweak, 808 WitnessScript: htlcWitnessScript, 809 Output: htlcOutput, 810 HashType: txscript.SigHashAll, 811 SigHashes: sweepTxSigHashes, 812 InputIndex: 0, 813 } 814 815 return ReceiverHtlcSpendRedeem( 816 aliceSenderSig, aliceSigHash, 817 paymentPreimage, bobSigner, 818 signDesc, sweepTx, 819 ) 820 }), 821 true, 822 }, 823 { 824 // HTLC redemption w/ valid preimage size, but trying 825 // to spend CSV output without sequence set. 826 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 827 // Generate commitment tx with 1 CSV locked 828 // HTLC. 829 genCommitTx(true) 830 831 // Generate sweep tx that doesn't have locktime 832 // enabled. 833 genSweepTx(false) 834 835 signDesc := &SignDescriptor{ 836 KeyDesc: keychain.KeyDescriptor{ 837 PubKey: bobKeyPub, 838 }, 839 SingleTweak: bobCommitTweak, 840 WitnessScript: htlcWitnessScript, 841 Output: htlcOutput, 842 HashType: txscript.SigHashAll, 843 SigHashes: sweepTxSigHashes, 844 InputIndex: 0, 845 } 846 847 return ReceiverHtlcSpendRedeem( 848 aliceSenderSig, aliceSigHash, 849 paymentPreimage, bobSigner, signDesc, 850 sweepTx, 851 ) 852 }), 853 false, 854 }, 855 856 { 857 // refund w/ invalid lock time 858 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 859 genCommitTx(false) 860 genSweepTx(false) 861 862 signDesc := &SignDescriptor{ 863 KeyDesc: keychain.KeyDescriptor{ 864 PubKey: aliceKeyPub, 865 }, 866 SingleTweak: aliceCommitTweak, 867 WitnessScript: htlcWitnessScript, 868 Output: htlcOutput, 869 HashType: txscript.SigHashAll, 870 SigHashes: sweepTxSigHashes, 871 InputIndex: 0, 872 } 873 874 return ReceiverHtlcSpendTimeout(aliceSigner, signDesc, 875 sweepTx, int32(cltvTimeout-2)) 876 }), 877 false, 878 }, 879 { 880 // refund w/ valid lock time 881 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 882 genCommitTx(false) 883 genSweepTx(false) 884 885 signDesc := &SignDescriptor{ 886 KeyDesc: keychain.KeyDescriptor{ 887 PubKey: aliceKeyPub, 888 }, 889 SingleTweak: aliceCommitTweak, 890 WitnessScript: htlcWitnessScript, 891 Output: htlcOutput, 892 HashType: txscript.SigHashAll, 893 SigHashes: sweepTxSigHashes, 894 InputIndex: 0, 895 } 896 897 return ReceiverHtlcSpendTimeout(aliceSigner, signDesc, 898 sweepTx, int32(cltvTimeout)) 899 }), 900 true, 901 }, 902 { 903 // refund w/ valid lock time, and enforced locktime in 904 // HTLC scripts. 905 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 906 // Make a commit tx that needs confirmation for 907 // HTLC output to be spent. 908 genCommitTx(true) 909 910 // Generate a sweep with the locktime set. 911 genSweepTx(true) 912 913 signDesc := &SignDescriptor{ 914 KeyDesc: keychain.KeyDescriptor{ 915 PubKey: aliceKeyPub, 916 }, 917 SingleTweak: aliceCommitTweak, 918 WitnessScript: htlcWitnessScript, 919 Output: htlcOutput, 920 HashType: txscript.SigHashAll, 921 SigHashes: sweepTxSigHashes, 922 InputIndex: 0, 923 } 924 925 return ReceiverHtlcSpendTimeout(aliceSigner, signDesc, 926 sweepTx, int32(cltvTimeout)) 927 }), 928 true, 929 }, 930 { 931 // refund w/ valid lock time, but no sequence set in 932 // sweep tx trying to spend CSV locked HTLC output. 933 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 934 // Generate commitment tx with 1 CSV locked 935 // HTLC. 936 genCommitTx(true) 937 938 // Generate sweep tx that doesn't have locktime 939 // enabled. 940 genSweepTx(false) 941 942 signDesc := &SignDescriptor{ 943 KeyDesc: keychain.KeyDescriptor{ 944 PubKey: aliceKeyPub, 945 }, 946 SingleTweak: aliceCommitTweak, 947 WitnessScript: htlcWitnessScript, 948 Output: htlcOutput, 949 HashType: txscript.SigHashAll, 950 SigHashes: sweepTxSigHashes, 951 InputIndex: 0, 952 } 953 954 return ReceiverHtlcSpendTimeout(aliceSigner, signDesc, 955 sweepTx, int32(cltvTimeout)) 956 }), 957 false, 958 }, 959 } 960 961 for i, testCase := range testCases { 962 sweepTx.TxIn[0].Witness = testCase.witness() 963 964 newEngine := func() (*txscript.Engine, error) { 965 return txscript.NewEngine( 966 htlcPkScript, 967 sweepTx, 0, txscript.StandardVerifyFlags, nil, 968 nil, int64(paymentAmt), 969 txscript.NewCannedPrevOutputFetcher( 970 htlcPkScript, int64(paymentAmt), 971 ), 972 ) 973 } 974 975 assertEngineExecution(t, i, testCase.valid, newEngine) 976 } 977 } 978 979 // TestSecondLevelHtlcSpends tests all the possible redemption clauses from the 980 // HTLC success and timeout covenant transactions. 981 func TestSecondLevelHtlcSpends(t *testing.T) { 982 t.Parallel() 983 984 // We'll start be creating a creating a 2BTC HTLC. 985 const htlcAmt = btcutil.Amount(2 * 10e8) 986 987 // In all of our scenarios, the CSV timeout to claim a self output will 988 // be 5 blocks. 989 const claimDelay = 5 990 991 // First we'll set up some initial key state for Alice and Bob that 992 // will be used in the scripts we created below. 993 aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(testWalletPrivKey) 994 bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(bobsPrivKey) 995 996 revokePreimage := testHdSeed.CloneBytes() 997 commitSecret, commitPoint := btcec.PrivKeyFromBytes(revokePreimage) 998 999 // As we're modeling this as Bob sweeping the HTLC on-chain from his 1000 // commitment transaction after a period of time, we'll be using a 1001 // revocation key derived from Alice's base point and his secret. 1002 revocationKey := DeriveRevocationPubkey(aliceKeyPub, commitPoint) 1003 1004 // Next, craft a fake HTLC outpoint that we'll use to generate the 1005 // sweeping transaction using. 1006 txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) 1007 require.NoError(t, err, "unable to create txid") 1008 htlcOutPoint := &wire.OutPoint{ 1009 Hash: *txid, 1010 Index: 0, 1011 } 1012 sweepTx := wire.NewMsgTx(2) 1013 sweepTx.AddTxIn(wire.NewTxIn(htlcOutPoint, nil, nil)) 1014 sweepTx.AddTxOut( 1015 &wire.TxOut{ 1016 PkScript: []byte("doesn't matter"), 1017 Value: 1 * 10e8, 1018 }, 1019 ) 1020 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1021 1022 // The delay key will be crafted using Bob's public key as the output 1023 // we created will be spending from Alice's commitment transaction. 1024 delayKey := TweakPubKey(bobKeyPub, commitPoint) 1025 1026 // The commit tweak will be required in order for Bob to derive the 1027 // proper key need to spend the output. 1028 commitTweak := SingleTweakBytes(commitPoint, bobKeyPub) 1029 1030 // Finally we'll generate the HTLC script itself that we'll be spending 1031 // from. The revocation clause can be claimed by Alice, while Bob can 1032 // sweep the output after a particular delay. 1033 htlcWitnessScript, err := SecondLevelHtlcScript(revocationKey, 1034 delayKey, claimDelay) 1035 require.NoError(t, err, "unable to create htlc script") 1036 htlcPkScript, err := WitnessScriptHash(htlcWitnessScript) 1037 require.NoError(t, err, "unable to create htlc output") 1038 1039 htlcOutput := &wire.TxOut{ 1040 PkScript: htlcPkScript, 1041 Value: int64(htlcAmt), 1042 } 1043 1044 // TODO(roasbeef): make actually use timeout/success txns? 1045 1046 // Finally, we'll create mock signers for both of them based on their 1047 // private keys. This test simplifies a bit and uses the same key as 1048 // the base point for all scripts and derivations. 1049 bobSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{bobKeyPriv}} 1050 aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}} 1051 1052 testCases := []struct { 1053 witness func() wire.TxWitness 1054 valid bool 1055 }{ 1056 { 1057 // Sender of the HTLC attempts to activate the 1058 // revocation clause, but uses the wrong key (fails to 1059 // use the double tweak in this case). 1060 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1061 signDesc := &SignDescriptor{ 1062 KeyDesc: keychain.KeyDescriptor{ 1063 PubKey: aliceKeyPub, 1064 }, 1065 WitnessScript: htlcWitnessScript, 1066 Output: htlcOutput, 1067 HashType: txscript.SigHashAll, 1068 SigHashes: sweepTxSigHashes, 1069 InputIndex: 0, 1070 } 1071 1072 return HtlcSpendRevoke(aliceSigner, signDesc, 1073 sweepTx) 1074 }), 1075 false, 1076 }, 1077 { 1078 // Sender of HTLC activates the revocation clause. 1079 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1080 signDesc := &SignDescriptor{ 1081 KeyDesc: keychain.KeyDescriptor{ 1082 PubKey: aliceKeyPub, 1083 }, 1084 DoubleTweak: commitSecret, 1085 WitnessScript: htlcWitnessScript, 1086 Output: htlcOutput, 1087 HashType: txscript.SigHashAll, 1088 SigHashes: sweepTxSigHashes, 1089 InputIndex: 0, 1090 } 1091 1092 return HtlcSpendRevoke(aliceSigner, signDesc, 1093 sweepTx) 1094 }), 1095 true, 1096 }, 1097 { 1098 // Receiver of the HTLC attempts to sweep, but tries to 1099 // do so pre-maturely with a smaller CSV delay (2 1100 // blocks instead of 5 blocks). 1101 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1102 signDesc := &SignDescriptor{ 1103 KeyDesc: keychain.KeyDescriptor{ 1104 PubKey: bobKeyPub, 1105 }, 1106 SingleTweak: commitTweak, 1107 WitnessScript: htlcWitnessScript, 1108 Output: htlcOutput, 1109 HashType: txscript.SigHashAll, 1110 SigHashes: sweepTxSigHashes, 1111 InputIndex: 0, 1112 } 1113 1114 return HtlcSpendSuccess(bobSigner, signDesc, 1115 sweepTx, claimDelay-3) 1116 }), 1117 false, 1118 }, 1119 { 1120 // Receiver of the HTLC sweeps with the proper CSV 1121 // delay, but uses the wrong key (leaves off the single 1122 // tweak). 1123 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1124 signDesc := &SignDescriptor{ 1125 KeyDesc: keychain.KeyDescriptor{ 1126 PubKey: bobKeyPub, 1127 }, 1128 WitnessScript: htlcWitnessScript, 1129 Output: htlcOutput, 1130 HashType: txscript.SigHashAll, 1131 SigHashes: sweepTxSigHashes, 1132 InputIndex: 0, 1133 } 1134 1135 return HtlcSpendSuccess(bobSigner, signDesc, 1136 sweepTx, claimDelay) 1137 }), 1138 false, 1139 }, 1140 { 1141 // Receiver of the HTLC sweeps with the proper CSV 1142 // delay, and the correct key. 1143 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1144 signDesc := &SignDescriptor{ 1145 KeyDesc: keychain.KeyDescriptor{ 1146 PubKey: bobKeyPub, 1147 }, 1148 SingleTweak: commitTweak, 1149 WitnessScript: htlcWitnessScript, 1150 Output: htlcOutput, 1151 HashType: txscript.SigHashAll, 1152 SigHashes: sweepTxSigHashes, 1153 InputIndex: 0, 1154 } 1155 1156 return HtlcSpendSuccess(bobSigner, signDesc, 1157 sweepTx, claimDelay) 1158 }), 1159 true, 1160 }, 1161 } 1162 1163 for i, testCase := range testCases { 1164 sweepTx.TxIn[0].Witness = testCase.witness() 1165 1166 newEngine := func() (*txscript.Engine, error) { 1167 return txscript.NewEngine( 1168 htlcPkScript, 1169 sweepTx, 0, txscript.StandardVerifyFlags, nil, 1170 nil, int64(htlcAmt), 1171 txscript.NewCannedPrevOutputFetcher( 1172 htlcPkScript, int64(htlcAmt), 1173 ), 1174 ) 1175 } 1176 1177 assertEngineExecution(t, i, testCase.valid, newEngine) 1178 } 1179 } 1180 1181 // TestLeaseSecondLevelHtlcSpends tests all the possible redemption clauses from 1182 // the HTLC success and timeout covenant transactions in script enforced lease 1183 // commitments. 1184 func TestLeaseSecondLevelHtlcSpends(t *testing.T) { 1185 t.Parallel() 1186 1187 // We'll start be creating a creating a 2BTC HTLC. 1188 const htlcAmt = btcutil.Amount(2 * 10e8) 1189 1190 // In all of our scenarios, the CSV timeout to claim a self output will 1191 // be 5 blocks. 1192 const claimDelay = 5 1193 1194 // In all of our scenarios, the CLTV timelock will expire at height 1195 // 1337. 1196 const leaseExpiry = 1337 1197 1198 // First we'll set up some initial key state for Alice and Bob that 1199 // will be used in the scripts we created below. 1200 aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(testWalletPrivKey) 1201 bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(bobsPrivKey) 1202 1203 revokePreimage := testHdSeed.CloneBytes() 1204 commitSecret, commitPoint := btcec.PrivKeyFromBytes(revokePreimage) 1205 1206 // As we're modeling this as Bob sweeping the HTLC on-chain from his 1207 // commitment transaction after a period of time, we'll be using a 1208 // revocation key derived from Alice's base point and his secret. 1209 revocationKey := DeriveRevocationPubkey(aliceKeyPub, commitPoint) 1210 1211 // Next, craft a fake HTLC outpoint that we'll use to generate the 1212 // sweeping transaction using. 1213 txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) 1214 require.NoError(t, err) 1215 htlcOutPoint := &wire.OutPoint{ 1216 Hash: *txid, 1217 Index: 0, 1218 } 1219 sweepTx := wire.NewMsgTx(2) 1220 sweepTx.AddTxIn(wire.NewTxIn(htlcOutPoint, nil, nil)) 1221 sweepTx.AddTxOut( 1222 &wire.TxOut{ 1223 PkScript: []byte("doesn't matter"), 1224 Value: 1 * 10e8, 1225 }, 1226 ) 1227 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1228 1229 // The delay key will be crafted using Bob's public key as the output 1230 // we created will be spending from Alice's commitment transaction. 1231 delayKey := TweakPubKey(bobKeyPub, commitPoint) 1232 1233 // The commit tweak will be required in order for Bob to derive the 1234 // proper key need to spend the output. 1235 commitTweak := SingleTweakBytes(commitPoint, bobKeyPub) 1236 1237 // Finally we'll generate the HTLC script itself that we'll be spending 1238 // from. The revocation clause can be claimed by Alice, while Bob can 1239 // sweep the output after a particular delay. 1240 htlcWitnessScript, err := LeaseSecondLevelHtlcScript( 1241 revocationKey, delayKey, claimDelay, leaseExpiry, 1242 ) 1243 require.NoError(t, err) 1244 htlcPkScript, err := WitnessScriptHash(htlcWitnessScript) 1245 require.NoError(t, err) 1246 1247 htlcOutput := &wire.TxOut{ 1248 PkScript: htlcPkScript, 1249 Value: int64(htlcAmt), 1250 } 1251 1252 // Finally, we'll create mock signers for both of them based on their 1253 // private keys. This test simplifies a bit and uses the same key as 1254 // the base point for all scripts and derivations. 1255 bobSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{bobKeyPriv}} 1256 aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}} 1257 1258 testCases := []struct { 1259 witness func() wire.TxWitness 1260 valid bool 1261 }{ 1262 { 1263 // Sender of the HTLC attempts to activate the 1264 // revocation clause, but uses the wrong key (fails to 1265 // use the double tweak in this case). 1266 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1267 signDesc := &SignDescriptor{ 1268 KeyDesc: keychain.KeyDescriptor{ 1269 PubKey: aliceKeyPub, 1270 }, 1271 WitnessScript: htlcWitnessScript, 1272 Output: htlcOutput, 1273 HashType: txscript.SigHashAll, 1274 SigHashes: sweepTxSigHashes, 1275 InputIndex: 0, 1276 } 1277 1278 return HtlcSpendRevoke( 1279 aliceSigner, signDesc, sweepTx, 1280 ) 1281 }), 1282 false, 1283 }, 1284 { 1285 // Sender of HTLC activates the revocation clause. 1286 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1287 signDesc := &SignDescriptor{ 1288 KeyDesc: keychain.KeyDescriptor{ 1289 PubKey: aliceKeyPub, 1290 }, 1291 DoubleTweak: commitSecret, 1292 WitnessScript: htlcWitnessScript, 1293 Output: htlcOutput, 1294 HashType: txscript.SigHashAll, 1295 SigHashes: sweepTxSigHashes, 1296 InputIndex: 0, 1297 } 1298 1299 return HtlcSpendRevoke( 1300 aliceSigner, signDesc, sweepTx, 1301 ) 1302 }), 1303 true, 1304 }, 1305 { 1306 // Receiver of the HTLC attempts to sweep, but tries to 1307 // do so pre-maturely with a smaller CSV delay (2 1308 // blocks instead of 5 blocks), even after the CLTV 1309 // timelock expires. 1310 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1311 sweepTx.LockTime = leaseExpiry 1312 signDesc := &SignDescriptor{ 1313 KeyDesc: keychain.KeyDescriptor{ 1314 PubKey: bobKeyPub, 1315 }, 1316 SingleTweak: commitTweak, 1317 WitnessScript: htlcWitnessScript, 1318 Output: htlcOutput, 1319 HashType: txscript.SigHashAll, 1320 SigHashes: sweepTxSigHashes, 1321 InputIndex: 0, 1322 } 1323 1324 return HtlcSpendSuccess( 1325 bobSigner, signDesc, sweepTx, claimDelay-3, 1326 ) 1327 }), 1328 false, 1329 }, 1330 { 1331 // Receiver of the HTLC sweeps with the proper CSV delay 1332 // and after the CLTV timelock expires, but uses the 1333 // wrong key (leaves off the single tweak). 1334 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1335 sweepTx.LockTime = leaseExpiry 1336 signDesc := &SignDescriptor{ 1337 KeyDesc: keychain.KeyDescriptor{ 1338 PubKey: bobKeyPub, 1339 }, 1340 WitnessScript: htlcWitnessScript, 1341 Output: htlcOutput, 1342 HashType: txscript.SigHashAll, 1343 SigHashes: sweepTxSigHashes, 1344 InputIndex: 0, 1345 } 1346 1347 return HtlcSpendSuccess( 1348 bobSigner, signDesc, sweepTx, claimDelay, 1349 ) 1350 }), 1351 false, 1352 }, 1353 { 1354 // Receiver of the HTLC sweeps with the proper CSV 1355 // delay, and the correct key, but before the CTLV 1356 // timelock expires. 1357 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1358 sweepTx.LockTime = 0 1359 signDesc := &SignDescriptor{ 1360 KeyDesc: keychain.KeyDescriptor{ 1361 PubKey: bobKeyPub, 1362 }, 1363 SingleTweak: commitTweak, 1364 WitnessScript: htlcWitnessScript, 1365 Output: htlcOutput, 1366 HashType: txscript.SigHashAll, 1367 SigHashes: sweepTxSigHashes, 1368 InputIndex: 0, 1369 } 1370 1371 return HtlcSpendSuccess( 1372 bobSigner, signDesc, sweepTx, claimDelay, 1373 ) 1374 }), 1375 false, 1376 }, 1377 { 1378 // Receiver of the HTLC sweeps with the proper CSV 1379 // delay, and the correct key after the CTLV timelock 1380 // expires. 1381 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1382 sweepTx.LockTime = leaseExpiry 1383 signDesc := &SignDescriptor{ 1384 KeyDesc: keychain.KeyDescriptor{ 1385 PubKey: bobKeyPub, 1386 }, 1387 SingleTweak: commitTweak, 1388 WitnessScript: htlcWitnessScript, 1389 Output: htlcOutput, 1390 HashType: txscript.SigHashAll, 1391 SigHashes: sweepTxSigHashes, 1392 InputIndex: 0, 1393 } 1394 1395 return HtlcSpendSuccess( 1396 bobSigner, signDesc, sweepTx, claimDelay, 1397 ) 1398 }), 1399 true, 1400 }, 1401 } 1402 1403 for i, testCase := range testCases { 1404 sweepTx.TxIn[0].Witness = testCase.witness() 1405 1406 newEngine := func() (*txscript.Engine, error) { 1407 return txscript.NewEngine( 1408 htlcPkScript, sweepTx, 0, 1409 txscript.StandardVerifyFlags, nil, nil, 1410 int64(htlcAmt), 1411 txscript.NewCannedPrevOutputFetcher( 1412 htlcPkScript, int64(htlcAmt), 1413 ), 1414 ) 1415 } 1416 1417 assertEngineExecution(t, i, testCase.valid, newEngine) 1418 } 1419 } 1420 1421 // TestLeaseCommmitSpendToSelf tests all the possible redemption clauses from 1422 // the to_self output in a script enforced lease commitment transaction. 1423 func TestLeaseCommmitSpendToSelf(t *testing.T) { 1424 t.Parallel() 1425 1426 const ( 1427 outputVal = btcutil.Amount(2 * 10e8) 1428 csvDelay = 5 1429 leaseExpiry = 1337 1430 ) 1431 1432 // Set up some initial key state for Alice and Bob that will be used in 1433 // the scripts we created below. 1434 aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(testWalletPrivKey) 1435 bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(bobsPrivKey) 1436 1437 // We'll have Bob take the revocation path in some cases. 1438 revokePreimage := testHdSeed.CloneBytes() 1439 commitSecret, commitPoint := btcec.PrivKeyFromBytes(revokePreimage) 1440 revocationKey := DeriveRevocationPubkey(bobKeyPub, commitPoint) 1441 1442 // Construct the script enforced lease to_self commitment transaction 1443 // output. 1444 txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) 1445 require.NoError(t, err) 1446 commitOut := &wire.OutPoint{ 1447 Hash: *txid, 1448 Index: 0, 1449 } 1450 commitScript, err := LeaseCommitScriptToSelf( 1451 aliceKeyPub, revocationKey, csvDelay, leaseExpiry, 1452 ) 1453 require.NoError(t, err) 1454 commitPkScript, err := WitnessScriptHash(commitScript) 1455 require.NoError(t, err) 1456 1457 commitOutput := &wire.TxOut{ 1458 PkScript: commitPkScript, 1459 Value: int64(outputVal), 1460 } 1461 1462 sweepTx := wire.NewMsgTx(2) 1463 sweepTx.AddTxIn(wire.NewTxIn(commitOut, nil, nil)) 1464 sweepTx.AddTxOut( 1465 &wire.TxOut{ 1466 PkScript: []byte("doesn't matter"), 1467 Value: 1 * 10e8, 1468 }, 1469 ) 1470 1471 // Create mock signers for both parties to ensure signatures are 1472 // produced and verified correctly. 1473 aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}} 1474 bobSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{bobKeyPriv}} 1475 1476 testCases := []struct { 1477 witness func() wire.TxWitness 1478 valid bool 1479 }{ 1480 { 1481 // Bob can spend with his revocation key, but not 1482 // without the proper tweak. 1483 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1484 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1485 signDesc := &SignDescriptor{ 1486 KeyDesc: keychain.KeyDescriptor{ 1487 PubKey: bobKeyPub, 1488 }, 1489 WitnessScript: commitScript, 1490 Output: commitOutput, 1491 HashType: txscript.SigHashAll, 1492 SigHashes: sweepTxSigHashes, 1493 InputIndex: 0, 1494 } 1495 1496 return CommitSpendRevoke( 1497 bobSigner, signDesc, sweepTx, 1498 ) 1499 }), 1500 false, 1501 }, 1502 { 1503 // Bob can spend with his revocation key with the proper 1504 // tweak. 1505 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1506 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1507 signDesc := &SignDescriptor{ 1508 KeyDesc: keychain.KeyDescriptor{ 1509 PubKey: bobKeyPub, 1510 }, 1511 DoubleTweak: commitSecret, 1512 WitnessScript: commitScript, 1513 Output: commitOutput, 1514 HashType: txscript.SigHashAll, 1515 SigHashes: sweepTxSigHashes, 1516 InputIndex: 0, 1517 } 1518 1519 return CommitSpendRevoke( 1520 bobSigner, signDesc, sweepTx, 1521 ) 1522 }), 1523 true, 1524 }, 1525 { 1526 // Alice cannot spend with the proper key before the CSV 1527 // delay and after the CLTV timelock has expired. 1528 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1529 sweepTx.LockTime = leaseExpiry 1530 sweepTx.TxIn[0].Sequence = LockTimeToSequence( 1531 false, csvDelay/2, 1532 ) 1533 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1534 signDesc := &SignDescriptor{ 1535 KeyDesc: keychain.KeyDescriptor{ 1536 PubKey: aliceKeyPub, 1537 }, 1538 DoubleTweak: commitSecret, 1539 WitnessScript: commitScript, 1540 Output: commitOutput, 1541 HashType: txscript.SigHashAll, 1542 SigHashes: sweepTxSigHashes, 1543 InputIndex: 0, 1544 } 1545 1546 return CommitSpendTimeout( 1547 aliceSigner, signDesc, sweepTx, 1548 ) 1549 }), 1550 false, 1551 }, 1552 { 1553 // Alice cannot spend with the proper key after the CSV 1554 // delay and before the CLTV timelock has expired. 1555 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1556 sweepTx.LockTime = 0 1557 sweepTx.TxIn[0].Sequence = LockTimeToSequence( 1558 false, csvDelay, 1559 ) 1560 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1561 signDesc := &SignDescriptor{ 1562 KeyDesc: keychain.KeyDescriptor{ 1563 PubKey: aliceKeyPub, 1564 }, 1565 DoubleTweak: commitSecret, 1566 WitnessScript: commitScript, 1567 Output: commitOutput, 1568 HashType: txscript.SigHashAll, 1569 SigHashes: sweepTxSigHashes, 1570 InputIndex: 0, 1571 } 1572 1573 return CommitSpendTimeout( 1574 aliceSigner, signDesc, sweepTx, 1575 ) 1576 }), 1577 false, 1578 }, 1579 { 1580 // Alice can spend with the proper key after the CSV 1581 // delay and CLTV timelock have expired. 1582 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1583 sweepTx.LockTime = leaseExpiry 1584 sweepTx.TxIn[0].Sequence = LockTimeToSequence( 1585 false, csvDelay, 1586 ) 1587 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1588 signDesc := &SignDescriptor{ 1589 KeyDesc: keychain.KeyDescriptor{ 1590 PubKey: aliceKeyPub, 1591 }, 1592 WitnessScript: commitScript, 1593 Output: commitOutput, 1594 HashType: txscript.SigHashAll, 1595 SigHashes: sweepTxSigHashes, 1596 InputIndex: 0, 1597 } 1598 1599 return CommitSpendTimeout( 1600 aliceSigner, signDesc, sweepTx, 1601 ) 1602 }), 1603 true, 1604 }, 1605 } 1606 1607 for i, testCase := range testCases { 1608 sweepTx.TxIn[0].Witness = testCase.witness() 1609 1610 newEngine := func() (*txscript.Engine, error) { 1611 return txscript.NewEngine( 1612 commitPkScript, 1613 sweepTx, 0, txscript.StandardVerifyFlags, nil, 1614 nil, int64(outputVal), 1615 txscript.NewCannedPrevOutputFetcher( 1616 commitPkScript, int64(outputVal), 1617 ), 1618 ) 1619 } 1620 1621 assertEngineExecution(t, i, testCase.valid, newEngine) 1622 } 1623 } 1624 1625 // TestCommitSpendToRemoteConfirmed checks that the delayed version of the 1626 // to_remote version can only be spent by the owner, and after one 1627 // confirmation. 1628 func TestCommitSpendToRemoteConfirmed(t *testing.T) { 1629 t.Parallel() 1630 1631 const outputVal = btcutil.Amount(2 * 10e8) 1632 1633 aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(testWalletPrivKey) 1634 1635 txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) 1636 require.NoError(t, err, "unable to create txid") 1637 commitOut := &wire.OutPoint{ 1638 Hash: *txid, 1639 Index: 0, 1640 } 1641 commitScript, err := CommitScriptToRemoteConfirmed(aliceKeyPub) 1642 require.NoError(t, err, "unable to create htlc script") 1643 commitPkScript, err := WitnessScriptHash(commitScript) 1644 require.NoError(t, err, "unable to create htlc output") 1645 1646 commitOutput := &wire.TxOut{ 1647 PkScript: commitPkScript, 1648 Value: int64(outputVal), 1649 } 1650 1651 sweepTx := wire.NewMsgTx(2) 1652 sweepTx.AddTxIn(wire.NewTxIn(commitOut, nil, nil)) 1653 sweepTx.AddTxOut( 1654 &wire.TxOut{ 1655 PkScript: []byte("doesn't matter"), 1656 Value: 1 * 10e8, 1657 }, 1658 ) 1659 1660 aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}} 1661 1662 testCases := []struct { 1663 witness func() wire.TxWitness 1664 valid bool 1665 }{ 1666 { 1667 // Alice can spend after the a CSV delay has passed. 1668 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1669 sweepTx.TxIn[0].Sequence = LockTimeToSequence(false, 1) 1670 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1671 1672 signDesc := &SignDescriptor{ 1673 KeyDesc: keychain.KeyDescriptor{ 1674 PubKey: aliceKeyPub, 1675 }, 1676 WitnessScript: commitScript, 1677 Output: commitOutput, 1678 HashType: txscript.SigHashAll, 1679 SigHashes: sweepTxSigHashes, 1680 InputIndex: 0, 1681 } 1682 1683 return CommitSpendToRemoteConfirmed(aliceSigner, signDesc, 1684 sweepTx) 1685 }), 1686 true, 1687 }, 1688 { 1689 // Alice cannot spend output without sequence set. 1690 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1691 sweepTx.TxIn[0].Sequence = wire.MaxTxInSequenceNum 1692 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1693 1694 signDesc := &SignDescriptor{ 1695 KeyDesc: keychain.KeyDescriptor{ 1696 PubKey: aliceKeyPub, 1697 }, 1698 WitnessScript: commitScript, 1699 Output: commitOutput, 1700 HashType: txscript.SigHashAll, 1701 SigHashes: sweepTxSigHashes, 1702 InputIndex: 0, 1703 } 1704 1705 return CommitSpendToRemoteConfirmed(aliceSigner, signDesc, 1706 sweepTx) 1707 }), 1708 false, 1709 }, 1710 } 1711 1712 for i, testCase := range testCases { 1713 sweepTx.TxIn[0].Witness = testCase.witness() 1714 1715 newEngine := func() (*txscript.Engine, error) { 1716 return txscript.NewEngine( 1717 commitPkScript, sweepTx, 0, 1718 txscript.StandardVerifyFlags, nil, nil, 1719 int64(outputVal), 1720 txscript.NewCannedPrevOutputFetcher( 1721 commitPkScript, int64(outputVal), 1722 ), 1723 ) 1724 } 1725 1726 assertEngineExecution(t, i, testCase.valid, newEngine) 1727 } 1728 } 1729 1730 // TestLeaseCommitSpendToRemoteConfirmed checks that the delayed version of the 1731 // to_remote version can only be spent by the owner, after one confirmation, and 1732 // after the lease expiration has been met. 1733 func TestLeaseCommitSpendToRemoteConfirmed(t *testing.T) { 1734 t.Parallel() 1735 1736 const ( 1737 outputVal = btcutil.Amount(2 * 10e8) 1738 leaseExpiry = 1337 1739 ) 1740 1741 aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes( 1742 testWalletPrivKey, 1743 ) 1744 1745 txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) 1746 require.NoError(t, err) 1747 commitOut := &wire.OutPoint{ 1748 Hash: *txid, 1749 Index: 0, 1750 } 1751 commitScript, err := LeaseCommitScriptToRemoteConfirmed( 1752 aliceKeyPub, leaseExpiry, 1753 ) 1754 require.NoError(t, err) 1755 commitPkScript, err := WitnessScriptHash(commitScript) 1756 require.NoError(t, err) 1757 1758 commitOutput := &wire.TxOut{ 1759 PkScript: commitPkScript, 1760 Value: int64(outputVal), 1761 } 1762 1763 sweepTx := wire.NewMsgTx(2) 1764 sweepTx.AddTxIn(wire.NewTxIn(commitOut, nil, nil)) 1765 sweepTx.AddTxOut( 1766 &wire.TxOut{ 1767 PkScript: []byte("doesn't matter"), 1768 Value: 1 * 10e8, 1769 }, 1770 ) 1771 1772 aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}} 1773 1774 testCases := []struct { 1775 witness func() wire.TxWitness 1776 valid bool 1777 }{ 1778 { 1779 // Alice can spend after the CSV delay and CLTV timelock 1780 // has passed. 1781 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1782 sweepTx.LockTime = leaseExpiry 1783 sweepTx.TxIn[0].Sequence = LockTimeToSequence( 1784 false, 1, 1785 ) 1786 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1787 1788 signDesc := &SignDescriptor{ 1789 KeyDesc: keychain.KeyDescriptor{ 1790 PubKey: aliceKeyPub, 1791 }, 1792 WitnessScript: commitScript, 1793 Output: commitOutput, 1794 HashType: txscript.SigHashAll, 1795 SigHashes: sweepTxSigHashes, 1796 InputIndex: 0, 1797 } 1798 1799 return CommitSpendToRemoteConfirmed( 1800 aliceSigner, signDesc, sweepTx, 1801 ) 1802 }), 1803 true, 1804 }, 1805 { 1806 // Alice cannot spend output without sequence set, even 1807 // once the CLTV timelock has expired. 1808 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1809 sweepTx.LockTime = leaseExpiry 1810 sweepTx.TxIn[0].Sequence = wire.MaxTxInSequenceNum 1811 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1812 1813 signDesc := &SignDescriptor{ 1814 KeyDesc: keychain.KeyDescriptor{ 1815 PubKey: aliceKeyPub, 1816 }, 1817 WitnessScript: commitScript, 1818 Output: commitOutput, 1819 HashType: txscript.SigHashAll, 1820 SigHashes: sweepTxSigHashes, 1821 InputIndex: 0, 1822 } 1823 1824 return CommitSpendToRemoteConfirmed( 1825 aliceSigner, signDesc, sweepTx, 1826 ) 1827 }), 1828 false, 1829 }, 1830 { 1831 // Alice cannot spend output without sequence or 1832 // locktime set. 1833 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1834 sweepTx.LockTime = 0 1835 sweepTx.TxIn[0].Sequence = wire.MaxTxInSequenceNum 1836 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1837 1838 signDesc := &SignDescriptor{ 1839 KeyDesc: keychain.KeyDescriptor{ 1840 PubKey: aliceKeyPub, 1841 }, 1842 WitnessScript: commitScript, 1843 Output: commitOutput, 1844 HashType: txscript.SigHashAll, 1845 SigHashes: sweepTxSigHashes, 1846 InputIndex: 0, 1847 } 1848 1849 return CommitSpendToRemoteConfirmed( 1850 aliceSigner, signDesc, sweepTx, 1851 ) 1852 }), 1853 false, 1854 }, 1855 } 1856 1857 for i, testCase := range testCases { 1858 sweepTx.TxIn[0].Witness = testCase.witness() 1859 1860 newEngine := func() (*txscript.Engine, error) { 1861 return txscript.NewEngine( 1862 commitPkScript, sweepTx, 0, 1863 txscript.StandardVerifyFlags, nil, nil, 1864 int64(outputVal), 1865 txscript.NewCannedPrevOutputFetcher( 1866 commitPkScript, int64(outputVal), 1867 ), 1868 ) 1869 } 1870 1871 assertEngineExecution(t, i, testCase.valid, newEngine) 1872 } 1873 } 1874 1875 // TestSpendAnchor checks that we can spend the anchors using the various spend 1876 // paths. 1877 func TestSpendAnchor(t *testing.T) { 1878 t.Parallel() 1879 1880 const anchorSize = 294 1881 1882 // First we'll set up some initial key state for Alice. 1883 aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(testWalletPrivKey) 1884 1885 // Create a fake anchor outpoint that we'll use to generate the 1886 // sweeping transaction. 1887 txid, err := chainhash.NewHash(testHdSeed.CloneBytes()) 1888 require.NoError(t, err, "unable to create txid") 1889 anchorOutPoint := &wire.OutPoint{ 1890 Hash: *txid, 1891 Index: 0, 1892 } 1893 1894 sweepTx := wire.NewMsgTx(2) 1895 sweepTx.AddTxIn(wire.NewTxIn(anchorOutPoint, nil, nil)) 1896 sweepTx.AddTxOut( 1897 &wire.TxOut{ 1898 PkScript: []byte("doesn't matter"), 1899 Value: 1 * 10e8, 1900 }, 1901 ) 1902 1903 // Generate the anchor script that can be spent by Alice immediately, 1904 // or by anyone after 16 blocks. 1905 anchorScript, err := CommitScriptAnchor(aliceKeyPub) 1906 require.NoError(t, err, "unable to create htlc script") 1907 anchorPkScript, err := WitnessScriptHash(anchorScript) 1908 require.NoError(t, err, "unable to create htlc output") 1909 1910 anchorOutput := &wire.TxOut{ 1911 PkScript: anchorPkScript, 1912 Value: int64(anchorSize), 1913 } 1914 1915 // Create mock signer for Alice. 1916 aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}} 1917 1918 testCases := []struct { 1919 witness func() wire.TxWitness 1920 valid bool 1921 }{ 1922 { 1923 // Alice can spend immediately. 1924 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1925 sweepTx.TxIn[0].Sequence = wire.MaxTxInSequenceNum 1926 sweepTxSigHashes := NewTxSigHashesV0Only(sweepTx) 1927 1928 signDesc := &SignDescriptor{ 1929 KeyDesc: keychain.KeyDescriptor{ 1930 PubKey: aliceKeyPub, 1931 }, 1932 WitnessScript: anchorScript, 1933 Output: anchorOutput, 1934 HashType: txscript.SigHashAll, 1935 SigHashes: sweepTxSigHashes, 1936 InputIndex: 0, 1937 } 1938 1939 return CommitSpendAnchor(aliceSigner, signDesc, 1940 sweepTx) 1941 }), 1942 true, 1943 }, 1944 { 1945 // Anyone can spend after 16 blocks. 1946 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1947 sweepTx.TxIn[0].Sequence = LockTimeToSequence(false, 16) 1948 return CommitSpendAnchorAnyone(anchorScript) 1949 }), 1950 true, 1951 }, 1952 { 1953 // Anyone cannot spend before 16 blocks. 1954 makeWitnessTestCase(t, func() (wire.TxWitness, error) { 1955 sweepTx.TxIn[0].Sequence = LockTimeToSequence(false, 15) 1956 return CommitSpendAnchorAnyone(anchorScript) 1957 }), 1958 false, 1959 }, 1960 } 1961 1962 for i, testCase := range testCases { 1963 sweepTx.TxIn[0].Witness = testCase.witness() 1964 1965 newEngine := func() (*txscript.Engine, error) { 1966 return txscript.NewEngine( 1967 anchorPkScript, 1968 sweepTx, 0, txscript.StandardVerifyFlags, nil, 1969 nil, int64(anchorSize), 1970 txscript.NewCannedPrevOutputFetcher( 1971 anchorPkScript, int64(anchorSize), 1972 ), 1973 ) 1974 } 1975 1976 assertEngineExecution(t, i, testCase.valid, newEngine) 1977 } 1978 } 1979 1980 // TestSpecificationKeyDerivation implements the test vectors provided in 1981 // BOLT-03, Appendix E. 1982 func TestSpecificationKeyDerivation(t *testing.T) { 1983 const ( 1984 baseSecretHex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" 1985 perCommitmentSecretHex = "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100" 1986 basePointHex = "036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2" 1987 perCommitmentPointHex = "025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486" 1988 ) 1989 1990 baseSecret, err := privkeyFromHex(baseSecretHex) 1991 require.NoError(t, err, "Failed to parse serialized privkey") 1992 perCommitmentSecret, err := privkeyFromHex(perCommitmentSecretHex) 1993 require.NoError(t, err, "Failed to parse serialized privkey") 1994 basePoint, err := pubkeyFromHex(basePointHex) 1995 require.NoError(t, err, "Failed to parse serialized pubkey") 1996 perCommitmentPoint, err := pubkeyFromHex(perCommitmentPointHex) 1997 require.NoError(t, err, "Failed to parse serialized pubkey") 1998 1999 // name: derivation of key from basepoint and per_commitment_point 2000 const expectedLocalKeyHex = "0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5" 2001 actualLocalKey := TweakPubKey(basePoint, perCommitmentPoint) 2002 actualLocalKeyHex := pubkeyToHex(actualLocalKey) 2003 if actualLocalKeyHex != expectedLocalKeyHex { 2004 t.Errorf("Incorrect derivation of local public key: "+ 2005 "expected %v, got %v", expectedLocalKeyHex, actualLocalKeyHex) 2006 } 2007 2008 // name: derivation of secret key from basepoint secret and per_commitment_secret 2009 const expectedLocalPrivKeyHex = "cbced912d3b21bf196a766651e436aff192362621ce317704ea2f75d87e7be0f" 2010 tweak := SingleTweakBytes(perCommitmentPoint, basePoint) 2011 actualLocalPrivKey := TweakPrivKey(baseSecret, tweak) 2012 actualLocalPrivKeyHex := privkeyToHex(actualLocalPrivKey) 2013 if actualLocalPrivKeyHex != expectedLocalPrivKeyHex { 2014 t.Errorf("Incorrect derivation of local private key: "+ 2015 "expected %v, got %v, %v", expectedLocalPrivKeyHex, 2016 actualLocalPrivKeyHex, hex.EncodeToString(tweak)) 2017 } 2018 2019 // name: derivation of revocation key from basepoint and per_commitment_point 2020 const expectedRevocationKeyHex = "02916e326636d19c33f13e8c0c3a03dd157f332f3e99c317c141dd865eb01f8ff0" 2021 actualRevocationKey := DeriveRevocationPubkey(basePoint, perCommitmentPoint) 2022 actualRevocationKeyHex := pubkeyToHex(actualRevocationKey) 2023 if actualRevocationKeyHex != expectedRevocationKeyHex { 2024 t.Errorf("Incorrect derivation of revocation public key: "+ 2025 "expected %v, got %v", expectedRevocationKeyHex, 2026 actualRevocationKeyHex) 2027 } 2028 2029 // name: derivation of revocation secret from basepoint_secret and per_commitment_secret 2030 const expectedRevocationPrivKeyHex = "d09ffff62ddb2297ab000cc85bcb4283fdeb6aa052affbc9dddcf33b61078110" 2031 actualRevocationPrivKey := DeriveRevocationPrivKey(baseSecret, 2032 perCommitmentSecret) 2033 actualRevocationPrivKeyHex := privkeyToHex(actualRevocationPrivKey) 2034 if actualRevocationPrivKeyHex != expectedRevocationPrivKeyHex { 2035 t.Errorf("Incorrect derivation of revocation private key: "+ 2036 "expected %v, got %v", expectedRevocationPrivKeyHex, 2037 actualRevocationPrivKeyHex) 2038 } 2039 } 2040 2041 // BenchmarkScriptBuilderAlloc benchmarks the script builder's default 2042 // allocation. 2043 func BenchmarkScriptBuilderAlloc(t *testing.B) { 2044 dummyData := []byte("dummy data") 2045 randomPriv, err := btcec.NewPrivateKey() 2046 require.NoError(t, err) 2047 randomPub := randomPriv.PubKey() 2048 randomPubBytes := randomPub.SerializeCompressed() 2049 2050 t.ReportAllocs() 2051 t.ResetTimer() 2052 2053 // We run each iteration 1000 times to make the script allocation stand 2054 // out a bit more vs. the overhead of the rest of the function calls. 2055 for i := 0; i < t.N*1000; i++ { 2056 err := runScriptAllocTest(dummyData, randomPubBytes, randomPub) 2057 if err != nil { 2058 t.Fatal(err) 2059 } 2060 } 2061 } 2062 2063 // TestScriptBuilderAlloc makes sure the scripts generated by the utils have the 2064 // correct length. 2065 func TestScriptBuilderAlloc(t *testing.T) { 2066 t.Parallel() 2067 2068 dummyData := []byte("dummy data") 2069 randomPriv, err := btcec.NewPrivateKey() 2070 require.NoError(t, err) 2071 randomPub := randomPriv.PubKey() 2072 randomPubBytes := randomPub.SerializeCompressed() 2073 2074 err = runScriptAllocTest(dummyData, randomPubBytes, randomPub) 2075 require.NoError(t, err) 2076 } 2077 2078 // runScriptAllocTest runs the script size test. We don't use the "require" 2079 // library to assert the length to not influence the benchmark too much. 2080 func runScriptAllocTest(dummyData, randomPubBytes []byte, 2081 randomPub *btcec.PublicKey) error { 2082 2083 const ( 2084 maxCLTV = 500000000 2085 maxCSV = (1 << 31) - 1 2086 ) 2087 script, err := WitnessScriptHash(dummyData) 2088 if err != nil { 2089 return err 2090 } 2091 if len(script) != P2WSHSize { 2092 return fmt.Errorf("expected script size of %d", P2WSHSize) 2093 } 2094 2095 script, err = WitnessPubKeyHash(randomPubBytes) 2096 if err != nil { 2097 return err 2098 } 2099 if len(script) != P2WPKHSize { 2100 return fmt.Errorf("expected script size of %d", P2WPKHSize) 2101 } 2102 2103 script, err = GenerateP2SH(dummyData) 2104 if err != nil { 2105 return err 2106 } 2107 if len(script) != NestedP2WPKHSize { 2108 return fmt.Errorf("expected script size of %d", 2109 NestedP2WPKHSize) 2110 } 2111 2112 script, err = GenerateP2PKH(dummyData) 2113 if err != nil { 2114 return err 2115 } 2116 if len(script) != P2PKHSize { 2117 return fmt.Errorf("expected script size of %d", P2PKHSize) 2118 } 2119 2120 script, err = GenMultiSigScript(randomPubBytes, randomPubBytes) 2121 if err != nil { 2122 return err 2123 } 2124 if len(script) != MultiSigSize { 2125 return fmt.Errorf("expected script size of %d", MultiSigSize) 2126 } 2127 2128 script, err = SenderHTLCScript( 2129 randomPub, randomPub, randomPub, dummyData, false, 2130 ) 2131 if err != nil { 2132 return err 2133 } 2134 if len(script) != OfferedHtlcScriptSize { 2135 return fmt.Errorf("expected script size of %d", 2136 OfferedHtlcScriptSize) 2137 } 2138 2139 script, err = SenderHTLCScript( 2140 randomPub, randomPub, randomPub, dummyData, true, 2141 ) 2142 if err != nil { 2143 return err 2144 } 2145 if len(script) != OfferedHtlcScriptSizeConfirmed { 2146 return fmt.Errorf("expected script size of %d", 2147 OfferedHtlcScriptSizeConfirmed) 2148 } 2149 2150 script, err = ReceiverHTLCScript( 2151 maxCLTV, randomPub, randomPub, randomPub, dummyData, false, 2152 ) 2153 if err != nil { 2154 return err 2155 } 2156 if len(script) != AcceptedHtlcScriptSize { 2157 return fmt.Errorf("expected script size of %d", 2158 AcceptedHtlcScriptSize) 2159 } 2160 2161 script, err = ReceiverHTLCScript( 2162 maxCLTV, randomPub, randomPub, randomPub, dummyData, true, 2163 ) 2164 if err != nil { 2165 return err 2166 } 2167 if len(script) != AcceptedHtlcScriptSizeConfirmed { 2168 return fmt.Errorf("expected script size of %d", 2169 AcceptedHtlcScriptSizeConfirmed) 2170 } 2171 2172 script, err = SecondLevelHtlcScript(randomPub, randomPub, maxCSV) 2173 if err != nil { 2174 return err 2175 } 2176 if len(script) != ToLocalScriptSize { 2177 return fmt.Errorf("expected script size of %d", 2178 ToLocalScriptSize) 2179 } 2180 2181 script, err = LeaseSecondLevelHtlcScript( 2182 randomPub, randomPub, maxCSV, maxCLTV, 2183 ) 2184 if err != nil { 2185 return err 2186 } 2187 if len(script) != ToLocalScriptSize+LeaseWitnessScriptSizeOverhead { 2188 return fmt.Errorf("expected script size of %d", 2189 ToLocalScriptSize+LeaseWitnessScriptSizeOverhead) 2190 } 2191 2192 script, err = CommitScriptToSelf(maxCSV, randomPub, randomPub) 2193 if err != nil { 2194 return err 2195 } 2196 if len(script) != ToLocalScriptSize { 2197 return fmt.Errorf("expected script size of %d", 2198 ToLocalScriptSize) 2199 } 2200 2201 script, err = LeaseCommitScriptToSelf( 2202 randomPub, randomPub, maxCSV, maxCLTV, 2203 ) 2204 if err != nil { 2205 return err 2206 } 2207 if len(script) != ToLocalScriptSize+LeaseWitnessScriptSizeOverhead { 2208 return fmt.Errorf("expected script size of %d", 2209 ToLocalScriptSize+LeaseWitnessScriptSizeOverhead) 2210 } 2211 2212 script, err = CommitScriptUnencumbered(randomPub) 2213 if err != nil { 2214 return err 2215 } 2216 if len(script) != P2WPKHSize { 2217 return fmt.Errorf("expected script size of %d", P2WPKHSize) 2218 } 2219 2220 script, err = CommitScriptToRemoteConfirmed(randomPub) 2221 if err != nil { 2222 return err 2223 } 2224 if len(script) != ToRemoteConfirmedScriptSize { 2225 return fmt.Errorf("expected script size of %d", 2226 ToRemoteConfirmedScriptSize) 2227 } 2228 2229 script, err = LeaseCommitScriptToRemoteConfirmed(randomPub, maxCSV) 2230 if err != nil { 2231 return err 2232 } 2233 if len(script) != 2234 ToRemoteConfirmedScriptSize+LeaseWitnessScriptSizeOverhead { 2235 2236 return fmt.Errorf("expected script size of %d", 2237 ToRemoteConfirmedScriptSize+ 2238 LeaseWitnessScriptSizeOverhead) 2239 } 2240 2241 script, err = CommitScriptAnchor(randomPub) 2242 if err != nil { 2243 return err 2244 } 2245 if len(script) != AnchorScriptSize { 2246 return fmt.Errorf("expected script size of %d", 2247 AnchorScriptSize) 2248 } 2249 2250 return nil 2251 }