package tx import ( "encoding/hex" "testing" ) // fixtureTx rebuilds the rig node's spend: one P2WPKH input, one output. func fixtureTx(t *testing.T) (*Tx, [20]byte, uint64) { t.Helper() fixture := loadFixture(t) hash, err := hex.DecodeString(fixture.Prevout.TxID) if err != nil { t.Fatal(err) } var outpoint [32]byte copy(outpoint[:], hash) programRaw, err := hex.DecodeString(fixture.ScriptPubKey[4:]) if err != nil { t.Fatal(err) } var program [20]byte copy(program[:], programRaw) transaction := New() transaction.AddInput(Outpoint{Hash: outpoint, Index: fixture.Prevout.Vout}, fixture.Sequence) outputScript := []byte{0x00, 0x14} outputScript = append(outputScript, program[:]...) transaction.AddOutput(50000, outputScript) return transaction, program, fixture.Prevout.Amount } // TestSighashCommitsToTheAmount: BIP143's addition, and the reason a signature cannot be // reused with a different value. func TestSighashCommitsToTheAmount(t *testing.T) { transaction, program, amount := fixtureTx(t) first, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll) if err != nil { t.Fatal(err) } second, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount+1, SighashAll) if err != nil { t.Fatal(err) } if first == second { t.Fatal("one satoshi of difference produced the same digest") } } // TestSighashCommitsToTheScript: a different scriptCode is a different spend. func TestSighashCommitsToTheScript(t *testing.T) { transaction, program, amount := fixtureTx(t) first, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll) if err != nil { t.Fatal(err) } other := P2WPKHScriptCode(program) other[5] ^= 0xff second, err := transaction.SighashV0(0, other, amount, SighashAll) if err != nil { t.Fatal(err) } if first == second { t.Fatal("one byte of scriptCode did not change the digest") } } // TestSighashCommitsToTheOutputs: a wallet that signed one destination cannot have it swapped. func TestSighashCommitsToTheOutputs(t *testing.T) { transaction, program, amount := fixtureTx(t) first, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll) if err != nil { t.Fatal(err) } transaction.Outputs[0].Value++ second, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll) if err != nil { t.Fatal(err) } if first == second { t.Fatal("a changed output did not change the digest") } } // TestSighashCommitsToTheLocktime: a refund cannot be made valid early by editing the locktime. func TestSighashCommitsToTheLocktime(t *testing.T) { transaction, program, amount := fixtureTx(t) transaction.LockTime = 500 first, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll) if err != nil { t.Fatal(err) } transaction.LockTime = 501 second, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, SighashAll) if err != nil { t.Fatal(err) } if first == second { t.Fatal("a changed locktime did not change the digest") } } // TestSighashRefusesWhatItDoesNotSign: another hash type, or an input that is not there. func TestSighashRefusesWhatItDoesNotSign(t *testing.T) { transaction, program, amount := fixtureTx(t) if _, err := transaction.SighashV0(0, P2WPKHScriptCode(program), amount, 2); err != ErrSighashType { t.Fatalf("sighash type 2: %v", err) } if _, err := transaction.SighashV0(1, P2WPKHScriptCode(program), amount, SighashAll); err != ErrInputIndex { t.Fatalf("input 1: %v", err) } } // TestP2WPKHScriptCode: the scriptCode is the legacy script the program stands for. func TestP2WPKHScriptCode(t *testing.T) { var program [20]byte code := P2WPKHScriptCode(program) if len(code) != 25 || code[0] != 0x76 || code[1] != 0xa9 || code[2] != 0x14 || code[24] != 0xac { t.Fatalf("the scriptCode is %x", code) } }