Skip to content

Commit

Permalink
txscript/engine_debug_test: add TestDebugEngine
Browse files Browse the repository at this point in the history
Add a simple test that make sure the stack and alt stack is correctly
set in the callback from script execution.
  • Loading branch information
halseth committed Aug 7, 2023
1 parent 6d38900 commit 5c5bef0
Showing 1 changed file with 178 additions and 0 deletions.
178 changes: 178 additions & 0 deletions txscript/engine_debug_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright (c) 2013-2023 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package txscript

import (
"testing"

"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/wire"
"github.com/stretchr/testify/require"
)

// TestDebugEngine checks that the StepCallbck called during debug script
// execution contains the expected data.
func TestDebugEngine(t *testing.T) {
t.Parallel()

// We'll generate a private key and a signature for the tx.
privKey, err := btcec.NewPrivateKey()
require.NoError(t, err)

internalKey := privKey.PubKey()

// We use a simple script that will utilize both the stack and alt
// stack in order to test the step callback, and wrap it in a taproot
// witness script.
builder := NewScriptBuilder()
builder.AddData([]byte{0xab})
builder.AddOp(OP_TOALTSTACK)
builder.AddData(schnorr.SerializePubKey(internalKey))
builder.AddOp(OP_CHECKSIG)
builder.AddOp(OP_VERIFY)
builder.AddOp(OP_1)
pkScript, err := builder.Script()
require.NoError(t, err)

tapLeaf := NewBaseTapLeaf(pkScript)
tapScriptTree := AssembleTaprootScriptTree(tapLeaf)

ctrlBlock := tapScriptTree.LeafMerkleProofs[0].ToControlBlock(
internalKey,
)

tapScriptRootHash := tapScriptTree.RootNode.TapHash()
outputKey := ComputeTaprootOutputKey(
internalKey, tapScriptRootHash[:],
)
p2trScript, err := PayToTaprootScript(outputKey)
require.NoError(t, err)

testTx := wire.NewMsgTx(2)
testTx.AddTxIn(&wire.TxIn{
PreviousOutPoint: wire.OutPoint{
Index: 1,
},
})
txOut := &wire.TxOut{
Value: 1e8, PkScript: p2trScript,
}
testTx.AddTxOut(txOut)

prevFetcher := NewCannedPrevOutputFetcher(
txOut.PkScript, txOut.Value,
)
sigHashes := NewTxSigHashes(testTx, prevFetcher)

sig, err := RawTxInTapscriptSignature(
testTx, sigHashes, 0, txOut.Value,
txOut.PkScript, tapLeaf,
SigHashDefault, privKey,
)
require.NoError(t, err)

// Now that we have the sig, we'll make a valid witness
// including the control block.
ctrlBlockBytes, err := ctrlBlock.ToBytes()
require.NoError(t, err)
txCopy := testTx.Copy()
txCopy.TxIn[0].Witness = wire.TxWitness{
sig, pkScript, ctrlBlockBytes,
}

expCallback := []StepInfo{
// First callback is looking at the OP_1 witness version.
{
ScriptIndex: 1,
OpcodeIndex: 0,
Stack: [][]byte{},
AltStack: [][]byte{},
},
// The OP_1 witness version is pushed to stack,
{
ScriptIndex: 1,
OpcodeIndex: 1,
Stack: [][]byte{{0x01}},
AltStack: [][]byte{},
},
// Then the taproot script is being executed, starting with
// only the signature on the stacks.
{
ScriptIndex: 2,
OpcodeIndex: 0,
Stack: [][]byte{sig},
AltStack: [][]byte{},
},
// 0xab is pushed to the stack.
{
ScriptIndex: 2,
OpcodeIndex: 1,
Stack: [][]byte{sig, {0xab}},
AltStack: [][]byte{},
},
// 0xab is moved to the alt stack.
{
ScriptIndex: 2,
OpcodeIndex: 2,
Stack: [][]byte{sig},
AltStack: [][]byte{{0xab}},
},
// The public key is pushed to the stack.
{
ScriptIndex: 2,
OpcodeIndex: 3,
Stack: [][]byte{
sig,
schnorr.SerializePubKey(internalKey),
},
AltStack: [][]byte{{0xab}},
},
// OP_CHECKSIG is executed, resulting in 0x01 on the stack.
{
ScriptIndex: 2,
OpcodeIndex: 4,
Stack: [][]byte{
{0x01},
},
AltStack: [][]byte{{0xab}},
},
// OP_VERIFY pops and checks the top stack element.
{
ScriptIndex: 2,
OpcodeIndex: 5,
Stack: [][]byte{},
AltStack: [][]byte{{0xab}},
},
// A single OP_1 push completes the script execution (note that
// the alt stack is cleared when the script is "done").
{
ScriptIndex: 2,
OpcodeIndex: 6,
Stack: [][]byte{{0x01}},
AltStack: [][]byte{},
},
}

stepIndex := 0
callback := func(s *StepInfo) error {
require.Less(
t, stepIndex, len(expCallback), "unexpected callback",
)

require.Equal(t, &expCallback[stepIndex], s)
stepIndex++
return nil
}

// Run the debug engine.
vm, err := NewDebugEngine(
txOut.PkScript, txCopy, 0, StandardVerifyFlags,
nil, sigHashes, txOut.Value, prevFetcher,
callback,
)
require.NoError(t, err)
require.NoError(t, vm.Execute())
}

0 comments on commit 5c5bef0

Please sign in to comment.