OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / txscript / scriptbuilder.go
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 //      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()
45 //      if err != nil {
46 //              // Handle the error.
47 //              return
48 //      }
49 //      fmt.Printf("Final multi-sig script: %x\n", script)
50 type ScriptBuilder struct {
51         script []byte
52         err    error
53 }
54
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 {
59         if b.err != nil {
60                 return b
61         }
62
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)
69                 return b
70         }
71
72         b.script = append(b.script, opcode)
73         return b
74 }
75
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 {
80         if b.err != nil {
81                 return b
82         }
83
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)
90                 return b
91         }
92
93         b.script = append(b.script, opcodes...)
94         return b
95 }
96
97 // canonicalDataSize returns the number of bytes the canonical encoding of the
98 // data will take.
99 func canonicalDataSize(data []byte) int {
100         dataLen := len(data)
101
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.
105         if dataLen == 0 {
106                 return 1
107         } else if dataLen == 1 && data[0] <= 16 {
108                 return 1
109         } else if dataLen == 1 && data[0] == 0x81 {
110                 return 1
111         }
112
113         if dataLen < OP_PUSHDATA1 {
114                 return 1 + dataLen
115         } else if dataLen <= 0xff {
116                 return 2 + dataLen
117         } else if dataLen <= 0xffff {
118                 return 3 + dataLen
119         }
120
121         return 5 + dataLen
122 }
123
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 {
129         dataLen := len(data)
130
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)
136                 return b
137         } else if dataLen == 1 && data[0] <= 16 {
138                 b.script = append(b.script, (OP_1-1)+data[0])
139                 return b
140         } else if dataLen == 1 && data[0] == 0x81 {
141                 b.script = append(b.script, byte(OP_1NEGATE))
142                 return b
143         }
144
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...)
158         } else {
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...)
163         }
164
165         // Append the actual data.
166         b.script = append(b.script, data...)
167
168         return b
169 }
170
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.
176 //
177 // Use AddData instead.
178 func (b *ScriptBuilder) AddFullData(data []byte) *ScriptBuilder {
179         if b.err != nil {
180                 return b
181         }
182
183         return b.addData(data)
184 }
185
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 {
194         if b.err != nil {
195                 return b
196         }
197
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)
206                 return b
207         }
208
209         // Pushes larger than the max script element size would result in a
210         // script that is not canonical.
211         dataLen := len(data)
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)
217                 return b
218         }
219
220         return b.addData(data)
221 }
222
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 {
227         if b.err != nil {
228                 return b
229         }
230
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",
236                         MaxScriptSize)
237                 b.err = ErrScriptNotCanonical(str)
238                 return b
239         }
240
241         // Fast path for small integers and OP_1NEGATE.
242         if val == 0 {
243                 b.script = append(b.script, OP_0)
244                 return b
245         }
246         if val == -1 || (val >= 1 && val <= 16) {
247                 b.script = append(b.script, byte((OP_1-1)+val))
248                 return b
249         }
250
251         return b.AddData(scriptNum(val).Bytes())
252 }
253
254 // Reset resets the script so it has no content.
255 func (b *ScriptBuilder) Reset() *ScriptBuilder {
256         b.script = b.script[0:0]
257         b.err = nil
258         return b
259 }
260
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
266 }
267
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),
273         }
274 }