github.com/btcsuite/btcd@v0.24.0/txscript/engine_debug_test.go (about) 1 // Copyright (c) 2013-2023 The btcsuite developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package txscript 6 7 import ( 8 "testing" 9 10 "github.com/btcsuite/btcd/btcec/v2" 11 "github.com/btcsuite/btcd/btcec/v2/schnorr" 12 "github.com/btcsuite/btcd/wire" 13 "github.com/stretchr/testify/require" 14 ) 15 16 // TestDebugEngine checks that the StepCallbck called during debug script 17 // execution contains the expected data. 18 func TestDebugEngine(t *testing.T) { 19 t.Parallel() 20 21 // We'll generate a private key and a signature for the tx. 22 privKey, err := btcec.NewPrivateKey() 23 require.NoError(t, err) 24 25 internalKey := privKey.PubKey() 26 27 // We use a simple script that will utilize both the stack and alt 28 // stack in order to test the step callback, and wrap it in a taproot 29 // witness script. 30 builder := NewScriptBuilder() 31 builder.AddData([]byte{0xab}) 32 builder.AddOp(OP_TOALTSTACK) 33 builder.AddData(schnorr.SerializePubKey(internalKey)) 34 builder.AddOp(OP_CHECKSIG) 35 builder.AddOp(OP_VERIFY) 36 builder.AddOp(OP_1) 37 pkScript, err := builder.Script() 38 require.NoError(t, err) 39 40 tapLeaf := NewBaseTapLeaf(pkScript) 41 tapScriptTree := AssembleTaprootScriptTree(tapLeaf) 42 43 ctrlBlock := tapScriptTree.LeafMerkleProofs[0].ToControlBlock( 44 internalKey, 45 ) 46 47 tapScriptRootHash := tapScriptTree.RootNode.TapHash() 48 outputKey := ComputeTaprootOutputKey( 49 internalKey, tapScriptRootHash[:], 50 ) 51 p2trScript, err := PayToTaprootScript(outputKey) 52 require.NoError(t, err) 53 54 testTx := wire.NewMsgTx(2) 55 testTx.AddTxIn(&wire.TxIn{ 56 PreviousOutPoint: wire.OutPoint{ 57 Index: 1, 58 }, 59 }) 60 txOut := &wire.TxOut{ 61 Value: 1e8, PkScript: p2trScript, 62 } 63 testTx.AddTxOut(txOut) 64 65 prevFetcher := NewCannedPrevOutputFetcher( 66 txOut.PkScript, txOut.Value, 67 ) 68 sigHashes := NewTxSigHashes(testTx, prevFetcher) 69 70 sig, err := RawTxInTapscriptSignature( 71 testTx, sigHashes, 0, txOut.Value, 72 txOut.PkScript, tapLeaf, 73 SigHashDefault, privKey, 74 ) 75 require.NoError(t, err) 76 77 // Now that we have the sig, we'll make a valid witness 78 // including the control block. 79 ctrlBlockBytes, err := ctrlBlock.ToBytes() 80 require.NoError(t, err) 81 txCopy := testTx.Copy() 82 txCopy.TxIn[0].Witness = wire.TxWitness{ 83 sig, pkScript, ctrlBlockBytes, 84 } 85 86 expCallback := []StepInfo{ 87 // First callback is looking at the OP_1 witness version. 88 { 89 ScriptIndex: 1, 90 OpcodeIndex: 0, 91 Stack: [][]byte{}, 92 AltStack: [][]byte{}, 93 }, 94 // The OP_1 witness version is pushed to stack, 95 { 96 ScriptIndex: 1, 97 OpcodeIndex: 1, 98 Stack: [][]byte{{0x01}}, 99 AltStack: [][]byte{}, 100 }, 101 // Then the taproot script is being executed, starting with 102 // only the signature on the stacks. 103 { 104 ScriptIndex: 2, 105 OpcodeIndex: 0, 106 Stack: [][]byte{sig}, 107 AltStack: [][]byte{}, 108 }, 109 // 0xab is pushed to the stack. 110 { 111 ScriptIndex: 2, 112 OpcodeIndex: 1, 113 Stack: [][]byte{sig, {0xab}}, 114 AltStack: [][]byte{}, 115 }, 116 // 0xab is moved to the alt stack. 117 { 118 ScriptIndex: 2, 119 OpcodeIndex: 2, 120 Stack: [][]byte{sig}, 121 AltStack: [][]byte{{0xab}}, 122 }, 123 // The public key is pushed to the stack. 124 { 125 ScriptIndex: 2, 126 OpcodeIndex: 3, 127 Stack: [][]byte{ 128 sig, 129 schnorr.SerializePubKey(internalKey), 130 }, 131 AltStack: [][]byte{{0xab}}, 132 }, 133 // OP_CHECKSIG is executed, resulting in 0x01 on the stack. 134 { 135 ScriptIndex: 2, 136 OpcodeIndex: 4, 137 Stack: [][]byte{ 138 {0x01}, 139 }, 140 AltStack: [][]byte{{0xab}}, 141 }, 142 // OP_VERIFY pops and checks the top stack element. 143 { 144 ScriptIndex: 2, 145 OpcodeIndex: 5, 146 Stack: [][]byte{}, 147 AltStack: [][]byte{{0xab}}, 148 }, 149 // A single OP_1 push completes the script execution (note that 150 // the alt stack is cleared when the script is "done"). 151 { 152 ScriptIndex: 2, 153 OpcodeIndex: 6, 154 Stack: [][]byte{{0x01}}, 155 AltStack: [][]byte{}, 156 }, 157 } 158 159 stepIndex := 0 160 callback := func(s *StepInfo) error { 161 require.Less( 162 t, stepIndex, len(expCallback), "unexpected callback", 163 ) 164 165 require.Equal(t, &expCallback[stepIndex], s) 166 stepIndex++ 167 return nil 168 } 169 170 // Run the debug engine. 171 vm, err := NewDebugEngine( 172 txOut.PkScript, txCopy, 0, StandardVerifyFlags, 173 nil, sigHashes, txOut.Value, prevFetcher, 174 callback, 175 ) 176 require.NoError(t, err) 177 require.NoError(t, vm.Execute()) 178 }