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.
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
21 // ErrScriptNotCanonical identifies a non-canonical script. The caller can use
22 // a type assertion to detect this error type.
23 type ErrScriptNotCanonical string
25 // Error implements the error interface.
26 func (e ErrScriptNotCanonical) Error() string {
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.
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 // builder := txscript.NewScriptBuilder()
41 // builder.AddOp(txscript.OP_2).AddData(pubKey1).AddData(pubKey2)
42 // builder.AddData(pubKey3).AddOp(txscript.OP_3)
43 // builder.AddOp(txscript.OP_CHECKMULTISIG)
44 // script, err := builder.Script()
46 // // Handle the error.
49 // fmt.Printf("Final multi-sig script: %x\n", script)
50 type ScriptBuilder struct {
55 // AddOp pushes the passed opcode to the end of the script. The script will not
56 // be modified if pushing the opcode would cause the script to exceed the
57 // maximum allowed script engine size.
58 func (b *ScriptBuilder) AddOp(opcode byte) *ScriptBuilder {
63 // Pushes that would cause the script to exceed the largest allowed
64 // script size would result in a non-canonical script.
65 if len(b.script)+1 > MaxScriptSize {
66 str := fmt.Sprintf("adding an opcode would exceed the maximum "+
67 "allowed canonical script length of %d", MaxScriptSize)
68 b.err = ErrScriptNotCanonical(str)
72 b.script = append(b.script, opcode)
76 // AddOps pushes the passed opcodes to the end of the script. The script will
77 // not be modified if pushing the opcodes would cause the script to exceed the
78 // maximum allowed script engine size.
79 func (b *ScriptBuilder) AddOps(opcodes []byte) *ScriptBuilder {
84 // Pushes that would cause the script to exceed the largest allowed
85 // script size would result in a non-canonical script.
86 if len(b.script)+len(opcodes) > MaxScriptSize {
87 str := fmt.Sprintf("adding opcodes would exceed the maximum "+
88 "allowed canonical script length of %d", MaxScriptSize)
89 b.err = ErrScriptNotCanonical(str)
93 b.script = append(b.script, opcodes...)
97 // canonicalDataSize returns the number of bytes the canonical encoding of the
99 func canonicalDataSize(data []byte) int {
102 // When the data consists of a single number that can be represented
103 // by one of the "small integer" opcodes, that opcode will be instead
104 // of a data push opcode followed by the number.
107 } else if dataLen == 1 && data[0] <= 16 {
109 } else if dataLen == 1 && data[0] == 0x81 {
113 if dataLen < OP_PUSHDATA1 {
115 } else if dataLen <= 0xff {
117 } else if dataLen <= 0xffff {
124 // addData is the internal function that actually pushes the passed data to the
125 // end of the script. It automatically chooses canonical opcodes depending on
126 // the length of the data. A zero length buffer will lead to a push of empty
127 // data onto the stack (OP_0). No data limits are enforced with this function.
128 func (b *ScriptBuilder) addData(data []byte) *ScriptBuilder {
131 // When the data consists of a single number that can be represented
132 // by one of the "small integer" opcodes, use that opcode instead of
133 // a data push opcode followed by the number.
134 if dataLen == 0 || dataLen == 1 && data[0] == 0 {
135 b.script = append(b.script, OP_0)
137 } else if dataLen == 1 && data[0] <= 16 {
138 b.script = append(b.script, (OP_1-1)+data[0])
140 } else if dataLen == 1 && data[0] == 0x81 {
141 b.script = append(b.script, byte(OP_1NEGATE))
145 // Use one of the OP_DATA_# opcodes if the length of the data is small
146 // enough so the data push instruction is only a single byte.
147 // Otherwise, choose the smallest possible OP_PUSHDATA# opcode that
148 // can represent the length of the data.
149 if dataLen < OP_PUSHDATA1 {
150 b.script = append(b.script, byte((OP_DATA_1-1)+dataLen))
151 } else if dataLen <= 0xff {
152 b.script = append(b.script, OP_PUSHDATA1, byte(dataLen))
153 } else if dataLen <= 0xffff {
154 buf := make([]byte, 2)
155 binary.LittleEndian.PutUint16(buf, uint16(dataLen))
156 b.script = append(b.script, OP_PUSHDATA2)
157 b.script = append(b.script, buf...)
159 buf := make([]byte, 4)
160 binary.LittleEndian.PutUint32(buf, uint32(dataLen))
161 b.script = append(b.script, OP_PUSHDATA4)
162 b.script = append(b.script, buf...)
165 // Append the actual data.
166 b.script = append(b.script, data...)
171 // AddFullData should not typically be used by ordinary users as it does not
172 // include the checks which prevent data pushes larger than the maximum allowed
173 // sizes which leads to scripts that can't be executed. This is provided for
174 // testing purposes such as regression tests where sizes are intentionally made
175 // larger than allowed.
177 // Use AddData instead.
178 func (b *ScriptBuilder) AddFullData(data []byte) *ScriptBuilder {
183 return b.addData(data)
186 // AddData pushes the passed data to the end of the script. It automatically
187 // chooses canonical opcodes depending on the length of the data. A zero length
188 // buffer will lead to a push of empty data onto the stack (OP_0) and any push
189 // of data greater than MaxScriptElementSize will not modify the script since
190 // that is not allowed by the script engine. Also, the script will not be
191 // modified if pushing the data would cause the script to exceed the maximum
192 // allowed script engine size.
193 func (b *ScriptBuilder) AddData(data []byte) *ScriptBuilder {
198 // Pushes that would cause the script to exceed the largest allowed
199 // script size would result in a non-canonical script.
200 dataSize := canonicalDataSize(data)
201 if len(b.script)+dataSize > MaxScriptSize {
202 str := fmt.Sprintf("adding %d bytes of data would exceed the "+
203 "maximum allowed canonical script length of %d",
204 dataSize, MaxScriptSize)
205 b.err = ErrScriptNotCanonical(str)
209 // Pushes larger than the max script element size would result in a
210 // script that is not canonical.
212 if dataLen > MaxScriptElementSize {
213 str := fmt.Sprintf("adding a data element of %d bytes would "+
214 "exceed the maximum allowed script element size of %d",
215 dataLen, MaxScriptElementSize)
216 b.err = ErrScriptNotCanonical(str)
220 return b.addData(data)
223 // AddInt64 pushes the passed integer to the end of the script. The script will
224 // not be modified if pushing the data would cause the script to exceed the
225 // maximum allowed script engine size.
226 func (b *ScriptBuilder) AddInt64(val int64) *ScriptBuilder {
231 // Pushes that would cause the script to exceed the largest allowed
232 // script size would result in a non-canonical script.
233 if len(b.script)+1 > MaxScriptSize {
234 str := fmt.Sprintf("adding an integer would exceed the "+
235 "maximum allow canonical script length of %d",
237 b.err = ErrScriptNotCanonical(str)
241 // Fast path for small integers and OP_1NEGATE.
243 b.script = append(b.script, OP_0)
246 if val == -1 || (val >= 1 && val <= 16) {
247 b.script = append(b.script, byte((OP_1-1)+val))
251 return b.AddData(scriptNum(val).Bytes())
254 // Reset resets the script so it has no content.
255 func (b *ScriptBuilder) Reset() *ScriptBuilder {
256 b.script = b.script[0:0]
261 // Script returns the currently built script. When any errors occurred while
262 // building the script, the script will be returned up the point of the first
263 // error along with the error.
264 func (b *ScriptBuilder) Script() ([]byte, error) {
265 return b.script, b.err
268 // NewScriptBuilder returns a new instance of a script builder. See
269 // ScriptBuilder for details.
270 func NewScriptBuilder() *ScriptBuilder {
271 return &ScriptBuilder{
272 script: make([]byte, 0, defaultScriptAlloc),