github.com/dashpay/godash@v0.0.0-20160726055534-e038a21e0e3d/txscript/stack.go (about) 1 // Copyright (c) 2013-2015 The btcsuite developers 2 // Copyright (c) 2016 The Dash developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package txscript 7 8 import "encoding/hex" 9 10 // asBool gets the boolean value of the byte array. 11 func asBool(t []byte) bool { 12 for i := range t { 13 if t[i] != 0 { 14 // Negative 0 is also considered false. 15 if i == len(t)-1 && t[i] == 0x80 { 16 return false 17 } 18 return true 19 } 20 } 21 return false 22 } 23 24 // fromBool converts a boolean into the appropriate byte array. 25 func fromBool(v bool) []byte { 26 if v { 27 return []byte{1} 28 } 29 return nil 30 } 31 32 // stack represents a stack of immutable objects to be used with bitcoin 33 // scripts. Objects may be shared, therefore in usage if a value is to be 34 // changed it *must* be deep-copied first to avoid changing other values on the 35 // stack. 36 type stack struct { 37 stk [][]byte 38 verifyMinimalData bool 39 } 40 41 // Depth returns the number of items on the stack. 42 func (s *stack) Depth() int32 { 43 return int32(len(s.stk)) 44 } 45 46 // PushByteArray adds the given back array to the top of the stack. 47 // 48 // Stack transformation: [... x1 x2] -> [... x1 x2 data] 49 func (s *stack) PushByteArray(so []byte) { 50 s.stk = append(s.stk, so) 51 } 52 53 // PushInt converts the provided scriptNum to a suitable byte array then pushes 54 // it onto the top of the stack. 55 // 56 // Stack transformation: [... x1 x2] -> [... x1 x2 int] 57 func (s *stack) PushInt(val scriptNum) { 58 s.PushByteArray(val.Bytes()) 59 } 60 61 // PushBool converts the provided boolean to a suitable byte array then pushes 62 // it onto the top of the stack. 63 // 64 // Stack transformation: [... x1 x2] -> [... x1 x2 bool] 65 func (s *stack) PushBool(val bool) { 66 s.PushByteArray(fromBool(val)) 67 } 68 69 // PopByteArray pops the value off the top of the stack and returns it. 70 // 71 // Stack transformation: [... x1 x2 x3] -> [... x1 x2] 72 func (s *stack) PopByteArray() ([]byte, error) { 73 return s.nipN(0) 74 } 75 76 // PopInt pops the value off the top of the stack, converts it into a script 77 // num, and returns it. The act of converting to a script num enforces the 78 // consensus rules imposed on data interpreted as numbers. 79 // 80 // Stack transformation: [... x1 x2 x3] -> [... x1 x2] 81 func (s *stack) PopInt() (scriptNum, error) { 82 so, err := s.PopByteArray() 83 if err != nil { 84 return 0, err 85 } 86 87 return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen) 88 } 89 90 // PopBool pops the value off the top of the stack, converts it into a bool, and 91 // returns it. 92 // 93 // Stack transformation: [... x1 x2 x3] -> [... x1 x2] 94 func (s *stack) PopBool() (bool, error) { 95 so, err := s.PopByteArray() 96 if err != nil { 97 return false, err 98 } 99 100 return asBool(so), nil 101 } 102 103 // PeekByteArray returns the Nth item on the stack without removing it. 104 func (s *stack) PeekByteArray(idx int32) ([]byte, error) { 105 sz := int32(len(s.stk)) 106 if idx < 0 || idx >= sz { 107 return nil, ErrStackUnderflow 108 } 109 110 return s.stk[sz-idx-1], nil 111 } 112 113 // PeekInt returns the Nth item on the stack as a script num without removing 114 // it. The act of converting to a script num enforces the consensus rules 115 // imposed on data interpreted as numbers. 116 func (s *stack) PeekInt(idx int32) (scriptNum, error) { 117 so, err := s.PeekByteArray(idx) 118 if err != nil { 119 return 0, err 120 } 121 122 return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen) 123 } 124 125 // PeekBool returns the Nth item on the stack as a bool without removing it. 126 func (s *stack) PeekBool(idx int32) (bool, error) { 127 so, err := s.PeekByteArray(idx) 128 if err != nil { 129 return false, err 130 } 131 132 return asBool(so), nil 133 } 134 135 // nipN is an internal function that removes the nth item on the stack and 136 // returns it. 137 // 138 // Stack transformation: 139 // nipN(0): [... x1 x2 x3] -> [... x1 x2] 140 // nipN(1): [... x1 x2 x3] -> [... x1 x3] 141 // nipN(2): [... x1 x2 x3] -> [... x2 x3] 142 func (s *stack) nipN(idx int32) ([]byte, error) { 143 sz := int32(len(s.stk)) 144 if idx < 0 || idx > sz-1 { 145 return nil, ErrStackUnderflow 146 } 147 148 so := s.stk[sz-idx-1] 149 if idx == 0 { 150 s.stk = s.stk[:sz-1] 151 } else if idx == sz-1 { 152 s1 := make([][]byte, sz-1, sz-1) 153 copy(s1, s.stk[1:]) 154 s.stk = s1 155 } else { 156 s1 := s.stk[sz-idx : sz] 157 s.stk = s.stk[:sz-idx-1] 158 s.stk = append(s.stk, s1...) 159 } 160 return so, nil 161 } 162 163 // NipN removes the Nth object on the stack 164 // 165 // Stack transformation: 166 // NipN(0): [... x1 x2 x3] -> [... x1 x2] 167 // NipN(1): [... x1 x2 x3] -> [... x1 x3] 168 // NipN(2): [... x1 x2 x3] -> [... x2 x3] 169 func (s *stack) NipN(idx int32) error { 170 _, err := s.nipN(idx) 171 return err 172 } 173 174 // Tuck copies the item at the top of the stack and inserts it before the 2nd 175 // to top item. 176 // 177 // Stack transformation: [... x1 x2] -> [... x2 x1 x2] 178 func (s *stack) Tuck() error { 179 so2, err := s.PopByteArray() 180 if err != nil { 181 return err 182 } 183 so1, err := s.PopByteArray() 184 if err != nil { 185 return err 186 } 187 s.PushByteArray(so2) // stack [... x2] 188 s.PushByteArray(so1) // stack [... x2 x1] 189 s.PushByteArray(so2) // stack [... x2 x1 x2] 190 191 return nil 192 } 193 194 // DropN removes the top N items from the stack. 195 // 196 // Stack transformation: 197 // DropN(1): [... x1 x2] -> [... x1] 198 // DropN(2): [... x1 x2] -> [...] 199 func (s *stack) DropN(n int32) error { 200 if n < 1 { 201 return ErrStackInvalidArgs 202 } 203 204 for ; n > 0; n-- { 205 _, err := s.PopByteArray() 206 if err != nil { 207 return err 208 } 209 } 210 return nil 211 } 212 213 // DupN duplicates the top N items on the stack. 214 // 215 // Stack transformation: 216 // DupN(1): [... x1 x2] -> [... x1 x2 x2] 217 // DupN(2): [... x1 x2] -> [... x1 x2 x1 x2] 218 func (s *stack) DupN(n int32) error { 219 if n < 1 { 220 return ErrStackInvalidArgs 221 } 222 223 // Iteratively duplicate the value n-1 down the stack n times. 224 // This leaves an in-order duplicate of the top n items on the stack. 225 for i := n; i > 0; i-- { 226 so, err := s.PeekByteArray(n - 1) 227 if err != nil { 228 return err 229 } 230 s.PushByteArray(so) 231 } 232 return nil 233 } 234 235 // RotN rotates the top 3N items on the stack to the left N times. 236 // 237 // Stack transformation: 238 // RotN(1): [... x1 x2 x3] -> [... x2 x3 x1] 239 // RotN(2): [... x1 x2 x3 x4 x5 x6] -> [... x3 x4 x5 x6 x1 x2] 240 func (s *stack) RotN(n int32) error { 241 if n < 1 { 242 return ErrStackInvalidArgs 243 } 244 245 // Nip the 3n-1th item from the stack to the top n times to rotate 246 // them up to the head of the stack. 247 entry := 3*n - 1 248 for i := n; i > 0; i-- { 249 so, err := s.nipN(entry) 250 if err != nil { 251 return err 252 } 253 254 s.PushByteArray(so) 255 } 256 return nil 257 } 258 259 // SwapN swaps the top N items on the stack with those below them. 260 // 261 // Stack transformation: 262 // SwapN(1): [... x1 x2] -> [... x2 x1] 263 // SwapN(2): [... x1 x2 x3 x4] -> [... x3 x4 x1 x2] 264 func (s *stack) SwapN(n int32) error { 265 if n < 1 { 266 return ErrStackInvalidArgs 267 } 268 269 entry := 2*n - 1 270 for i := n; i > 0; i-- { 271 // Swap 2n-1th entry to top. 272 so, err := s.nipN(entry) 273 if err != nil { 274 return err 275 } 276 277 s.PushByteArray(so) 278 } 279 return nil 280 } 281 282 // OverN copies N items N items back to the top of the stack. 283 // 284 // Stack transformation: 285 // OverN(1): [... x1 x2 x3] -> [... x1 x2 x3 x2] 286 // OverN(2): [... x1 x2 x3 x4] -> [... x1 x2 x3 x4 x1 x2] 287 func (s *stack) OverN(n int32) error { 288 if n < 1 { 289 return ErrStackInvalidArgs 290 } 291 292 // Copy 2n-1th entry to top of the stack. 293 entry := 2*n - 1 294 for ; n > 0; n-- { 295 so, err := s.PeekByteArray(entry) 296 if err != nil { 297 return err 298 } 299 s.PushByteArray(so) 300 } 301 302 return nil 303 } 304 305 // PickN copies the item N items back in the stack to the top. 306 // 307 // Stack transformation: 308 // PickN(0): [x1 x2 x3] -> [x1 x2 x3 x3] 309 // PickN(1): [x1 x2 x3] -> [x1 x2 x3 x2] 310 // PickN(2): [x1 x2 x3] -> [x1 x2 x3 x1] 311 func (s *stack) PickN(n int32) error { 312 so, err := s.PeekByteArray(n) 313 if err != nil { 314 return err 315 } 316 s.PushByteArray(so) 317 318 return nil 319 } 320 321 // RollN moves the item N items back in the stack to the top. 322 // 323 // Stack transformation: 324 // RollN(0): [x1 x2 x3] -> [x1 x2 x3] 325 // RollN(1): [x1 x2 x3] -> [x1 x3 x2] 326 // RollN(2): [x1 x2 x3] -> [x2 x3 x1] 327 func (s *stack) RollN(n int32) error { 328 so, err := s.nipN(n) 329 if err != nil { 330 return err 331 } 332 333 s.PushByteArray(so) 334 335 return nil 336 } 337 338 // String returns the stack in a readable format. 339 func (s *stack) String() string { 340 var result string 341 for _, stack := range s.stk { 342 if len(stack) == 0 { 343 result += "00000000 <empty>\n" 344 } 345 result += hex.Dump(stack) 346 } 347 348 return result 349 }