// receiverHtlcSpendTimeout constructs a valid witness allowing the sender of // an HTLC to recover the pending funds after an absolute timeout in the // scenario that the receiver of the HTLC broadcasts their version of the // commitment transaction. func receiverHtlcSpendTimeout(commitScript []byte, outputAmt btcutil.Amount, senderKey *btcec.PrivateKey, sweepTx *wire.MsgTx, absoluteTimeout uint32) (wire.TxWitness, error) { // The HTLC output has an absolute time period before we are permitted // to recover the pending funds. Therefore we need to set the locktime // on this sweeping transaction in order to pass Script verification. sweepTx.LockTime = absoluteTimeout hashCache := txscript.NewTxSigHashes(sweepTx) sweepSig, err := txscript.RawTxInWitnessSignature( sweepTx, hashCache, 0, int64(outputAmt), commitScript, txscript.SigHashAll, senderKey) if err != nil { return nil, err } witnessStack := wire.TxWitness(make([][]byte, 4)) witnessStack[0] = sweepSig witnessStack[1] = []byte{0} witnessStack[2] = []byte{0} witnessStack[3] = commitScript return witnessStack, nil }
// CommitSpendTimeout constructs a valid witness allowing the owner of a // particular commitment transaction to spend the output returning settled // funds back to themselves after a relative block timeout. In order to // properly spend the transaction, the target input's sequence number should be // set accordingly based off of the target relative block timeout within the // redeem script. Additionally, OP_CSV requires that the version of the // transaction spending a pkscript with OP_CSV within it *must* be >= 2. func CommitSpendTimeout(signer Signer, signDesc *SignDescriptor, sweepTx *wire.MsgTx) (wire.TxWitness, error) { // Ensure the transaction version supports the validation of sequence // locks and CSV semantics. if sweepTx.Version < 2 { return nil, fmt.Errorf("version of passed transaction MUST "+ "be >= 2, not %v", sweepTx.Version) } // With the sequence number in place, we're now able to properly sign // off on the sweep transaction. sweepSig, err := signer.SignOutputRaw(sweepTx, signDesc) if err != nil { return nil, err } // Place a zero as the first item in the evaluated witness stack to // force script execution to the timeout spend clause. witnessStack := wire.TxWitness(make([][]byte, 3)) witnessStack[0] = append(sweepSig, byte(txscript.SigHashAll)) witnessStack[1] = []byte{0} witnessStack[2] = signDesc.WitnessScript return witnessStack, nil }
// receiverHtlcSpendRevoke constructs a valid witness allowing the sender of an // HTLC within a previously revoked commitment transaction to re-claim the // pending funds in the case that the receiver broadcasts this revoked // commitment transaction. func receiverHtlcSpendRevoke(commitScript []byte, outputAmt btcutil.Amount, senderKey *btcec.PrivateKey, sweepTx *wire.MsgTx, revokePreimage []byte) (wire.TxWitness, error) { // TODO(roasbeef): move sig generate outside func, or just factor out? hashCache := txscript.NewTxSigHashes(sweepTx) sweepSig, err := txscript.RawTxInWitnessSignature( sweepTx, hashCache, 0, int64(outputAmt), commitScript, txscript.SigHashAll, senderKey) if err != nil { return nil, err } // We place a zero, then one as the first items in the evaluated // witness stack in order to force script execution to the HTLC // revocation clause. witnessStack := wire.TxWitness(make([][]byte, 5)) witnessStack[0] = sweepSig witnessStack[1] = revokePreimage witnessStack[2] = []byte{1} witnessStack[3] = []byte{0} witnessStack[4] = commitScript return witnessStack, nil }
// receiverHtlcSpendRedeem constructs a valid witness allowing the receiver of // an HTLC to redeem the conditional payment in the event that their commitment // transaction is broadcast. Since this is a pay out to the receiving party as // an output on their commitment transaction, a relative time delay is required // before the output can be spent. func receiverHtlcSpendRedeem(commitScript []byte, outputAmt btcutil.Amount, reciverKey *btcec.PrivateKey, sweepTx *wire.MsgTx, paymentPreimage []byte, relativeTimeout uint32) (wire.TxWitness, error) { // In order to properly spend the transaction, we need to set the // sequence number. We do this by convering the relative block delay // into a sequence number value able to be interpeted by // OP_CHECKSEQUENCEVERIFY. sweepTx.TxIn[0].Sequence = lockTimeToSequence(false, relativeTimeout) // Additionally, OP_CSV requires that the version of the transaction // spending a pkscript with OP_CSV within it *must* be >= 2. sweepTx.Version = 2 hashCache := txscript.NewTxSigHashes(sweepTx) sweepSig, err := txscript.RawTxInWitnessSignature( sweepTx, hashCache, 0, int64(outputAmt), commitScript, txscript.SigHashAll, reciverKey) if err != nil { return nil, err } // Place a one as the first item in the evaluated witness stack to // force script execution to the HTLC redemption clause. witnessStack := wire.TxWitness(make([][]byte, 4)) witnessStack[0] = sweepSig witnessStack[1] = paymentPreimage witnessStack[2] = []byte{1} witnessStack[3] = commitScript return witnessStack, nil }
// commitSpendNoDelay constructs a valid witness allowing a node to spend their // settled no-delay output on the counter-party's commitment transaction. func commitSpendNoDelay(commitScript []byte, outputAmt btcutil.Amount, commitPriv *btcec.PrivateKey, sweepTx *wire.MsgTx) (wire.TxWitness, error) { // This is just a regular p2wkh spend which looks something like: // * witness: <sig> <pubkey> hashCache := txscript.NewTxSigHashes(sweepTx) witness, err := txscript.WitnessScript(sweepTx, hashCache, 0, int64(outputAmt), commitScript, txscript.SigHashAll, commitPriv, true) if err != nil { return nil, err } return wire.TxWitness(witness), nil }
// commitSpendRevoke constructs a valid witness allowing a node to sweep the // settled output of a malicious counter-party who broadcasts a revoked // commitment trransaction. func commitSpendRevoke(commitScript []byte, outputAmt btcutil.Amount, revocationPriv *btcec.PrivateKey, sweepTx *wire.MsgTx) (wire.TxWitness, error) { hashCache := txscript.NewTxSigHashes(sweepTx) sweepSig, err := txscript.RawTxInWitnessSignature( sweepTx, hashCache, 0, int64(outputAmt), commitScript, txscript.SigHashAll, revocationPriv) if err != nil { return nil, err } // Place a 1 as the first item in the evaluated witness stack to // force script execution to the revocation clause. witnessStack := wire.TxWitness(make([][]byte, 3)) witnessStack[0] = sweepSig witnessStack[1] = []byte{1} witnessStack[2] = commitScript return witnessStack, nil }
// htlcSpendTimeout constructs a valid witness allowing the sender of an HTLC // to recover the pending funds after an absolute, then relative locktime // period. func senderHtlcSpendTimeout(commitScript []byte, outputAmt btcutil.Amount, senderKey *btcec.PrivateKey, sweepTx *wire.MsgTx, absoluteTimeout, relativeTimeout uint32) (wire.TxWitness, error) { // Since the HTLC output has an absolute timeout before we're permitted // to sweep the output, we need to set the locktime of this sweepign // transaction to that aboslute value in order to pass Script // verification. sweepTx.LockTime = absoluteTimeout // Additionally, we're required to wait a relative period of time // before we can sweep the output in order to allow the other party to // contest our claim of validity to this version of the commitment // transaction. sweepTx.TxIn[0].Sequence = lockTimeToSequence(false, relativeTimeout) // Finally, OP_CSV requires that the version of the transaction // spending a pkscript with OP_CSV within it *must* be >= 2. sweepTx.Version = 2 hashCache := txscript.NewTxSigHashes(sweepTx) sweepSig, err := txscript.RawTxInWitnessSignature( sweepTx, hashCache, 0, int64(outputAmt), commitScript, txscript.SigHashAll, senderKey) if err != nil { return nil, err } // We place a zero as the first item of the evaluated witness stack in // order to force Script execution to the HTLC timeout clause. witnessStack := wire.TxWitness(make([][]byte, 3)) witnessStack[0] = sweepSig witnessStack[1] = []byte{0} witnessStack[2] = commitScript return witnessStack, nil }
// senderHtlcSpendRedeem constructs a valid witness allowing the receiver of an // HTLC to redeem the pending output in the scenario that the sender broadcasts // their version of the commitment transaction. A valid spend requires // knowledge of the payment pre-image, and a valid signature under the // receivers public key. func senderHtlcSpendRedeem(commitScript []byte, outputAmt btcutil.Amount, reciverKey *btcec.PrivateKey, sweepTx *wire.MsgTx, paymentPreimage []byte) (wire.TxWitness, error) { hashCache := txscript.NewTxSigHashes(sweepTx) sweepSig, err := txscript.RawTxInWitnessSignature( sweepTx, hashCache, 0, int64(outputAmt), commitScript, txscript.SigHashAll, reciverKey) if err != nil { return nil, err } // We force script execution into the HTLC redemption clause by placing // a one, then a zero as the first items in the final evalulated // witness stack. witnessStack := wire.TxWitness(make([][]byte, 5)) witnessStack[0] = sweepSig witnessStack[1] = paymentPreimage witnessStack[2] = []byte{0} witnessStack[3] = []byte{1} witnessStack[4] = commitScript return witnessStack, nil }
// senderHtlcSpendRevoke constructs a valid witness allowing the reciever of an // HTLC to claim the output with knowledge of the revocation preimage in the // scenario that the sender of the HTLC broadcasts a previously revoked // commitment transaction. A valid spend requires knowledge of the pre-image to // the commitment transaction's revocation hash, and a valid signature under // the receiver's public key. func senderHtlcSpendRevoke(commitScript []byte, outputAmt btcutil.Amount, reciverKey *btcec.PrivateKey, sweepTx *wire.MsgTx, revokePreimage []byte) (wire.TxWitness, error) { hashCache := txscript.NewTxSigHashes(sweepTx) sweepSig, err := txscript.RawTxInWitnessSignature( sweepTx, hashCache, 0, int64(outputAmt), commitScript, txscript.SigHashAll, reciverKey) if err != nil { return nil, err } // In order to force script execution to enter the revocation clause, // we place two one's as the first items in the final evalulated // witness stack. witnessStack := wire.TxWitness(make([][]byte, 5)) witnessStack[0] = sweepSig witnessStack[1] = revokePreimage witnessStack[2] = []byte{1} witnessStack[3] = []byte{1} witnessStack[4] = commitScript return witnessStack, nil }