input/script_utils: add delayed to_remote script + tests
This commit is contained in:
parent
a309132253
commit
990992ce94
@ -853,18 +853,6 @@ func CommitScriptToSelf(csvTimeout uint32, selfKey, revokeKey *btcec.PublicKey)
|
|||||||
return builder.Script()
|
return builder.Script()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitScriptUnencumbered constructs the public key script on the commitment
|
|
||||||
// transaction paying to the "other" party. The constructed output is a normal
|
|
||||||
// p2wkh output spendable immediately, requiring no contestation period.
|
|
||||||
func CommitScriptUnencumbered(key *btcec.PublicKey) ([]byte, error) {
|
|
||||||
// This script goes to the "other" party, and is spendable immediately.
|
|
||||||
builder := txscript.NewScriptBuilder()
|
|
||||||
builder.AddOp(txscript.OP_0)
|
|
||||||
builder.AddData(btcutil.Hash160(key.SerializeCompressed()))
|
|
||||||
|
|
||||||
return builder.Script()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommitSpendTimeout constructs a valid witness allowing the owner of a
|
// CommitSpendTimeout constructs a valid witness allowing the owner of a
|
||||||
// particular commitment transaction to spend the output returning settled
|
// particular commitment transaction to spend the output returning settled
|
||||||
// funds back to themselves after a relative block timeout. In order to
|
// funds back to themselves after a relative block timeout. In order to
|
||||||
@ -973,6 +961,69 @@ func CommitSpendNoDelay(signer Signer, signDesc *SignDescriptor,
|
|||||||
return witness, nil
|
return witness, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CommitScriptUnencumbered constructs the public key script on the commitment
|
||||||
|
// transaction paying to the "other" party. The constructed output is a normal
|
||||||
|
// p2wkh output spendable immediately, requiring no contestation period.
|
||||||
|
func CommitScriptUnencumbered(key *btcec.PublicKey) ([]byte, error) {
|
||||||
|
// This script goes to the "other" party, and is spendable immediately.
|
||||||
|
builder := txscript.NewScriptBuilder()
|
||||||
|
builder.AddOp(txscript.OP_0)
|
||||||
|
builder.AddData(btcutil.Hash160(key.SerializeCompressed()))
|
||||||
|
|
||||||
|
return builder.Script()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitScriptToRemoteConfirmed constructs the script for the output on the
|
||||||
|
// commitment transaction paying to the remote party of said commitment
|
||||||
|
// transaction. The money can only be spend after one confirmation.
|
||||||
|
//
|
||||||
|
// Possible Input Scripts:
|
||||||
|
// SWEEP: <sig>
|
||||||
|
//
|
||||||
|
// Output Script:
|
||||||
|
// <key> OP_CHECKSIGVERIFY
|
||||||
|
// 1 OP_CHECKSEQUENCEVERIFY
|
||||||
|
func CommitScriptToRemoteConfirmed(key *btcec.PublicKey) ([]byte, error) {
|
||||||
|
builder := txscript.NewScriptBuilder()
|
||||||
|
|
||||||
|
// Only the given key can spend the output.
|
||||||
|
builder.AddData(key.SerializeCompressed())
|
||||||
|
builder.AddOp(txscript.OP_CHECKSIGVERIFY)
|
||||||
|
|
||||||
|
// Check that the it has one confirmation.
|
||||||
|
builder.AddOp(txscript.OP_1)
|
||||||
|
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||||
|
|
||||||
|
return builder.Script()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitSpendToRemoteConfirmed constructs a valid witness allowing a node to
|
||||||
|
// spend their settled output on the counterparty's commitment transaction when
|
||||||
|
// it has one confirmetion. This is used for the anchor channel type. The
|
||||||
|
// spending key will always be non-tweaked for this output type.
|
||||||
|
func CommitSpendToRemoteConfirmed(signer Signer, signDesc *SignDescriptor,
|
||||||
|
sweepTx *wire.MsgTx) (wire.TxWitness, error) {
|
||||||
|
|
||||||
|
if signDesc.KeyDesc.PubKey == nil {
|
||||||
|
return nil, fmt.Errorf("cannot generate witness with nil " +
|
||||||
|
"KeyDesc pubkey")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similar to non delayed output, only a signature is needed.
|
||||||
|
sweepSig, err := signer.SignOutputRaw(sweepTx, signDesc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, we'll manually craft the witness. The witness here is the
|
||||||
|
// signature and the redeem script.
|
||||||
|
witnessStack := make([][]byte, 2)
|
||||||
|
witnessStack[0] = append(sweepSig, byte(signDesc.HashType))
|
||||||
|
witnessStack[1] = signDesc.WitnessScript
|
||||||
|
|
||||||
|
return witnessStack, nil
|
||||||
|
}
|
||||||
|
|
||||||
// SingleTweakBytes computes set of bytes we call the single tweak. The purpose
|
// SingleTweakBytes computes set of bytes we call the single tweak. The purpose
|
||||||
// of the single tweak is to randomize all regular delay and payment base
|
// of the single tweak is to randomize all regular delay and payment base
|
||||||
// points. To do this, we generate a hash that binds the commitment point to
|
// points. To do this, we generate a hash that binds the commitment point to
|
||||||
|
@ -1144,6 +1144,113 @@ func TestSecondLevelHtlcSpends(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestCommitSpendToRemoteConfirmed checks that the delayed version of the
|
||||||
|
// to_remote version can only be spent by the owner, and after one
|
||||||
|
// confirmation.
|
||||||
|
func TestCommitSpendToRemoteConfirmed(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
const outputVal = btcutil.Amount(2 * 10e8)
|
||||||
|
|
||||||
|
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||||
|
testWalletPrivKey)
|
||||||
|
|
||||||
|
txid, err := chainhash.NewHash(testHdSeed.CloneBytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create txid: %v", err)
|
||||||
|
}
|
||||||
|
commitOut := &wire.OutPoint{
|
||||||
|
Hash: *txid,
|
||||||
|
Index: 0,
|
||||||
|
}
|
||||||
|
commitScript, err := CommitScriptToRemoteConfirmed(aliceKeyPub)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create htlc script: %v", err)
|
||||||
|
}
|
||||||
|
commitPkScript, err := WitnessScriptHash(commitScript)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create htlc output: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
commitOutput := &wire.TxOut{
|
||||||
|
PkScript: commitPkScript,
|
||||||
|
Value: int64(outputVal),
|
||||||
|
}
|
||||||
|
|
||||||
|
sweepTx := wire.NewMsgTx(2)
|
||||||
|
sweepTx.AddTxIn(wire.NewTxIn(commitOut, nil, nil))
|
||||||
|
sweepTx.AddTxOut(
|
||||||
|
&wire.TxOut{
|
||||||
|
PkScript: []byte("doesn't matter"),
|
||||||
|
Value: 1 * 10e8,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
aliceSigner := &MockSigner{Privkeys: []*btcec.PrivateKey{aliceKeyPriv}}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
witness func() wire.TxWitness
|
||||||
|
valid bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// Alice can spend after the a CSV delay has passed.
|
||||||
|
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||||
|
sweepTx.TxIn[0].Sequence = LockTimeToSequence(false, 1)
|
||||||
|
sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx)
|
||||||
|
|
||||||
|
signDesc := &SignDescriptor{
|
||||||
|
KeyDesc: keychain.KeyDescriptor{
|
||||||
|
PubKey: aliceKeyPub,
|
||||||
|
},
|
||||||
|
WitnessScript: commitScript,
|
||||||
|
Output: commitOutput,
|
||||||
|
HashType: txscript.SigHashAll,
|
||||||
|
SigHashes: sweepTxSigHashes,
|
||||||
|
InputIndex: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
return CommitSpendToRemoteConfirmed(aliceSigner, signDesc,
|
||||||
|
sweepTx)
|
||||||
|
}),
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Alice cannot spend output without sequence set.
|
||||||
|
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||||
|
sweepTx.TxIn[0].Sequence = wire.MaxTxInSequenceNum
|
||||||
|
sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx)
|
||||||
|
|
||||||
|
signDesc := &SignDescriptor{
|
||||||
|
KeyDesc: keychain.KeyDescriptor{
|
||||||
|
PubKey: aliceKeyPub,
|
||||||
|
},
|
||||||
|
WitnessScript: commitScript,
|
||||||
|
Output: commitOutput,
|
||||||
|
HashType: txscript.SigHashAll,
|
||||||
|
SigHashes: sweepTxSigHashes,
|
||||||
|
InputIndex: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
return CommitSpendToRemoteConfirmed(aliceSigner, signDesc,
|
||||||
|
sweepTx)
|
||||||
|
}),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
sweepTx.TxIn[0].Witness = testCase.witness()
|
||||||
|
|
||||||
|
newEngine := func() (*txscript.Engine, error) {
|
||||||
|
return txscript.NewEngine(commitPkScript,
|
||||||
|
sweepTx, 0, txscript.StandardVerifyFlags, nil,
|
||||||
|
nil, int64(outputVal))
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEngineExecution(t, i, testCase.valid, newEngine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestSpecificationKeyDerivation implements the test vectors provided in
|
// TestSpecificationKeyDerivation implements the test vectors provided in
|
||||||
// BOLT-03, Appendix E.
|
// BOLT-03, Appendix E.
|
||||||
func TestSpecificationKeyDerivation(t *testing.T) {
|
func TestSpecificationKeyDerivation(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user