github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/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  }