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  }