1 // Copyright (c) 2013-2017 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
12 // asBool gets the boolean value of the byte array.
13 func asBool(t []byte) bool {
16 // Negative 0 is also considered false.
17 if i == len(t)-1 && t[i] == 0x80 {
26 // fromBool converts a boolean into the appropriate byte array.
27 func fromBool(v bool) []byte {
34 // stack represents a stack of immutable objects to be used with bitcoin
35 // scripts. Objects may be shared, therefore in usage if a value is to be
36 // changed it *must* be deep-copied first to avoid changing other values on the
40 verifyMinimalData bool
43 // Depth returns the number of items on the stack.
44 func (s *stack) Depth() int32 {
45 return int32(len(s.stk))
48 // PushByteArray adds the given back array to the top of the stack.
50 // Stack transformation: [... x1 x2] -> [... x1 x2 data]
51 func (s *stack) PushByteArray(so []byte) {
52 s.stk = append(s.stk, so)
55 // PushInt converts the provided scriptNum to a suitable byte array then pushes
56 // it onto the top of the stack.
58 // Stack transformation: [... x1 x2] -> [... x1 x2 int]
59 func (s *stack) PushInt(val scriptNum) {
60 s.PushByteArray(val.Bytes())
63 // PushBool converts the provided boolean to a suitable byte array then pushes
64 // it onto the top of the stack.
66 // Stack transformation: [... x1 x2] -> [... x1 x2 bool]
67 func (s *stack) PushBool(val bool) {
68 s.PushByteArray(fromBool(val))
71 // PopByteArray pops the value off the top of the stack and returns it.
73 // Stack transformation: [... x1 x2 x3] -> [... x1 x2]
74 func (s *stack) PopByteArray() ([]byte, error) {
78 // PopInt pops the value off the top of the stack, converts it into a script
79 // num, and returns it. The act of converting to a script num enforces the
80 // consensus rules imposed on data interpreted as numbers.
82 // Stack transformation: [... x1 x2 x3] -> [... x1 x2]
83 func (s *stack) PopInt() (scriptNum, error) {
84 so, err := s.PopByteArray()
89 return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen)
92 // PopBool pops the value off the top of the stack, converts it into a bool, and
95 // Stack transformation: [... x1 x2 x3] -> [... x1 x2]
96 func (s *stack) PopBool() (bool, error) {
97 so, err := s.PopByteArray()
102 return asBool(so), nil
105 // PeekByteArray returns the Nth item on the stack without removing it.
106 func (s *stack) PeekByteArray(idx int32) ([]byte, error) {
107 sz := int32(len(s.stk))
108 if idx < 0 || idx >= sz {
109 str := fmt.Sprintf("index %d is invalid for stack size %d", idx,
111 return nil, scriptError(ErrInvalidStackOperation, str)
114 return s.stk[sz-idx-1], nil
117 // PeekInt returns the Nth item on the stack as a script num without removing
118 // it. The act of converting to a script num enforces the consensus rules
119 // imposed on data interpreted as numbers.
120 func (s *stack) PeekInt(idx int32) (scriptNum, error) {
121 so, err := s.PeekByteArray(idx)
126 return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen)
129 // PeekBool returns the Nth item on the stack as a bool without removing it.
130 func (s *stack) PeekBool(idx int32) (bool, error) {
131 so, err := s.PeekByteArray(idx)
136 return asBool(so), nil
139 // nipN is an internal function that removes the nth item on the stack and
142 // Stack transformation:
143 // nipN(0): [... x1 x2 x3] -> [... x1 x2]
144 // nipN(1): [... x1 x2 x3] -> [... x1 x3]
145 // nipN(2): [... x1 x2 x3] -> [... x2 x3]
146 func (s *stack) nipN(idx int32) ([]byte, error) {
147 sz := int32(len(s.stk))
148 if idx < 0 || idx > sz-1 {
149 str := fmt.Sprintf("index %d is invalid for stack size %d", idx,
151 return nil, scriptError(ErrInvalidStackOperation, str)
154 so := s.stk[sz-idx-1]
157 } else if idx == sz-1 {
158 s1 := make([][]byte, sz-1)
162 s1 := s.stk[sz-idx : sz]
163 s.stk = s.stk[:sz-idx-1]
164 s.stk = append(s.stk, s1...)
169 // NipN removes the Nth object on the stack
171 // Stack transformation:
172 // NipN(0): [... x1 x2 x3] -> [... x1 x2]
173 // NipN(1): [... x1 x2 x3] -> [... x1 x3]
174 // NipN(2): [... x1 x2 x3] -> [... x2 x3]
175 func (s *stack) NipN(idx int32) error {
176 _, err := s.nipN(idx)
180 // Tuck copies the item at the top of the stack and inserts it before the 2nd
183 // Stack transformation: [... x1 x2] -> [... x2 x1 x2]
184 func (s *stack) Tuck() error {
185 so2, err := s.PopByteArray()
189 so1, err := s.PopByteArray()
193 s.PushByteArray(so2) // stack [... x2]
194 s.PushByteArray(so1) // stack [... x2 x1]
195 s.PushByteArray(so2) // stack [... x2 x1 x2]
200 // DropN removes the top N items from the stack.
202 // Stack transformation:
203 // DropN(1): [... x1 x2] -> [... x1]
204 // DropN(2): [... x1 x2] -> [...]
205 func (s *stack) DropN(n int32) error {
207 str := fmt.Sprintf("attempt to drop %d items from stack", n)
208 return scriptError(ErrInvalidStackOperation, str)
212 _, err := s.PopByteArray()
220 // DupN duplicates the top N items on the stack.
222 // Stack transformation:
223 // DupN(1): [... x1 x2] -> [... x1 x2 x2]
224 // DupN(2): [... x1 x2] -> [... x1 x2 x1 x2]
225 func (s *stack) DupN(n int32) error {
227 str := fmt.Sprintf("attempt to dup %d stack items", n)
228 return scriptError(ErrInvalidStackOperation, str)
231 // Iteratively duplicate the value n-1 down the stack n times.
232 // This leaves an in-order duplicate of the top n items on the stack.
233 for i := n; i > 0; i-- {
234 so, err := s.PeekByteArray(n - 1)
243 // RotN rotates the top 3N items on the stack to the left N times.
245 // Stack transformation:
246 // RotN(1): [... x1 x2 x3] -> [... x2 x3 x1]
247 // RotN(2): [... x1 x2 x3 x4 x5 x6] -> [... x3 x4 x5 x6 x1 x2]
248 func (s *stack) RotN(n int32) error {
250 str := fmt.Sprintf("attempt to rotate %d stack items", n)
251 return scriptError(ErrInvalidStackOperation, str)
254 // Nip the 3n-1th item from the stack to the top n times to rotate
255 // them up to the head of the stack.
257 for i := n; i > 0; i-- {
258 so, err := s.nipN(entry)
268 // SwapN swaps the top N items on the stack with those below them.
270 // Stack transformation:
271 // SwapN(1): [... x1 x2] -> [... x2 x1]
272 // SwapN(2): [... x1 x2 x3 x4] -> [... x3 x4 x1 x2]
273 func (s *stack) SwapN(n int32) error {
275 str := fmt.Sprintf("attempt to swap %d stack items", n)
276 return scriptError(ErrInvalidStackOperation, str)
280 for i := n; i > 0; i-- {
281 // Swap 2n-1th entry to top.
282 so, err := s.nipN(entry)
292 // OverN copies N items N items back to the top of the stack.
294 // Stack transformation:
295 // OverN(1): [... x1 x2 x3] -> [... x1 x2 x3 x2]
296 // OverN(2): [... x1 x2 x3 x4] -> [... x1 x2 x3 x4 x1 x2]
297 func (s *stack) OverN(n int32) error {
299 str := fmt.Sprintf("attempt to perform over on %d stack items",
301 return scriptError(ErrInvalidStackOperation, str)
304 // Copy 2n-1th entry to top of the stack.
307 so, err := s.PeekByteArray(entry)
317 // PickN copies the item N items back in the stack to the top.
319 // Stack transformation:
320 // PickN(0): [x1 x2 x3] -> [x1 x2 x3 x3]
321 // PickN(1): [x1 x2 x3] -> [x1 x2 x3 x2]
322 // PickN(2): [x1 x2 x3] -> [x1 x2 x3 x1]
323 func (s *stack) PickN(n int32) error {
324 so, err := s.PeekByteArray(n)
333 // RollN moves the item N items back in the stack to the top.
335 // Stack transformation:
336 // RollN(0): [x1 x2 x3] -> [x1 x2 x3]
337 // RollN(1): [x1 x2 x3] -> [x1 x3 x2]
338 // RollN(2): [x1 x2 x3] -> [x2 x3 x1]
339 func (s *stack) RollN(n int32) error {
350 // String returns the stack in a readable format.
351 func (s *stack) String() string {
353 for _, stack := range s.stk {
355 result += "00000000 <empty>\n"
357 result += hex.Dump(stack)