lbcd/txscript/stack.go

362 lines
8.6 KiB
Go
Raw Normal View History

// Copyright (c) 2013-2017 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 (
"encoding/hex"
"fmt"
)
2013-06-12 23:35:27 +02:00
// asBool gets the boolean value of the byte array.
func asBool(t []byte) bool {
for i := range t {
if t[i] != 0 {
// Negative 0 is also considered false.
if i == len(t)-1 && t[i] == 0x80 {
return false
}
2013-06-12 23:35:27 +02:00
return true
}
}
return false
}
// fromBool converts a boolean into the appropriate byte array.
func fromBool(v bool) []byte {
if v {
return []byte{1}
}
return nil
2013-06-12 23:35:27 +02:00
}
// stack represents a stack of immutable objects to be used with bitcoin
// scripts. Objects may be shared, therefore in usage if a value is to be
// changed it *must* be deep-copied first to avoid changing other values on the
// stack.
type stack struct {
stk [][]byte
verifyMinimalData bool
}
// Depth returns the number of items on the stack.
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
func (s *stack) Depth() int32 {
return int32(len(s.stk))
}
2013-06-12 23:35:27 +02:00
// PushByteArray adds the given back array to the top of the stack.
//
// Stack transformation: [... x1 x2] -> [... x1 x2 data]
func (s *stack) PushByteArray(so []byte) {
2013-06-12 23:35:27 +02:00
s.stk = append(s.stk, so)
}
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
// PushInt converts the provided scriptNum to a suitable byte array then pushes
2013-06-12 23:35:27 +02:00
// it onto the top of the stack.
//
// Stack transformation: [... x1 x2] -> [... x1 x2 int]
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
func (s *stack) PushInt(val scriptNum) {
s.PushByteArray(val.Bytes())
2013-06-12 23:35:27 +02:00
}
// PushBool converts the provided boolean to a suitable byte array then pushes
// it onto the top of the stack.
//
// Stack transformation: [... x1 x2] -> [... x1 x2 bool]
func (s *stack) PushBool(val bool) {
2013-06-12 23:35:27 +02:00
s.PushByteArray(fromBool(val))
}
// PopByteArray pops the value off the top of the stack and returns it.
//
// Stack transformation: [... x1 x2 x3] -> [... x1 x2]
func (s *stack) PopByteArray() ([]byte, error) {
2013-06-12 23:35:27 +02:00
return s.nipN(0)
}
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
// PopInt pops the value off the top of the stack, converts it into a script
// num, and returns it. The act of converting to a script num enforces the
// consensus rules imposed on data interpreted as numbers.
//
// Stack transformation: [... x1 x2 x3] -> [... x1 x2]
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
func (s *stack) PopInt() (scriptNum, error) {
2013-06-12 23:35:27 +02:00
so, err := s.PopByteArray()
if err != nil {
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
return 0, err
2013-06-12 23:35:27 +02:00
}
return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen)
2013-06-12 23:35:27 +02:00
}
// PopBool pops the value off the top of the stack, converts it into a bool, and
2013-06-12 23:35:27 +02:00
// returns it.
//
// Stack transformation: [... x1 x2 x3] -> [... x1 x2]
func (s *stack) PopBool() (bool, error) {
2013-06-12 23:35:27 +02:00
so, err := s.PopByteArray()
if err != nil {
return false, err
}
2013-06-12 23:35:27 +02:00
return asBool(so), nil
}
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
// PeekByteArray returns the Nth item on the stack without removing it.
func (s *stack) PeekByteArray(idx int32) ([]byte, error) {
sz := int32(len(s.stk))
2013-06-12 23:35:27 +02:00
if idx < 0 || idx >= sz {
str := fmt.Sprintf("index %d is invalid for stack size %d", idx,
sz)
return nil, scriptError(ErrInvalidStackOperation, str)
2013-06-12 23:35:27 +02:00
}
2013-06-12 23:35:27 +02:00
return s.stk[sz-idx-1], nil
}
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
// PeekInt returns the Nth item on the stack as a script num without removing
// it. The act of converting to a script num enforces the consensus rules
// imposed on data interpreted as numbers.
func (s *stack) PeekInt(idx int32) (scriptNum, error) {
2013-06-12 23:35:27 +02:00
so, err := s.PeekByteArray(idx)
if err != nil {
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
return 0, err
}
return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen)
2013-06-12 23:35:27 +02:00
}
// PeekBool returns the Nth item on the stack as a bool without removing it.
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
func (s *stack) PeekBool(idx int32) (bool, error) {
2013-06-12 23:35:27 +02:00
so, err := s.PeekByteArray(idx)
if err != nil {
return false, err
}
2013-06-12 23:35:27 +02:00
return asBool(so), nil
}
// nipN is an internal function that removes the nth item on the stack and
// returns it.
//
// Stack transformation:
// nipN(0): [... x1 x2 x3] -> [... x1 x2]
// nipN(1): [... x1 x2 x3] -> [... x1 x3]
// nipN(2): [... x1 x2 x3] -> [... x2 x3]
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
func (s *stack) nipN(idx int32) ([]byte, error) {
sz := int32(len(s.stk))
2013-06-12 23:35:27 +02:00
if idx < 0 || idx > sz-1 {
str := fmt.Sprintf("index %d is invalid for stack size %d", idx,
sz)
return nil, scriptError(ErrInvalidStackOperation, str)
2013-06-12 23:35:27 +02:00
}
so := s.stk[sz-idx-1]
2013-06-12 23:35:27 +02:00
if idx == 0 {
s.stk = s.stk[:sz-1]
} else if idx == sz-1 {
s1 := make([][]byte, sz-1, sz-1)
copy(s1, s.stk[1:])
s.stk = s1
2013-06-12 23:35:27 +02:00
} else {
s1 := s.stk[sz-idx : sz]
s.stk = s.stk[:sz-idx-1]
s.stk = append(s.stk, s1...)
}
return so, nil
2013-06-12 23:35:27 +02:00
}
// NipN removes the Nth object on the stack
//
// Stack transformation:
// NipN(0): [... x1 x2 x3] -> [... x1 x2]
// NipN(1): [... x1 x2 x3] -> [... x1 x3]
// NipN(2): [... x1 x2 x3] -> [... x2 x3]
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
func (s *stack) NipN(idx int32) error {
2013-06-12 23:35:27 +02:00
_, err := s.nipN(idx)
return err
}
// Tuck copies the item at the top of the stack and inserts it before the 2nd
// to top item.
//
// Stack transformation: [... x1 x2] -> [... x2 x1 x2]
func (s *stack) Tuck() error {
2013-06-12 23:35:27 +02:00
so2, err := s.PopByteArray()
if err != nil {
return err
}
so1, err := s.PopByteArray()
if err != nil {
return err
}
s.PushByteArray(so2) // stack [... x2]
s.PushByteArray(so1) // stack [... x2 x1]
s.PushByteArray(so2) // stack [... x2 x1 x2]
2013-06-12 23:35:27 +02:00
return nil
}
// DropN removes the top N items from the stack.
//
// Stack transformation:
// DropN(1): [... x1 x2] -> [... x1]
// DropN(2): [... x1 x2] -> [...]
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
func (s *stack) DropN(n int32) error {
2013-06-12 23:35:27 +02:00
if n < 1 {
str := fmt.Sprintf("attempt to drop %d items from stack", n)
return scriptError(ErrInvalidStackOperation, str)
2013-06-12 23:35:27 +02:00
}
2013-06-12 23:35:27 +02:00
for ; n > 0; n-- {
_, err := s.PopByteArray()
if err != nil {
return err
}
}
return nil
}
// DupN duplicates the top N items on the stack.
//
// Stack transformation:
// DupN(1): [... x1 x2] -> [... x1 x2 x2]
// DupN(2): [... x1 x2] -> [... x1 x2 x1 x2]
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
func (s *stack) DupN(n int32) error {
2013-06-12 23:35:27 +02:00
if n < 1 {
str := fmt.Sprintf("attempt to dup %d stack items", n)
return scriptError(ErrInvalidStackOperation, str)
2013-06-12 23:35:27 +02:00
}
2013-06-12 23:35:27 +02:00
// Iteratively duplicate the value n-1 down the stack n times.
// This leaves an in-order duplicate of the top n items on the stack.
2013-06-12 23:35:27 +02:00
for i := n; i > 0; i-- {
so, err := s.PeekByteArray(n - 1)
if err != nil {
return err
}
s.PushByteArray(so)
}
return nil
}
// RotN rotates the top 3N items on the stack to the left N times.
//
// Stack transformation:
// RotN(1): [... x1 x2 x3] -> [... x2 x3 x1]
// RotN(2): [... x1 x2 x3 x4 x5 x6] -> [... x3 x4 x5 x6 x1 x2]
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
func (s *stack) RotN(n int32) error {
2013-06-12 23:35:27 +02:00
if n < 1 {
str := fmt.Sprintf("attempt to rotate %d stack items", n)
return scriptError(ErrInvalidStackOperation, str)
2013-06-12 23:35:27 +02:00
}
2013-06-12 23:35:27 +02:00
// Nip the 3n-1th item from the stack to the top n times to rotate
// them up to the head of the stack.
entry := 3*n - 1
2013-06-12 23:35:27 +02:00
for i := n; i > 0; i-- {
so, err := s.nipN(entry)
if err != nil {
return err
}
s.PushByteArray(so)
}
return nil
}
// SwapN swaps the top N items on the stack with those below them.
//
// Stack transformation:
// SwapN(1): [... x1 x2] -> [... x2 x1]
// SwapN(2): [... x1 x2 x3 x4] -> [... x3 x4 x1 x2]
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
func (s *stack) SwapN(n int32) error {
2013-06-12 23:35:27 +02:00
if n < 1 {
str := fmt.Sprintf("attempt to swap %d stack items", n)
return scriptError(ErrInvalidStackOperation, str)
2013-06-12 23:35:27 +02:00
}
2013-06-12 23:35:27 +02:00
entry := 2*n - 1
for i := n; i > 0; i-- {
// Swap 2n-1th entry to top.
2013-06-12 23:35:27 +02:00
so, err := s.nipN(entry)
if err != nil {
return err
}
s.PushByteArray(so)
}
return nil
}
// OverN copies N items N items back to the top of the stack.
//
// Stack transformation:
// OverN(1): [... x1 x2 x3] -> [... x1 x2 x3 x2]
// OverN(2): [... x1 x2 x3 x4] -> [... x1 x2 x3 x4 x1 x2]
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
func (s *stack) OverN(n int32) error {
2013-06-12 23:35:27 +02:00
if n < 1 {
str := fmt.Sprintf("attempt to perform over on %d stack items",
n)
return scriptError(ErrInvalidStackOperation, str)
2013-06-12 23:35:27 +02:00
}
// Copy 2n-1th entry to top of the stack.
2013-06-12 23:35:27 +02:00
entry := 2*n - 1
for ; n > 0; n-- {
so, err := s.PeekByteArray(entry)
if err != nil {
return err
}
s.PushByteArray(so)
}
return nil
}
// PickN copies the item N items back in the stack to the top.
//
// Stack transformation:
// PickN(0): [x1 x2 x3] -> [x1 x2 x3 x3]
// PickN(1): [x1 x2 x3] -> [x1 x2 x3 x2]
// PickN(2): [x1 x2 x3] -> [x1 x2 x3 x1]
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
func (s *stack) PickN(n int32) error {
2013-06-12 23:35:27 +02:00
so, err := s.PeekByteArray(n)
if err != nil {
return err
}
s.PushByteArray(so)
return nil
}
// RollN moves the item N items back in the stack to the top.
//
// Stack transformation:
// RollN(0): [x1 x2 x3] -> [x1 x2 x3]
// RollN(1): [x1 x2 x3] -> [x1 x3 x2]
// RollN(2): [x1 x2 x3] -> [x2 x3 x1]
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
func (s *stack) RollN(n int32) error {
2013-06-12 23:35:27 +02:00
so, err := s.nipN(n)
if err != nil {
return err
}
s.PushByteArray(so)
return nil
}
2014-08-29 15:27:46 +02:00
// String returns the stack in a readable format.
func (s *stack) String() string {
2014-08-29 15:27:46 +02:00
var result string
for _, stack := range s.stk {
if len(stack) == 0 {
result += "00000000 <empty>\n"
}
2014-08-29 15:27:46 +02:00
result += hex.Dump(stack)
}
return result
}