github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/txscript/scriptbuilder.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 (
     9  	"encoding/binary"
    10  	"fmt"
    11  )
    12  
    13  const (
    14  	// defaultScriptAlloc is the default size used for the backing array
    15  	// for a script being built by the ScriptBuilder.  The array will
    16  	// dynamically grow as needed, but this figure is intended to provide
    17  	// enough space for vast majority of scripts without needing to grow the
    18  	// backing array multiple times.
    19  	defaultScriptAlloc = 500
    20  )
    21  
    22  // ErrScriptNotCanonical identifies a non-canonical script.  The caller can use
    23  // a type assertion to detect this error type.
    24  type ErrScriptNotCanonical string
    25  
    26  // Error implements the error interface.
    27  func (e ErrScriptNotCanonical) Error() string {
    28  	return string(e)
    29  }
    30  
    31  // ScriptBuilder provides a facility for building custom scripts.  It allows
    32  // you to push opcodes, ints, and data while respecting canonical encoding.  In
    33  // general it does not ensure the script will execute correctly, however any
    34  // data pushes which would exceed the maximum allowed script engine limits and
    35  // are therefore guaranteed not to execute will not be pushed and will result in
    36  // the Script function returning an error.
    37  //
    38  // For example, the following would build a 2-of-3 multisig script for usage in
    39  // a pay-to-script-hash (although in this situation MultiSigScript() would be a
    40  // better choice to generate the script):
    41  // 	builder := txscript.NewScriptBuilder()
    42  // 	builder.AddOp(txscript.OP_2).AddData(pubKey1).AddData(pubKey2)
    43  // 	builder.AddData(pubKey3).AddOp(txscript.OP_3)
    44  // 	builder.AddOp(txscript.OP_CHECKMULTISIG)
    45  // 	script, err := builder.Script()
    46  // 	if err != nil {
    47  // 		// Handle the error.
    48  // 		return
    49  // 	}
    50  // 	fmt.Printf("Final multi-sig script: %x\n", script)
    51  type ScriptBuilder struct {
    52  	script []byte
    53  	err    error
    54  }
    55  
    56  // AddOp pushes the passed opcode to the end of the script.  The script will not
    57  // be modified if pushing the opcode would cause the script to exceed the
    58  // maximum allowed script engine size.
    59  func (b *ScriptBuilder) AddOp(opcode byte) *ScriptBuilder {
    60  	if b.err != nil {
    61  		return b
    62  	}
    63  
    64  	// Pushes that would cause the script to exceed the largest allowed
    65  	// script size would result in a non-canonical script.
    66  	if len(b.script)+1 > maxScriptSize {
    67  		str := fmt.Sprintf("adding an opcode would exceed the maximum "+
    68  			"allowed canonical script length of %d", maxScriptSize)
    69  		b.err = ErrScriptNotCanonical(str)
    70  		return b
    71  	}
    72  
    73  	b.script = append(b.script, opcode)
    74  	return b
    75  }
    76  
    77  // canonicalDataSize returns the number of bytes the canonical encoding of the
    78  // data will take.
    79  func canonicalDataSize(data []byte) int {
    80  	dataLen := len(data)
    81  
    82  	// When the data consists of a single number that can be represented
    83  	// by one of the "small integer" opcodes, that opcode will be instead
    84  	// of a data push opcode followed by the number.
    85  	if dataLen == 0 {
    86  		return 1
    87  	} else if dataLen == 1 && data[0] <= 16 {
    88  		return 1
    89  	} else if dataLen == 1 && data[0] == 0x81 {
    90  		return 1
    91  	}
    92  
    93  	if dataLen < OP_PUSHDATA1 {
    94  		return 1 + dataLen
    95  	} else if dataLen <= 0xff {
    96  		return 2 + dataLen
    97  	} else if dataLen <= 0xffff {
    98  		return 3 + dataLen
    99  	}
   100  
   101  	return 5 + dataLen
   102  }
   103  
   104  // addData is the internal function that actually pushes the passed data to the
   105  // end of the script.  It automatically chooses canonical opcodes depending on
   106  // the length of the data.  A zero length buffer will lead to a push of empty
   107  // data onto the stack (OP_0).  No data limits are enforced with this function.
   108  func (b *ScriptBuilder) addData(data []byte) *ScriptBuilder {
   109  	dataLen := len(data)
   110  
   111  	// When the data consists of a single number that can be represented
   112  	// by one of the "small integer" opcodes, use that opcode instead of
   113  	// a data push opcode followed by the number.
   114  	if dataLen == 0 || dataLen == 1 && data[0] == 0 {
   115  		b.script = append(b.script, OP_0)
   116  		return b
   117  	} else if dataLen == 1 && data[0] <= 16 {
   118  		b.script = append(b.script, byte((OP_1-1)+data[0]))
   119  		return b
   120  	} else if dataLen == 1 && data[0] == 0x81 {
   121  		b.script = append(b.script, byte(OP_1NEGATE))
   122  		return b
   123  	}
   124  
   125  	// Use one of the OP_DATA_# opcodes if the length of the data is small
   126  	// enough so the data push instruction is only a single byte.
   127  	// Otherwise, choose the smallest possible OP_PUSHDATA# opcode that
   128  	// can represent the length of the data.
   129  	if dataLen < OP_PUSHDATA1 {
   130  		b.script = append(b.script, byte((OP_DATA_1-1)+dataLen))
   131  	} else if dataLen <= 0xff {
   132  		b.script = append(b.script, OP_PUSHDATA1, byte(dataLen))
   133  	} else if dataLen <= 0xffff {
   134  		buf := make([]byte, 2)
   135  		binary.LittleEndian.PutUint16(buf, uint16(dataLen))
   136  		b.script = append(b.script, OP_PUSHDATA2)
   137  		b.script = append(b.script, buf...)
   138  	} else {
   139  		buf := make([]byte, 4)
   140  		binary.LittleEndian.PutUint32(buf, uint32(dataLen))
   141  		b.script = append(b.script, OP_PUSHDATA4)
   142  		b.script = append(b.script, buf...)
   143  	}
   144  
   145  	// Append the actual data.
   146  	b.script = append(b.script, data...)
   147  
   148  	return b
   149  }
   150  
   151  // AddFullData should not typically be used by ordinary users as it does not
   152  // include the checks which prevent data pushes larger than the maximum allowed
   153  // sizes which leads to scripts that can't be executed.  This is provided for
   154  // testing purposes such as regression tests where sizes are intentionally made
   155  // larger than allowed.
   156  //
   157  // Use AddData instead.
   158  func (b *ScriptBuilder) AddFullData(data []byte) *ScriptBuilder {
   159  	if b.err != nil {
   160  		return b
   161  	}
   162  
   163  	return b.addData(data)
   164  }
   165  
   166  // AddData pushes the passed data to the end of the script.  It automatically
   167  // chooses canonical opcodes depending on the length of the data.  A zero length
   168  // buffer will lead to a push of empty data onto the stack (OP_0) and any push
   169  // of data greater than MaxScriptElementSize will not modify the script since
   170  // that is not allowed by the script engine.  Also, the script will not be
   171  // modified if pushing the data would cause the script to exceed the maximum
   172  // allowed script engine size.
   173  func (b *ScriptBuilder) AddData(data []byte) *ScriptBuilder {
   174  	if b.err != nil {
   175  		return b
   176  	}
   177  
   178  	// Pushes that would cause the script to exceed the largest allowed
   179  	// script size would result in a non-canonical script.
   180  	dataSize := canonicalDataSize(data)
   181  	if len(b.script)+dataSize > maxScriptSize {
   182  		str := fmt.Sprintf("adding %d bytes of data would exceed the "+
   183  			"maximum allowed canonical script length of %d",
   184  			dataSize, maxScriptSize)
   185  		b.err = ErrScriptNotCanonical(str)
   186  		return b
   187  	}
   188  
   189  	// Pushes larger than the max script element size would result in a
   190  	// script that is not canonical.
   191  	dataLen := len(data)
   192  	if dataLen > MaxScriptElementSize {
   193  		str := fmt.Sprintf("adding a data element of %d bytes would "+
   194  			"exceed the maximum allowed script element size of %d",
   195  			dataLen, maxScriptSize)
   196  		b.err = ErrScriptNotCanonical(str)
   197  		return b
   198  	}
   199  
   200  	return b.addData(data)
   201  }
   202  
   203  // AddInt64 pushes the passed integer to the end of the script.  The script will
   204  // not be modified if pushing the data would cause the script to exceed the
   205  // maximum allowed script engine size.
   206  func (b *ScriptBuilder) AddInt64(val int64) *ScriptBuilder {
   207  	if b.err != nil {
   208  		return b
   209  	}
   210  
   211  	// Pushes that would cause the script to exceed the largest allowed
   212  	// script size would result in a non-canonical script.
   213  	if len(b.script)+1 > maxScriptSize {
   214  		str := fmt.Sprintf("adding an integer would exceed the "+
   215  			"maximum allow canonical script length of %d",
   216  			maxScriptSize)
   217  		b.err = ErrScriptNotCanonical(str)
   218  		return b
   219  	}
   220  
   221  	// Fast path for small integers and OP_1NEGATE.
   222  	if val == 0 {
   223  		b.script = append(b.script, OP_0)
   224  		return b
   225  	}
   226  	if val == -1 || (val >= 1 && val <= 16) {
   227  		b.script = append(b.script, byte((OP_1-1)+val))
   228  		return b
   229  	}
   230  
   231  	return b.AddData(scriptNum(val).Bytes())
   232  }
   233  
   234  // Reset resets the script so it has no content.
   235  func (b *ScriptBuilder) Reset() *ScriptBuilder {
   236  	b.script = b.script[0:0]
   237  	b.err = nil
   238  	return b
   239  }
   240  
   241  // Script returns the currently built script.  When any errors occurred while
   242  // building the script, the script will be returned up the point of the first
   243  // error along with the error.
   244  func (b *ScriptBuilder) Script() ([]byte, error) {
   245  	return b.script, b.err
   246  }
   247  
   248  // NewScriptBuilder returns a new instance of a script builder.  See
   249  // ScriptBuilder for details.
   250  func NewScriptBuilder() *ScriptBuilder {
   251  	return &ScriptBuilder{
   252  		script: make([]byte, 0, defaultScriptAlloc),
   253  	}
   254  }