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