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