lnwallet: TestHTLCSenderSpendValidation for new HTLC scripts

This commit is contained in:
Olaoluwa Osuntokun 2017-07-29 18:34:54 -07:00
parent 7c035a4729
commit 5b6cc5e92d
No known key found for this signature in database
GPG Key ID: 9CC5B105D03521A2

@ -209,8 +209,10 @@ func TestRevocationKeyDerivation(t *testing.T) {
// makeWitnessTestCase is a helper function used within test cases involving // makeWitnessTestCase is a helper function used within test cases involving
// the validity of a crafted witness. This function is a wrapper function which // the validity of a crafted witness. This function is a wrapper function which
// allows constructing table-driven tests. In the case of an error while // allows constructing table-driven tests. In the case of an error while
// constructing the witness, the test fails fataly. // constructing the witness, the test fails fatally.
func makeWitnessTestCase(t *testing.T, f func() (wire.TxWitness, error)) func() wire.TxWitness { func makeWitnessTestCase(t *testing.T,
f func() (wire.TxWitness, error)) func() wire.TxWitness {
return func() wire.TxWitness { return func() wire.TxWitness {
witness, err := f() witness, err := f()
if err != nil { if err != nil {
@ -238,21 +240,27 @@ func makeWitnessTestCase(t *testing.T, f func() (wire.TxWitness, error)) func()
func TestHTLCSenderSpendValidation(t *testing.T) { func TestHTLCSenderSpendValidation(t *testing.T) {
t.Parallel() t.Parallel()
// TODO(roasbeef): eliminate duplication with other HTLC tests. // We generate a fake output, and the corresponding txin. This output
// We generate a fake output, and the coresponding txin. This output
// doesn't need to exist, as we'll only be validating spending from the // doesn't need to exist, as we'll only be validating spending from the
// transaction that references this. // transaction that references this.
txid, err := chainhash.NewHash(testHdSeed.CloneBytes())
if err != nil {
t.Fatalf("unable to create txid: %v", err)
}
fundingOut := &wire.OutPoint{ fundingOut := &wire.OutPoint{
Hash: testHdSeed, Hash: *txid,
Index: 50, Index: 50,
} }
fakeFundingTxIn := wire.NewTxIn(fundingOut, nil, nil) fakeFundingTxIn := wire.NewTxIn(fundingOut, nil, nil)
// Generate a payment and revocation preimage to be used below. // Next we'll the commitment secret for our commitment tx and also the
revokePreimage := testHdSeed[:] // revocation key that we'll use as well.
revokeHash := sha256.Sum256(revokePreimage) revokePreimage := testHdSeed.CloneBytes()
paymentPreimage := revokeHash commitSecret, commitPoint := btcec.PrivKeyFromBytes(btcec.S256(),
revokePreimage)
// Generate a payment preimage to be used below.
paymentPreimage := revokePreimage
paymentPreimage[0] ^= 1 paymentPreimage[0] ^= 1
paymentHash := sha256.Sum256(paymentPreimage[:]) paymentHash := sha256.Sum256(paymentPreimage[:])
@ -263,29 +271,35 @@ func TestHTLCSenderSpendValidation(t *testing.T) {
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(), bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
bobsPrivKey) bobsPrivKey)
paymentAmt := btcutil.Amount(1 * 10e8) paymentAmt := btcutil.Amount(1 * 10e8)
cltvTimeout := uint32(8)
csvTimeout := uint32(5) aliceLocalKey := TweakPubKey(aliceKeyPub, commitPoint)
bobLocalKey := TweakPubKey(bobKeyPub, commitPoint)
// As we'll be modeling spends from Alice's commitment transaction,
// we'll be using Bob's base point for the revocation key.
revocationKey := DeriveRevocationPubkey(bobKeyPub, commitPoint)
// Generate the raw HTLC redemption scripts, and its p2wsh counterpart. // Generate the raw HTLC redemption scripts, and its p2wsh counterpart.
htlcScript, err := senderHTLCScript(cltvTimeout, csvTimeout, htlcWitnessScript, err := senderHTLCScript(aliceLocalKey, bobLocalKey,
aliceKeyPub, bobKeyPub, revokeHash[:], paymentHash[:]) revocationKey, paymentHash[:])
if err != nil { if err != nil {
t.Fatalf("unable to create htlc sender script: %v", err) t.Fatalf("unable to create htlc sender script: %v", err)
} }
htlcWitnessScript, err := witnessScriptHash(htlcScript) htlcPkScript, err := witnessScriptHash(htlcWitnessScript)
if err != nil { if err != nil {
t.Fatalf("unable to create p2wsh htlc script: %v", err) t.Fatalf("unable to create p2wsh htlc script: %v", err)
} }
// This will be Alice's commitment transaction. In this scenario Alice // This will be Alice's commitment transaction. In this scenario Alice
// is sending an HTLC to a node she has a a path to (could be Bob, // is sending an HTLC to a node she has a path to (could be Bob, could
// could be multiple hops down, it doesn't really matter). // be multiple hops down, it doesn't really matter).
htlcOutput := &wire.TxOut{
Value: int64(paymentAmt),
PkScript: htlcPkScript,
}
senderCommitTx := wire.NewMsgTx(2) senderCommitTx := wire.NewMsgTx(2)
senderCommitTx.AddTxIn(fakeFundingTxIn) senderCommitTx.AddTxIn(fakeFundingTxIn)
senderCommitTx.AddTxOut(&wire.TxOut{ senderCommitTx.AddTxOut(htlcOutput)
Value: int64(paymentAmt),
PkScript: htlcWitnessScript,
})
prevOut := &wire.OutPoint{ prevOut := &wire.OutPoint{
Hash: senderCommitTx.TxHash(), Hash: senderCommitTx.TxHash(),
@ -300,6 +314,33 @@ func TestHTLCSenderSpendValidation(t *testing.T) {
Value: 1 * 10e8, Value: 1 * 10e8,
}, },
) )
sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx)
bobCommitTweak := SingleTweakBytes(commitPoint, bobKeyPub)
aliceCommitTweak := SingleTweakBytes(commitPoint, aliceKeyPub)
// Finally, we'll create mock signers for both of them based on their
// private keys. This test simplifies a bit and uses the same key as
// the base point for all scripts and derivations.
bobSigner := &mockSigner{bobKeyPriv}
aliceSigner := &mockSigner{aliceKeyPriv}
// We'll also generate a signature on the sweep transaction above
// that'll act as Bob's signature to Alice for the second level HTLC
// transaction.
bobSignDesc := SignDescriptor{
PubKey: bobKeyPub,
SingleTweak: bobCommitTweak,
WitnessScript: htlcWitnessScript,
Output: htlcOutput,
HashType: txscript.SigHashAll,
SigHashes: sweepTxSigHashes,
InputIndex: 0,
}
bobRecvrSig, err := bobSigner.SignOutputRaw(sweepTx, &bobSignDesc)
if err != nil {
t.Fatalf("unable to generate alice signature: %v", err)
}
testCases := []struct { testCases := []struct {
witness func() wire.TxWitness witness func() wire.TxWitness
@ -309,17 +350,36 @@ func TestHTLCSenderSpendValidation(t *testing.T) {
// revoke w/ sig // revoke w/ sig
// TODO(roasbeef): test invalid revoke // TODO(roasbeef): test invalid revoke
makeWitnessTestCase(t, func() (wire.TxWitness, error) { makeWitnessTestCase(t, func() (wire.TxWitness, error) {
return senderHtlcSpendRevoke(htlcScript, paymentAmt, signDesc := &SignDescriptor{
bobKeyPriv, sweepTx, PubKey: bobKeyPub,
revokePreimage) DoubleTweak: commitSecret,
WitnessScript: htlcWitnessScript,
Output: htlcOutput,
HashType: txscript.SigHashAll,
SigHashes: sweepTxSigHashes,
InputIndex: 0,
}
return senderHtlcSpendRevoke(bobSigner, signDesc,
revocationKey, sweepTx)
}), }),
true, true,
}, },
{ {
// HTLC with invalid preimage size // HTLC with invalid preimage size
makeWitnessTestCase(t, func() (wire.TxWitness, error) { makeWitnessTestCase(t, func() (wire.TxWitness, error) {
return senderHtlcSpendRedeem(htlcScript, paymentAmt, signDesc := &SignDescriptor{
bobKeyPriv, sweepTx, PubKey: bobKeyPub,
SingleTweak: bobCommitTweak,
WitnessScript: htlcWitnessScript,
Output: htlcOutput,
HashType: txscript.SigHashAll,
SigHashes: sweepTxSigHashes,
InputIndex: 0,
}
return senderHtlcSpendRedeem(bobSigner, signDesc,
sweepTx,
// Invalid preimage length // Invalid preimage length
bytes.Repeat([]byte{1}, 45)) bytes.Repeat([]byte{1}, 45))
}), }),
@ -329,33 +389,38 @@ func TestHTLCSenderSpendValidation(t *testing.T) {
// HTLC with valid preimage size + sig // HTLC with valid preimage size + sig
// TODO(roabeef): invalid preimage // TODO(roabeef): invalid preimage
makeWitnessTestCase(t, func() (wire.TxWitness, error) { makeWitnessTestCase(t, func() (wire.TxWitness, error) {
return senderHtlcSpendRedeem(htlcScript, paymentAmt, signDesc := &SignDescriptor{
bobKeyPriv, sweepTx, PubKey: bobKeyPub,
paymentPreimage[:]) SingleTweak: bobCommitTweak,
WitnessScript: htlcWitnessScript,
Output: htlcOutput,
HashType: txscript.SigHashAll,
SigHashes: sweepTxSigHashes,
InputIndex: 0,
}
return senderHtlcSpendRedeem(bobSigner, signDesc,
sweepTx, paymentPreimage)
}), }),
true, true,
}, },
{ {
// invalid lock-time for CLTV // valid spend to the transition the state of the HTLC
// output with the second level HTLC timeout
// transaction.
makeWitnessTestCase(t, func() (wire.TxWitness, error) { makeWitnessTestCase(t, func() (wire.TxWitness, error) {
return senderHtlcSpendTimeout(htlcScript, paymentAmt, signDesc := &SignDescriptor{
aliceKeyPriv, sweepTx, cltvTimeout-2, csvTimeout) PubKey: aliceKeyPub,
}), SingleTweak: aliceCommitTweak,
false, WitnessScript: htlcWitnessScript,
}, Output: htlcOutput,
{ HashType: txscript.SigHashAll,
// invalid sequence for CSV SigHashes: sweepTxSigHashes,
makeWitnessTestCase(t, func() (wire.TxWitness, error) { InputIndex: 0,
return senderHtlcSpendTimeout(htlcScript, paymentAmt, }
aliceKeyPriv, sweepTx, cltvTimeout, csvTimeout-2)
}), return senderHtlcSpendTimeout(bobRecvrSig, aliceSigner,
false, signDesc, sweepTx)
},
{
// valid lock-time+sequence, valid sig
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
return senderHtlcSpendTimeout(htlcScript, paymentAmt,
aliceKeyPriv, sweepTx, cltvTimeout, csvTimeout)
}), }),
true, true,
}, },