script_test.go raw
1 package script
2
3 import (
4 "bytes"
5 "crypto/sha256"
6 "testing"
7
8 "git.smesh.lol/tinywallet/pkg/bech32"
9 )
10
11 // TestP2WPKHScript: OP_0, a twenty-byte push, the program.
12 func TestP2WPKHScript(t *testing.T) {
13 var program [20]byte
14 program[0], program[19] = 0xaa, 0xbb
15
16 out := P2WPKH(program)
17
18 if len(out) != 22 || out[0] != OpZero || out[1] != 0x14 || out[2] != 0xaa || out[21] != 0xbb {
19 t.Fatalf("the script is %x", out)
20 }
21 }
22
23 // TestP2WSHScript: OP_0, a thirty-two-byte push, the script hash.
24 func TestP2WSHScript(t *testing.T) {
25 witness := []byte{OpIf, 0x01, 0x01, OpEndIf}
26
27 out := P2WSH(witness)
28
29 if len(out) != 34 || out[0] != OpZero || out[1] != 0x20 {
30 t.Fatalf("the script is %x", out)
31 }
32
33 sum := sha256.Sum256(witness)
34
35 if !bytes.Equal(out[2:], sum[:]) {
36 t.Fatalf("the program is %x, want %x", out[2:], sum)
37 }
38 }
39
40 // TestPushIsMinimal: the push width is what makes the script hash what it is.
41 func TestPushIsMinimal(t *testing.T) {
42 cases := []struct {
43 length int
44 want []byte
45 }{
46 {0, []byte{OpZero}},
47 {1, []byte{0x01}},
48 {75, []byte{75}},
49 {76, []byte{0x4c, 76}},
50 {0xff, []byte{0x4c, 0xff}},
51 {0x100, []byte{0x4d, 0x00, 0x01}},
52 }
53
54 for _, test := range cases {
55 out, err := Push(make([]byte, test.length))
56
57 if err != nil {
58 t.Fatalf("%d bytes: %v", test.length, err)
59 }
60
61 if !bytes.HasPrefix(out, test.want) {
62 t.Fatalf("%d bytes: the prefix is %x, want %x", test.length, out[:len(test.want)], test.want)
63 }
64
65 if len(out) != len(test.want)+test.length {
66 t.Fatalf("%d bytes: the push is %d bytes", test.length, len(out))
67 }
68 }
69 }
70
71 // TestAddressRoundTrip: an address is a program with a prefix, and decoding gives it back.
72 func TestAddressRoundTrip(t *testing.T) {
73 var program [20]byte
74 program[3] = 0x42
75
76 address, err := P2WPKHAddress("bcrt", program)
77
78 if err != nil {
79 t.Fatal(err)
80 }
81
82 hrp, version, decoded, err := bech32.DecodeSegwit(address)
83
84 if err != nil {
85 t.Fatal(err)
86 }
87
88 if hrp != "bcrt" || version != 0 || !bytes.Equal(decoded, program[:]) {
89 t.Fatalf("decoded %q %d %x", hrp, version, decoded)
90 }
91
92 witness := []byte{OpIf, OpEndIf}
93 scriptAddress, err := P2WSHAddress("bcrt", witness)
94
95 if err != nil {
96 t.Fatal(err)
97 }
98
99 hrp, version, decoded, err = bech32.DecodeSegwit(scriptAddress)
100
101 if err != nil {
102 t.Fatal(err)
103 }
104
105 if hrp != "bcrt" || version != 0 || len(decoded) != 32 {
106 t.Fatalf("decoded %q %d %x", hrp, version, decoded)
107 }
108 }
109
110 // TestTheWitnessScriptDeterminesTheAddress: a one-byte difference is a different wallet.
111 func TestTheWitnessScriptDeterminesTheAddress(t *testing.T) {
112 first, err := P2WSHAddress("bcrt", []byte{OpIf, OpOne, OpEndIf})
113
114 if err != nil {
115 t.Fatal(err)
116 }
117
118 second, err := P2WSHAddress("bcrt", []byte{OpIf, OpZero, OpEndIf})
119
120 if err != nil {
121 t.Fatal(err)
122 }
123
124 if first == second {
125 t.Fatal("two different witness scripts produced one address")
126 }
127 }
128
129 // TestP2WPKHMatchesTheWallet: the wallet's own address script and this one agree.
130 func TestP2WPKHMatchesTheWallet(t *testing.T) {
131 var program [20]byte
132 program[0] = 0x01
133
134 address, err := P2WPKHAddress("bc", program)
135
136 if err != nil {
137 t.Fatal(err)
138 }
139
140 hrp, _, decoded, err := bech32.DecodeSegwit(address)
141
142 if err != nil || hrp != "bc" || !bytes.Equal(decoded, program[:]) {
143 t.Fatalf("decoded %q %x, %v", hrp, decoded, err)
144 }
145 }
146