github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/script/stack.go (about) 1 package script 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "github.com/piotrnar/gocoin/lib/btc" 7 ) 8 9 const nMaxNumSize = 4 10 11 type scrStack struct { 12 data [][]byte 13 } 14 15 func (s *scrStack) copy_from(x *scrStack) { 16 s.data = make([][]byte, len(x.data)) 17 for i := range x.data { 18 s.data[i] = x.data[i] 19 } 20 } 21 22 func (s *scrStack) push(d []byte) { 23 s.data = append(s.data, d) 24 } 25 26 func (s *scrStack) pushBool(v bool) { 27 if v { 28 s.data = append(s.data, []byte{1}) 29 } else { 30 s.data = append(s.data, []byte{}) 31 } 32 } 33 34 func (s *scrStack) pushInt(val int64) { 35 var negative bool 36 37 if val < 0 { 38 negative = true 39 val = -val 40 } 41 var d []byte 42 43 if val != 0 { 44 for val != 0 { 45 d = append(d, byte(val)) 46 val >>= 8 47 } 48 49 if negative { 50 if (d[len(d)-1] & 0x80) != 0 { 51 d = append(d, 0x80) 52 } else { 53 d[len(d)-1] |= 0x80 54 } 55 } else if (d[len(d)-1] & 0x80) != 0 { 56 d = append(d, 0x00) 57 } 58 } 59 60 s.data = append(s.data, d) 61 } 62 63 func bts2int(d []byte) (res int64) { 64 if len(d) > nMaxNumSize { 65 panic("Int on the stack is too long") 66 // Make sure this panic is captured in evalScript (cause the script to fail, not crash) 67 } 68 69 if len(d) == 0 { 70 return 71 } 72 73 var i int 74 for i < len(d)-1 { 75 res |= int64(d[i]) << uint(i*8) 76 i++ 77 } 78 79 if (d[i] & 0x80) != 0 { 80 res |= int64(d[i]&0x7f) << uint(i*8) 81 res = -res 82 } else { 83 res |= int64(d[i]) << uint(i*8) 84 } 85 86 return 87 } 88 89 func bts2int_ext(d []byte, max_bytes int, forcemin bool) (res int64) { 90 if len(d) > max_bytes { 91 panic("bts2int_ext: Int on the stack is too long") 92 // Make sure this panic is captured in evalScript (cause the script to fail, not crash) 93 } 94 95 if len(d) == 0 { 96 return 97 } 98 99 if forcemin && !is_minimal(d) { 100 panic("bts2int_ext: Not a minimal length") 101 } 102 103 var i int 104 for i < len(d)-1 { 105 res |= int64(d[i]) << uint(i*8) 106 i++ 107 } 108 109 if (d[i] & 0x80) != 0 { 110 res |= int64(d[i]&0x7f) << uint(i*8) 111 res = -res 112 } else { 113 res |= int64(d[i]) << uint(i*8) 114 } 115 116 return 117 } 118 119 func bts2bool(d []byte) bool { 120 if len(d) == 0 { 121 return false 122 } 123 for i := 0; i < len(d)-1; i++ { 124 if d[i] != 0 { 125 return true 126 } 127 } 128 return (d[len(d)-1] & 0x7f) != 0 // -0 (0x80) is also false (I hope..) 129 } 130 131 func is_minimal(d []byte) bool { 132 // Check that the number is encoded with the minimum possible 133 // number of bytes. 134 if len(d) > 0 { 135 // If the most-significant-byte - excluding the sign bit - is zero 136 // then we're not minimal. Note how this test also rejects the 137 // negative-zero encoding, 0x80. 138 if (d[len(d)-1] & 0x7f) == 0 { 139 // One exception: if there's more than one byte and the most 140 // significant bit of the second-most-significant-byte is set 141 // it would conflict with the sign bit. An example of this case 142 // is +-255, which encode to 0xff00 and 0xff80 respectively. 143 // (big-endian). 144 if len(d) <= 1 || (d[len(d)-2]&0x80) == 0 { 145 return false 146 } 147 } 148 } 149 return true 150 } 151 152 func (s *scrStack) popInt(check_for_min bool) int64 { 153 d := s.pop() 154 if check_for_min && !is_minimal(d) { 155 panic("Not minimal value") 156 } 157 return bts2int(d) 158 } 159 160 func (s *scrStack) popBool() bool { 161 return bts2bool(s.pop()) 162 } 163 164 func (s *scrStack) top(idx int) (d []byte) { 165 return s.data[len(s.data)+idx] 166 } 167 168 func (s *scrStack) at(idx int) (d []byte) { 169 return s.data[idx] 170 } 171 172 func (s *scrStack) topInt(idx int, check_for_min bool) int64 { 173 d := s.data[len(s.data)+idx] 174 if check_for_min && !is_minimal(d) { 175 panic("Not minimal value") 176 } 177 return bts2int(d) 178 } 179 180 func (s *scrStack) topBool(idx int) bool { 181 return bts2bool(s.data[len(s.data)+idx]) 182 } 183 184 func (s *scrStack) pop() (d []byte) { 185 l := len(s.data) 186 if l == 0 { 187 panic("stack is empty") 188 } 189 d = s.data[l-1] 190 s.data = s.data[:l-1] 191 return 192 } 193 194 func (s *scrStack) nofalse() bool { 195 for i := range s.data { 196 if !bts2bool(s.data[i]) { 197 return false 198 } 199 } 200 return true 201 } 202 203 func (s *scrStack) size() int { 204 return len(s.data) 205 } 206 207 func (s *scrStack) print() { 208 fmt.Println(len(s.data), "elements on stack:") 209 for i := range s.data { 210 fmt.Printf("%3d: len=%d, data:%s\n", i, len(s.data[i]), hex.EncodeToString(s.data[i])) 211 } 212 } 213 214 func (s *scrStack) resize(siz int) { 215 s.data = s.data[:siz] 216 } 217 218 func (s *scrStack) GetSerializeSize() (res int) { 219 res += btc.VLenSize(uint64(len(s.data))) 220 for _, d := range s.data { 221 res += btc.VLenSize(uint64(len(d))) 222 res += len(d) 223 } 224 return 225 }