btcd/txscript/stack_test.go

945 lines
15 KiB
Go
Raw Normal View History

// Copyright (c) 2013-2015 The btcsuite developers
2013-06-12 23:35:27 +02:00
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package txscript
2013-06-12 23:35:27 +02:00
import (
"bytes"
"errors"
"fmt"
2013-06-12 23:35:27 +02:00
"testing"
)
// TestStack tests that all of the stack operations work as expected.
func TestStack(t *testing.T) {
t.Parallel()
2013-06-12 23:35:27 +02:00
tests := []struct {
name string
before [][]byte
operation func(*stack) error
expectedReturn error
after [][]byte
}{
{
"noop",
[][]byte{{1}, {2}, {3}, {4}, {5}},
func(s *stack) error {
return nil
},
nil,
[][]byte{{1}, {2}, {3}, {4}, {5}},
},
{
"peek underflow (byte)",
[][]byte{{1}, {2}, {3}, {4}, {5}},
func(s *stack) error {
_, err := s.PeekByteArray(5)
2013-06-12 23:35:27 +02:00
return err
},
ErrStackUnderflow,
nil,
},
{
"peek underflow (int)",
[][]byte{{1}, {2}, {3}, {4}, {5}},
func(s *stack) error {
_, err := s.PeekInt(5)
2013-06-12 23:35:27 +02:00
return err
},
ErrStackUnderflow,
nil,
},
{
"peek underflow (bool)",
[][]byte{{1}, {2}, {3}, {4}, {5}},
func(s *stack) error {
_, err := s.PeekBool(5)
return err
},
ErrStackUnderflow,
nil,
},
{
"pop",
[][]byte{{1}, {2}, {3}, {4}, {5}},
func(s *stack) error {
val, err := s.PopByteArray()
2013-06-12 23:35:27 +02:00
if err != nil {
return err
}
if !bytes.Equal(val, []byte{5}) {
return errors.New("not equal")
}
return err
},
nil,
[][]byte{{1}, {2}, {3}, {4}},
},
{
"pop everything",
[][]byte{{1}, {2}, {3}, {4}, {5}},
func(s *stack) error {
for i := 0; i < 5; i++ {
_, err := s.PopByteArray()
if err != nil {
return err
}
}
return nil
},
nil,
nil,
},
{
"pop underflow",
[][]byte{{1}, {2}, {3}, {4}, {5}},
func(s *stack) error {
for i := 0; i < 6; i++ {
_, err := s.PopByteArray()
if err != nil {
return err
}
}
return nil
},
ErrStackUnderflow,
nil,
},
{
"pop bool",
[][]byte{nil},
func(s *stack) error {
val, err := s.PopBool()
if err != nil {
return err
}
2013-06-12 23:35:27 +02:00
if val != false {
return errors.New("unexpected value")
}
return nil
},
nil,
nil,
},
{
"pop bool",
[][]byte{{1}},
func(s *stack) error {
val, err := s.PopBool()
if err != nil {
return err
}
2013-06-12 23:35:27 +02:00
if val != true {
return errors.New("unexpected value")
}
return nil
},
nil,
nil,
},
{
"pop bool",
nil,
func(s *stack) error {
_, err := s.PopBool()
if err != nil {
return err
}
2013-06-12 23:35:27 +02:00
return nil
},
ErrStackUnderflow,
nil,
},
{
"popInt 0",
[][]byte{{0x0}},
func(s *stack) error {
v, err := s.PopInt()
if err != nil {
return err
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if v != 0 {
return errors.New("0 != 0 on popInt")
}
return nil
},
nil,
nil,
},
{
"popInt -0",
[][]byte{{0x80}},
func(s *stack) error {
v, err := s.PopInt()
if err != nil {
return err
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if v != 0 {
return errors.New("-0 != 0 on popInt")
}
return nil
},
nil,
nil,
},
{
"popInt 1",
[][]byte{{0x01}},
func(s *stack) error {
v, err := s.PopInt()
if err != nil {
return err
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if v != 1 {
return errors.New("1 != 1 on popInt")
}
return nil
},
nil,
nil,
},
{
"popInt 1 leading 0",
[][]byte{{0x01, 0x00, 0x00, 0x00}},
func(s *stack) error {
v, err := s.PopInt()
if err != nil {
return err
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if v != 1 {
fmt.Printf("%v != %v\n", v, 1)
return errors.New("1 != 1 on popInt")
}
return nil
},
nil,
nil,
},
{
"popInt -1",
[][]byte{{0x81}},
func(s *stack) error {
v, err := s.PopInt()
if err != nil {
return err
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if v != -1 {
return errors.New("-1 != -1 on popInt")
}
return nil
},
nil,
nil,
},
{
"popInt -1 leading 0",
[][]byte{{0x01, 0x00, 0x00, 0x80}},
func(s *stack) error {
v, err := s.PopInt()
if err != nil {
return err
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if v != -1 {
fmt.Printf("%v != %v\n", v, -1)
return errors.New("-1 != -1 on popInt")
}
return nil
},
nil,
nil,
},
// Triggers the multibyte case in asInt
{
"popInt -513",
[][]byte{{0x1, 0x82}},
func(s *stack) error {
v, err := s.PopInt()
if err != nil {
return err
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if v != -513 {
fmt.Printf("%v != %v\n", v, -513)
return errors.New("1 != 1 on popInt")
}
return nil
},
nil,
nil,
},
// Confirm that the asInt code doesn't modify the base data.
{
"peekint nomodify -1",
[][]byte{{0x01, 0x00, 0x00, 0x80}},
func(s *stack) error {
v, err := s.PeekInt(0)
if err != nil {
return err
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if v != -1 {
fmt.Printf("%v != %v\n", v, -1)
return errors.New("-1 != -1 on popInt")
}
return nil
},
nil,
[][]byte{{0x01, 0x00, 0x00, 0x80}},
},
{
"PushInt 0",
nil,
func(s *stack) error {
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
s.PushInt(scriptNum(0))
return nil
},
nil,
[][]byte{{}},
},
{
"PushInt 1",
nil,
func(s *stack) error {
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
s.PushInt(scriptNum(1))
return nil
},
nil,
[][]byte{{0x1}},
},
{
"PushInt -1",
nil,
func(s *stack) error {
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
s.PushInt(scriptNum(-1))
return nil
},
nil,
[][]byte{{0x81}},
},
{
"PushInt two bytes",
nil,
func(s *stack) error {
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
s.PushInt(scriptNum(256))
return nil
},
nil,
// little endian.. *sigh*
[][]byte{{0x00, 0x01}},
},
{
"PushInt leading zeros",
nil,
func(s *stack) error {
// this will have the highbit set
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
s.PushInt(scriptNum(128))
return nil
},
nil,
[][]byte{{0x80, 0x00}},
},
{
"dup",
[][]byte{{1}},
func(s *stack) error {
err := s.DupN(1)
if err != nil {
return err
}
2013-06-12 23:35:27 +02:00
return nil
},
nil,
[][]byte{{1}, {1}},
},
{
"dup2",
[][]byte{{1}, {2}},
func(s *stack) error {
err := s.DupN(2)
if err != nil {
return err
}
2013-06-12 23:35:27 +02:00
return nil
},
nil,
[][]byte{{1}, {2}, {1}, {2}},
},
{
"dup3",
[][]byte{{1}, {2}, {3}},
func(s *stack) error {
err := s.DupN(3)
if err != nil {
return err
}
2013-06-12 23:35:27 +02:00
return nil
},
nil,
[][]byte{{1}, {2}, {3}, {1}, {2}, {3}},
},
{
"dup0",
[][]byte{{1}},
func(s *stack) error {
err := s.DupN(0)
if err != nil {
return err
}
2013-06-12 23:35:27 +02:00
return nil
},
ErrStackInvalidArgs,
nil,
},
{
"dup-1",
[][]byte{{1}},
func(s *stack) error {
err := s.DupN(-1)
if err != nil {
return err
}
2013-06-12 23:35:27 +02:00
return nil
},
ErrStackInvalidArgs,
nil,
},
{
"dup too much",
[][]byte{{1}},
func(s *stack) error {
err := s.DupN(2)
if err != nil {
return err
}
2013-06-12 23:35:27 +02:00
return nil
},
ErrStackUnderflow,
nil,
},
{
"PushBool true",
nil,
func(s *stack) error {
s.PushBool(true)
2013-06-12 23:35:27 +02:00
return nil
},
nil,
[][]byte{{1}},
},
{
"PushBool false",
nil,
func(s *stack) error {
s.PushBool(false)
2013-06-12 23:35:27 +02:00
return nil
},
nil,
[][]byte{nil},
},
{
"PushBool PopBool",
nil,
func(s *stack) error {
s.PushBool(true)
val, err := s.PopBool()
if err != nil {
return err
}
if val != true {
return errors.New("unexpected value")
}
2013-06-12 23:35:27 +02:00
return nil
},
nil,
nil,
},
{
"PushBool PopBool 2",
nil,
func(s *stack) error {
s.PushBool(false)
val, err := s.PopBool()
if err != nil {
return err
}
if val != false {
return errors.New("unexpected value")
}
2013-06-12 23:35:27 +02:00
return nil
},
nil,
nil,
},
{
"PushInt PopBool",
nil,
func(s *stack) error {
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
s.PushInt(scriptNum(1))
val, err := s.PopBool()
if err != nil {
return err
}
if val != true {
return errors.New("unexpected value")
}
2013-06-12 23:35:27 +02:00
return nil
},
nil,
nil,
},
{
"PushInt PopBool 2",
nil,
func(s *stack) error {
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
s.PushInt(scriptNum(0))
val, err := s.PopBool()
if err != nil {
return err
}
if val != false {
return errors.New("unexpected value")
}
2013-06-12 23:35:27 +02:00
return nil
},
nil,
nil,
},
{
"Nip top",
[][]byte{{1}, {2}, {3}},
func(s *stack) error {
return s.NipN(0)
},
nil,
[][]byte{{1}, {2}},
},
{
"Nip middle",
[][]byte{{1}, {2}, {3}},
func(s *stack) error {
return s.NipN(1)
},
nil,
[][]byte{{1}, {3}},
},
{
"Nip low",
[][]byte{{1}, {2}, {3}},
func(s *stack) error {
return s.NipN(2)
},
nil,
[][]byte{{2}, {3}},
},
{
"Nip too much",
[][]byte{{1}, {2}, {3}},
func(s *stack) error {
// bite off more than we can chew
return s.NipN(3)
},
ErrStackUnderflow,
[][]byte{{2}, {3}},
},
{
"keep on tucking",
[][]byte{{1}, {2}, {3}},
func(s *stack) error {
return s.Tuck()
},
nil,
[][]byte{{1}, {3}, {2}, {3}},
},
{
"a little tucked up",
[][]byte{{1}}, // too few arguments for tuck
func(s *stack) error {
return s.Tuck()
},
ErrStackUnderflow,
nil,
},
{
"all tucked up",
nil, // too few arguments for tuck
func(s *stack) error {
return s.Tuck()
},
ErrStackUnderflow,
nil,
},
{
"drop 1",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.DropN(1)
},
nil,
[][]byte{{1}, {2}, {3}},
},
{
"drop 2",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.DropN(2)
},
nil,
[][]byte{{1}, {2}},
},
{
"drop 3",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.DropN(3)
},
nil,
[][]byte{{1}},
},
{
"drop 4",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.DropN(4)
},
nil,
nil,
},
{
"drop 4/5",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.DropN(5)
},
ErrStackUnderflow,
nil,
},
{
"drop invalid",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.DropN(0)
},
ErrStackInvalidArgs,
nil,
},
{
"Rot1",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.RotN(1)
},
nil,
[][]byte{{1}, {3}, {4}, {2}},
},
{
"Rot2",
[][]byte{{1}, {2}, {3}, {4}, {5}, {6}},
func(s *stack) error {
return s.RotN(2)
},
nil,
[][]byte{{3}, {4}, {5}, {6}, {1}, {2}},
},
{
"Rot too little",
[][]byte{{1}, {2}},
func(s *stack) error {
return s.RotN(1)
},
ErrStackUnderflow,
nil,
},
{
"Rot0",
[][]byte{{1}, {2}, {3}},
func(s *stack) error {
return s.RotN(0)
},
ErrStackInvalidArgs,
nil,
},
{
"Swap1",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.SwapN(1)
},
nil,
[][]byte{{1}, {2}, {4}, {3}},
},
{
"Swap2",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.SwapN(2)
},
nil,
[][]byte{{3}, {4}, {1}, {2}},
},
{
"Swap too little",
[][]byte{{1}},
func(s *stack) error {
return s.SwapN(1)
},
ErrStackUnderflow,
nil,
},
{
"Swap0",
[][]byte{{1}, {2}, {3}},
func(s *stack) error {
return s.SwapN(0)
},
ErrStackInvalidArgs,
nil,
},
{
"Over1",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.OverN(1)
},
nil,
[][]byte{{1}, {2}, {3}, {4}, {3}},
},
{
"Over2",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.OverN(2)
},
nil,
[][]byte{{1}, {2}, {3}, {4}, {1}, {2}},
},
{
"Over too little",
[][]byte{{1}},
func(s *stack) error {
return s.OverN(1)
},
ErrStackUnderflow,
nil,
},
{
"Over0",
[][]byte{{1}, {2}, {3}},
func(s *stack) error {
return s.OverN(0)
},
ErrStackInvalidArgs,
nil,
},
{
"Pick1",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.PickN(1)
},
nil,
[][]byte{{1}, {2}, {3}, {4}, {3}},
},
{
"Pick2",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.PickN(2)
},
nil,
[][]byte{{1}, {2}, {3}, {4}, {2}},
},
{
"Pick too little",
[][]byte{{1}},
func(s *stack) error {
return s.PickN(1)
},
ErrStackUnderflow,
nil,
},
{
"Roll1",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.RollN(1)
},
nil,
[][]byte{{1}, {2}, {4}, {3}},
},
{
"Roll2",
[][]byte{{1}, {2}, {3}, {4}},
func(s *stack) error {
return s.RollN(2)
},
nil,
[][]byte{{1}, {3}, {4}, {2}},
},
{
"Roll too little",
[][]byte{{1}},
func(s *stack) error {
return s.RollN(1)
},
ErrStackUnderflow,
nil,
},
{
"Peek bool",
[][]byte{{1}},
func(s *stack) error {
// Peek bool is otherwise pretty well tested,
// just check it works.
val, err := s.PeekBool(0)
if err != nil {
return err
}
if val != true {
return errors.New("invalid result")
}
return nil
},
nil,
[][]byte{{1}},
},
{
"Peek bool 2",
[][]byte{nil},
func(s *stack) error {
// Peek bool is otherwise pretty well tested,
// just check it works.
val, err := s.PeekBool(0)
if err != nil {
return err
}
if val != false {
return errors.New("invalid result")
}
return nil
},
nil,
[][]byte{nil},
},
{
"Peek int",
[][]byte{{1}},
func(s *stack) error {
// Peek int is otherwise pretty well tested,
// just check it works.
val, err := s.PeekInt(0)
if err != nil {
return err
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if val != 1 {
return errors.New("invalid result")
}
return nil
},
nil,
[][]byte{{1}},
},
{
"Peek int 2",
[][]byte{{0}},
func(s *stack) error {
// Peek int is otherwise pretty well tested,
// just check it works.
val, err := s.PeekInt(0)
if err != nil {
return err
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if val != 0 {
return errors.New("invalid result")
}
return nil
},
nil,
[][]byte{{0}},
},
{
"pop int",
nil,
func(s *stack) error {
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
s.PushInt(scriptNum(1))
// Peek int is otherwise pretty well tested,
// just check it works.
val, err := s.PopInt()
if err != nil {
return err
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if val != 1 {
return errors.New("invalid result")
}
return nil
},
nil,
nil,
},
{
"pop empty",
nil,
func(s *stack) error {
// Peek int is otherwise pretty well tested,
// just check it works.
_, err := s.PopInt()
2013-06-12 23:35:27 +02:00
return err
},
ErrStackUnderflow,
nil,
},
}
2013-06-12 23:35:27 +02:00
for _, test := range tests {
s := stack{}
2013-06-12 23:35:27 +02:00
for i := range test.before {
s.PushByteArray(test.before[i])
}
err := test.operation(&s)
if err != test.expectedReturn {
t.Errorf("%s: operation return not what expected: %v "+
"vs %v", test.name, err, test.expectedReturn)
}
2013-06-12 23:35:27 +02:00
if err != nil {
continue
2013-06-12 23:35:27 +02:00
}
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
if int32(len(test.after)) != s.Depth() {
t.Errorf("%s: stack depth doesn't match expected: %v "+
"vs %v", test.name, len(test.after),
s.Depth())
2013-06-12 23:35:27 +02:00
}
for i := range test.after {
txscript: Convert to new scriptnum type. This commit implements a new type, named scriptNum, for handling all numeric values used in scripts and converts the code over to make use of it. This is being done for a few of reasons. First, the consensus rules for handling numeric values in the scripts require special handling with subtle semantics. By encapsulating those details into a type specifically dedicated to that purpose, it simplifies the code and generally helps prevent improper usage. Second, the new type is quite a bit more efficient than big.Ints which are designed to be arbitrarily large and thus involve a lot of heap allocations and additional multi-precision bookkeeping. Because this new type is based on an int64, it allows the numbers to be stack allocated thereby eliminating a lot of GC and also eliminates the extra multi-precision arithmetic bookkeeping. The use of an int64 is possible because the consensus rules dictate that when data is interpreted as a number, it is limited to an int32 even though results outside of this range are allowed so long as they are not interpreted as integers again themselves. Thus, the maximum possible result comes from multiplying a max int32 by itself which safely fits into an int64 and can then still appropriately provide the serialization of the larger number as required by consensus. Finally, it more closely resembles the implementation used by Bitcoin Core and thus makes is easier to compare the behavior between the two implementations. This commit also includes a full suite of tests with 100% coverage of the semantics of the new type.
2015-04-30 03:16:00 +02:00
val, err := s.PeekByteArray(s.Depth() - int32(i) - 1)
if err != nil {
t.Errorf("%s: can't peek %dth stack entry: %v",
test.name, i, err)
break
}
if !bytes.Equal(val, test.after[i]) {
t.Errorf("%s: %dth stack entry doesn't match "+
"expected: %v vs %v", test.name, i, val,
test.after[i])
break
}
}
2013-06-12 23:35:27 +02:00
}
}