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