sighash_test.go raw
1 package tx
2
3 import (
4 "encoding/hex"
5 "testing"
6 )
7
8 // fixtureTx rebuilds the rig node's spend: one P2WPKH input, one output.
9 func fixtureTx(t *testing.T) (*Tx, [20]byte, uint64) {
10 t.Helper()
11
12 fixture := loadFixture(t)
13
14 hash, err := hex.DecodeString(fixture.Prevout.TxID)
15
16 if err != nil {
17 t.Fatal(err)
18 }
19
20 var outpoint [32]byte
21 copy(outpoint[:], hash)
22
23 programRaw, err := hex.DecodeString(fixture.ScriptPubKey[4:])
24
25 if err != nil {
26 t.Fatal(err)
27 }
28
29 var program [20]byte
30 copy(program[:], programRaw)
31
32 transaction := New()
33 transaction.AddInput(Outpoint{Hash: outpoint, Index: fixture.Prevout.Vout}, fixture.Sequence)
34
35 outputScript := []byte{0x00, 0x14}
36 outputScript = append(outputScript, program[:]...)
37 transaction.AddOutput(50000, outputScript)
38
39 return transaction, program, fixture.Prevout.Amount
40 }
41
42 // TestSighashCommitsToTheAmount: BIP143's addition, and the reason a signature cannot be
43 // reused with a different value.
44 func TestSighashCommitsToTheAmount(t *testing.T) {
45 transaction, program, amount := fixtureTx(t)
46
47 first, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll)
48
49 if err != nil {
50 t.Fatal(err)
51 }
52
53 second, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount+1, SighashAll)
54
55 if err != nil {
56 t.Fatal(err)
57 }
58
59 if first == second {
60 t.Fatal("one satoshi of difference produced the same digest")
61 }
62 }
63
64 // TestSighashCommitsToTheScript: a different scriptCode is a different spend.
65 func TestSighashCommitsToTheScript(t *testing.T) {
66 transaction, program, amount := fixtureTx(t)
67
68 first, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll)
69
70 if err != nil {
71 t.Fatal(err)
72 }
73
74 other := P2WPKHScriptCode(program)
75 other[5] ^= 0xff
76
77 second, err := transaction.SighashV0(0, other, amount, SighashAll)
78
79 if err != nil {
80 t.Fatal(err)
81 }
82
83 if first == second {
84 t.Fatal("one byte of scriptCode did not change the digest")
85 }
86 }
87
88 // TestSighashCommitsToTheOutputs: a wallet that signed one destination cannot have it swapped.
89 func TestSighashCommitsToTheOutputs(t *testing.T) {
90 transaction, program, amount := fixtureTx(t)
91
92 first, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll)
93
94 if err != nil {
95 t.Fatal(err)
96 }
97
98 transaction.Outputs[0].Value++
99
100 second, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll)
101
102 if err != nil {
103 t.Fatal(err)
104 }
105
106 if first == second {
107 t.Fatal("a changed output did not change the digest")
108 }
109 }
110
111 // TestSighashCommitsToTheLocktime: a refund cannot be made valid early by editing the locktime.
112 func TestSighashCommitsToTheLocktime(t *testing.T) {
113 transaction, program, amount := fixtureTx(t)
114 transaction.LockTime = 500
115
116 first, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll)
117
118 if err != nil {
119 t.Fatal(err)
120 }
121
122 transaction.LockTime = 501
123
124 second, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll)
125
126 if err != nil {
127 t.Fatal(err)
128 }
129
130 if first == second {
131 t.Fatal("a changed locktime did not change the digest")
132 }
133 }
134
135 // TestSighashRefusesWhatItDoesNotSign: another hash type, or an input that is not there.
136 func TestSighashRefusesWhatItDoesNotSign(t *testing.T) {
137 transaction, program, amount := fixtureTx(t)
138
139 if _, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, 2); err != ErrSighashType {
140 t.Fatalf("sighash type 2: %v", err)
141 }
142
143 if _, err := transaction.SighashV0(1, P2WPKHScriptCode(program), amount, SighashAll); err != ErrInputIndex {
144 t.Fatalf("input 1: %v", err)
145 }
146 }
147
148 // TestP2WPKHScriptCode: the scriptCode is the legacy script the program stands for.
149 func TestP2WPKHScriptCode(t *testing.T) {
150 var program [20]byte
151
152 code := P2WPKHScriptCode(program)
153
154 if len(code) != 25 || code[0] != 0x76 || code[1] != 0xa9 || code[2] != 0x14 || code[24] != 0xac {
155 t.Fatalf("the scriptCode is %x", code)
156 }
157 }
158