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