OSDN Git Service

maker taker v2
[bytom/vapor.git] / protocol / vm / vmutil / script.go
1 package vmutil
2
3 import (
4         "github.com/bytom/vapor/crypto/ed25519"
5         "github.com/bytom/vapor/errors"
6         "github.com/bytom/vapor/protocol/bc"
7         "github.com/bytom/vapor/protocol/vm"
8 )
9
10 // pre-define errors
11 var (
12         ErrBadValue       = errors.New("bad value")
13         ErrMultisigFormat = errors.New("bad multisig program format")
14 )
15
16 // MagneticContractArgs is a struct for magnetic contract arguments
17 type MagneticContractArgs struct {
18         RequestedAsset   bc.AssetID
19         RatioNumerator   int64
20         RatioDenominator int64
21         SellerProgram    []byte
22         SellerKey        []byte
23         Version          int
24 }
25
26 // IsUnspendable checks if a contorl program is absolute failed
27 func IsUnspendable(prog []byte) bool {
28         return len(prog) > 0 && prog[0] == byte(vm.OP_FAIL)
29 }
30
31 func (b *Builder) addP2SPMultiSig(pubkeys []ed25519.PublicKey, nrequired int) error {
32         if err := checkMultiSigParams(int64(nrequired), int64(len(pubkeys))); err != nil {
33                 return err
34         }
35
36         b.AddOp(vm.OP_TXSIGHASH) // stack is now [... NARGS SIG SIG SIG PREDICATEHASH]
37         for _, p := range pubkeys {
38                 b.AddData(p)
39         }
40         b.AddInt64(int64(nrequired))    // stack is now [... SIG SIG SIG PREDICATEHASH PUB PUB PUB M]
41         b.AddInt64(int64(len(pubkeys))) // stack is now [... SIG SIG SIG PREDICATEHASH PUB PUB PUB M N]
42         b.AddOp(vm.OP_CHECKMULTISIG)    // stack is now [... NARGS]
43         return nil
44 }
45
46 // DefaultCoinbaseProgram generates the script for contorl coinbase output
47 func DefaultCoinbaseProgram() ([]byte, error) {
48         builder := NewBuilder()
49         builder.AddOp(vm.OP_TRUE)
50         return builder.Build()
51 }
52
53 // P2WPKHProgram return the segwit pay to public key hash
54 func P2WPKHProgram(hash []byte) ([]byte, error) {
55         builder := NewBuilder()
56         builder.AddInt64(0)
57         builder.AddData(hash)
58         return builder.Build()
59 }
60
61 // P2WSHProgram return the segwit pay to script hash
62 func P2WSHProgram(hash []byte) ([]byte, error) {
63         builder := NewBuilder()
64         builder.AddInt64(0)
65         builder.AddData(hash)
66         return builder.Build()
67 }
68
69 // RetireProgram generates the script for retire output
70 func RetireProgram(comment []byte) ([]byte, error) {
71         builder := NewBuilder()
72         builder.AddOp(vm.OP_FAIL)
73         if len(comment) != 0 {
74                 builder.AddData(comment)
75         }
76         return builder.Build()
77 }
78
79 // P2PKHSigProgram generates the script for control with pubkey hash
80 func P2PKHSigProgram(pubkeyHash []byte) ([]byte, error) {
81         builder := NewBuilder()
82         builder.AddOp(vm.OP_DUP)
83         builder.AddOp(vm.OP_HASH160)
84         builder.AddData(pubkeyHash)
85         builder.AddOp(vm.OP_EQUALVERIFY)
86         builder.AddOp(vm.OP_TXSIGHASH)
87         builder.AddOp(vm.OP_SWAP)
88         builder.AddOp(vm.OP_CHECKSIG)
89         return builder.Build()
90 }
91
92 // P2SHProgram generates the script for control with script hash
93 func P2SHProgram(scriptHash []byte) ([]byte, error) {
94         builder := NewBuilder()
95         builder.AddOp(vm.OP_DUP)
96         builder.AddOp(vm.OP_SHA3)
97         builder.AddData(scriptHash)
98         builder.AddOp(vm.OP_EQUALVERIFY)
99         builder.AddInt64(-1)
100         builder.AddOp(vm.OP_SWAP)
101         builder.AddInt64(0)
102         builder.AddOp(vm.OP_CHECKPREDICATE)
103         return builder.Build()
104 }
105
106 // P2SPMultiSigProgram generates the script for control transaction output
107 func P2SPMultiSigProgram(pubkeys []ed25519.PublicKey, nrequired int) ([]byte, error) {
108         builder := NewBuilder()
109         if err := builder.addP2SPMultiSig(pubkeys, nrequired); err != nil {
110                 return nil, err
111         }
112         return builder.Build()
113 }
114
115 // P2SPMultiSigProgramWithHeight generates the script with block height for control transaction output
116 func P2SPMultiSigProgramWithHeight(pubkeys []ed25519.PublicKey, nrequired int, blockHeight int64) ([]byte, error) {
117         builder := NewBuilder()
118         if blockHeight > 0 {
119                 builder.AddInt64(blockHeight)
120                 builder.AddOp(vm.OP_BLOCKHEIGHT)
121                 builder.AddOp(vm.OP_GREATERTHAN)
122                 builder.AddOp(vm.OP_VERIFY)
123         } else if blockHeight < 0 {
124                 return nil, errors.WithDetail(ErrBadValue, "negative blockHeight")
125         }
126         if err := builder.addP2SPMultiSig(pubkeys, nrequired); err != nil {
127                 return nil, err
128         }
129         return builder.Build()
130 }
131
132 func checkMultiSigParams(nrequired, npubkeys int64) error {
133         if nrequired < 0 {
134                 return errors.WithDetail(ErrBadValue, "negative quorum")
135         }
136         if npubkeys < 0 {
137                 return errors.WithDetail(ErrBadValue, "negative pubkey count")
138         }
139         if nrequired > npubkeys {
140                 return errors.WithDetail(ErrBadValue, "quorum too big")
141         }
142         if nrequired == 0 && npubkeys > 0 {
143                 return errors.WithDetail(ErrBadValue, "quorum empty with non-empty pubkey list")
144         }
145         return nil
146 }
147
148 // P2WMCProgram return the segwit pay to magnetic contract
149 func P2WMCProgram(magneticContractArgs MagneticContractArgs) ([]byte, error) {
150         builder := NewBuilder()
151         builder.AddInt64(0)
152         builder.AddData(magneticContractArgs.RequestedAsset.Bytes())
153         builder.AddInt64(magneticContractArgs.RatioNumerator)
154         builder.AddInt64(magneticContractArgs.RatioDenominator)
155         builder.AddData(magneticContractArgs.SellerProgram)
156         builder.AddData(magneticContractArgs.SellerKey)
157         return builder.Build()
158 }
159
160 // P2MCProgram generates the script for control with magnetic contract
161 //
162 // MagneticContract source code:
163 // contract MagneticContract(requestedAsset: Asset,
164 //                           ratioNumerator: Integer,
165 //                           ratioDenominator: Integer,
166 //                           sellerProgram: Program,
167 //                           standardProgram: Program,
168 //                           sellerKey: PublicKey) locks valueAmount of valueAsset {
169 //  clause partialTrade(exchangeAmount: Amount) {
170 //   define actualAmount: Integer = exchangeAmount * ratioDenominator / ratioNumerator
171 //   verify actualAmount >= 0 && actualAmount < valueAmount
172 //   define receiveAmount: Integer = exchangeAmount * 999 / 1000
173 //   lock receiveAmount of requestedAsset with sellerProgram
174 //   lock valueAmount-actualAmount of valueAsset with standardProgram
175 //   unlock actualAmount of valueAsset
176 //  }
177 //  clause fullTrade() {
178 //   define requestedAmount: Integer = valueAmount * ratioNumerator / ratioDenominator
179 //   define requestedAmount: Integer = requestedAmount * 999 / 1000
180 //   verify requestedAmount >= 0
181 //   lock requestedAmount of requestedAsset with sellerProgram
182 //   unlock valueAmount of valueAsset
183 //  }
184 //  clause cancel(sellerSig: Signature) {
185 //   verify checkTxSig(sellerKey, sellerSig)
186 //   unlock valueAmount of valueAsset
187 //  }
188 // }
189 //
190 // contract stack flow:
191 // 7                        [... <position> <clause selector> sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset 7]
192 // ROLL                     [... <clause selector> sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <position>]
193 // TOALTSTACK               [... <clause selector> sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
194 // 6                        [... <clause selector> sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset 6]
195 // ROLL                     [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector>]
196 // DUP                      [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector> <clause selector>]
197 // 2                        [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector> <clause selector> 2]
198 // NUMEQUAL                 [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector> (<clause selector> == 2)]
199 // JUMPIF:$cancel           [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector>]
200 // JUMPIF:$fullTrade        [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
201 // $partialTrade            [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
202 // 6                        [... exchangeAmount sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset 6]
203 // PICK                     [... exchangeAmount sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset exchangeAmount]
204 // 3                        [... exchangeAmount sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset exchangeAmount 3]
205 // ROLL                     [... exchangeAmount sellerKey standardProgram sellerProgram ratioNumerator requestedAsset exchangeAmount ratioDenominator]
206 // 3                        [... exchangeAmount sellerKey standardProgram sellerProgram ratioNumerator requestedAsset exchangeAmount ratioDenominator 3]
207 // ROLL                     [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset exchangeAmount ratioDenominator ratioNumerator]
208 // MULFRACTION              [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount]
209 // AMOUNT                   [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount]
210 // OVER                     [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount actualAmount]
211 // 0                        [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount actualAmount 0]
212 // GREATERTHANOREQUAL       [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0)]
213 // 2                        [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0) 2]
214 // PICK                     [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0) actualAmount]
215 // 2                        [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount valueAmount (actualAmount > 0) actualAmount 2]
216 // ROLL                     [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount (actualAmount > 0) actualAmount valueAmount]
217 // LESSTHAN                 [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount (actualAmount > 0) (actualAmount < valueAmount)]
218 // BOOLAND                  [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount ((actualAmount > 0) && (actualAmount < valueAmount))]
219 // VERIFY                   [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount]
220 // FROMALTSTACK             [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount <position>]
221 // DUP                      [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> <position>]
222 // TOALTSTACK               [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount <position>]
223 // 6                        [... exchangeAmount sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> 6]
224 // ROLL                     [... sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> exchangeAmount]
225 // 999                      [... sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> exchangeAmount 999]
226 // 1000                     [... sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> exchangeAmount 1000]
227 // MULFRACTION              [... sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> receiveAmount]
228 // 3                        [... sellerKey standardProgram sellerProgram requestedAsset actualAmount <position> receiveAmount 3]
229 // ROLL                     [... sellerKey standardProgram sellerProgram actualAmount <position> receiveAmount requestedAsset]
230 // 1                        [... sellerKey standardProgram sellerProgram actualAmount <position> receiveAmount requestedAsset 1]
231 // 5                        [... sellerKey standardProgram sellerProgram actualAmount <position> receiveAmount requestedAsset 1 5]
232 // ROLL                     [... sellerKey standardProgram actualAmount <position> receiveAmount requestedAsset 1 sellerProgram]
233 // CHECKOUTPUT              [... sellerKey standardProgram actualAmount checkOutput(receiveAmount, requestedAsset, sellerProgram)]
234 // VERIFY                   [... sellerKey standardProgram actualAmount]
235 // FROMALTSTACK             [... sellerKey standardProgram actualAmount <position>]
236 // 1                        [... sellerKey standardProgram actualAmount <position> 1]
237 // ADD                      [... sellerKey standardProgram actualAmount (<position> + 1)]
238 // AMOUNT                   [... sellerKey standardProgram actualAmount (<position> + 1) valueAmount]
239 // 2                        [... sellerKey standardProgram actualAmount (<position> + 1) valueAmount 2]
240 // ROLL                     [... sellerKey standardProgram (<position> + 1) valueAmount actualAmount]
241 // SUB                      [... sellerKey standardProgram (<position> + 1) (valueAmount - actualAmount)]
242 // ASSET                    [... sellerKey standardProgram (<position> + 1) (valueAmount - actualAmount) valueAsset]
243 // 1                        [... sellerKey standardProgram (<position> + 1) (valueAmount - actualAmount) valueAsset 1]
244 // 4                        [... sellerKey standardProgram (<position> + 1) (valueAmount - actualAmount) valueAsset 1 4]
245 // ROLL                     [... sellerKey (<position> + 1) (valueAmount - actualAmount) valueAsset 1 standardProgram]
246 // CHECKOUTPUT              [... sellerKey checkOutput((valueAmount - actualAmount), valueAsset, standardProgram)]
247 // JUMP:$_end               [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
248 // $fullTrade               [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
249 // AMOUNT                   [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset valueAmount]
250 // 2                        [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset valueAmount 2]
251 // ROLL                     [... sellerKey standardProgram sellerProgram ratioDenominator requestedAsset valueAmount ratioNumerator]
252 // 3                        [... sellerKey standardProgram sellerProgram ratioDenominator requestedAsset valueAmount ratioNumerator 3]
253 // ROLL                     [... sellerKey standardProgram sellerProgram requestedAsset valueAmount ratioNumerator ratioDenominator]
254 // MULFRACTION              [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount]
255 // 999                      [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount 999]
256 // 1000                     [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount 999 1000]
257 // MULFRACTION              [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount]
258 // DUP                      [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount requestedAmount]
259 // 0                        [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount requestedAmount 0]
260 // GREATERTHANOREQUAL       [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount (requestedAmount > 0)]
261 // VERIFY                   [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount]
262 // FROMALTSTACK             [... sellerKey standardProgram sellerProgram requestedAsset requestedAmount <position>]
263 // SWAP                     [... sellerKey standardProgram sellerProgram requestedAsset <position> requestedAmount]
264 // 2                        [... sellerKey standardProgram sellerProgram requestedAsset <position> requestedAmount 2]
265 // ROLL                     [... sellerKey standardProgram sellerProgram <position> requestedAmount requestedAsset]
266 // 1                        [... sellerKey standardProgram sellerProgram <position> requestedAmount requestedAsset 1]
267 // 4                        [... sellerKey standardProgram sellerProgram <position> requestedAmount requestedAsset 1 4]
268 // ROLL                     [... sellerKey standardProgram <position> requestedAmount requestedAsset 1 sellerProgram]
269 // CHECKOUTPUT              [... sellerKey standardProgram checkOutput(requestedAmount, requestedAsset, sellerProgram)]
270 // JUMP:$_end               [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
271 // $cancel                  [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset <clause selector>]
272 // DROP                     [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
273 // 6                        [... sellerSig sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset 6]
274 // ROLL                     [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset sellerSig]
275 // 6                        [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset sellerSig 6]
276 // ROLL                     [... standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset sellerSig sellerKey]
277 // TXSIGHASH SWAP CHECKSIG  [... standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset checkTxSig(sellerKey, sellerSig)]
278 // $_end                    [... sellerKey standardProgram sellerProgram ratioDenominator ratioNumerator requestedAsset]
279 func P2MCProgram(magneticContractArgs MagneticContractArgs) ([]byte, error) {
280         standardProgram, err := P2WMCProgram(magneticContractArgs)
281         if err != nil {
282                 return nil, err
283         }
284
285         builder := NewBuilder()
286         // contract arguments
287         builder.AddData(magneticContractArgs.SellerKey)
288         builder.AddData(standardProgram)
289         builder.AddData(magneticContractArgs.SellerProgram)
290         builder.AddInt64(magneticContractArgs.RatioDenominator)
291         builder.AddInt64(magneticContractArgs.RatioNumerator)
292         builder.AddData(magneticContractArgs.RequestedAsset.Bytes())
293
294         // contract instructions
295         builder.AddOp(vm.OP_7)
296         builder.AddOp(vm.OP_ROLL)
297         builder.AddOp(vm.OP_TOALTSTACK)
298         builder.AddOp(vm.OP_6)
299         builder.AddOp(vm.OP_ROLL)
300         builder.AddOp(vm.OP_DUP)
301         builder.AddOp(vm.OP_2)
302         builder.AddOp(vm.OP_NUMEQUAL)
303         builder.AddJumpIf(0)
304         builder.AddJumpIf(1)
305         builder.AddOp(vm.OP_6)
306         builder.AddOp(vm.OP_PICK)
307         builder.AddOp(vm.OP_3)
308         builder.AddOp(vm.OP_ROLL)
309         builder.AddOp(vm.OP_3)
310         builder.AddOp(vm.OP_ROLL)
311         builder.AddOp(vm.OP_MULFRACTION)
312         builder.AddOp(vm.OP_AMOUNT)
313         builder.AddOp(vm.OP_OVER)
314         builder.AddOp(vm.OP_0)
315         builder.AddOp(vm.OP_GREATERTHANOREQUAL)
316         builder.AddOp(vm.OP_2)
317         builder.AddOp(vm.OP_PICK)
318         builder.AddOp(vm.OP_ROT)
319         builder.AddOp(vm.OP_LESSTHAN)
320         builder.AddOp(vm.OP_BOOLAND)
321         builder.AddOp(vm.OP_VERIFY)
322         builder.AddOp(vm.OP_FROMALTSTACK)
323         builder.AddOp(vm.OP_DUP)
324         builder.AddOp(vm.OP_TOALTSTACK)
325         builder.AddOp(vm.OP_6)
326         builder.AddOp(vm.OP_ROLL)
327         builder.AddInt64(999)
328         builder.AddInt64(1000)
329         builder.AddOp(vm.OP_MULFRACTION)
330         builder.AddOp(vm.OP_3)
331         builder.AddOp(vm.OP_ROLL)
332         builder.AddOp(vm.OP_1)
333         builder.AddOp(vm.OP_5)
334         builder.AddOp(vm.OP_ROLL)
335         builder.AddOp(vm.OP_CHECKOUTPUT)
336         builder.AddOp(vm.OP_VERIFY)
337         builder.AddOp(vm.OP_FROMALTSTACK)
338         builder.AddOp(vm.OP_1)
339         builder.AddOp(vm.OP_ADD)
340         builder.AddOp(vm.OP_AMOUNT)
341         builder.AddOp(vm.OP_ROT)
342         builder.AddOp(vm.OP_SUB)
343         builder.AddOp(vm.OP_ASSET)
344         builder.AddOp(vm.OP_1)
345         builder.AddOp(vm.OP_4)
346         builder.AddOp(vm.OP_ROLL)
347         builder.AddOp(vm.OP_CHECKOUTPUT)
348         builder.AddJump(2)
349         builder.SetJumpTarget(1)
350         builder.AddOp(vm.OP_AMOUNT)
351         builder.AddOp(vm.OP_ROT)
352         builder.AddOp(vm.OP_3)
353         builder.AddOp(vm.OP_ROLL)
354         builder.AddOp(vm.OP_MULFRACTION)
355         builder.AddInt64(999)
356         builder.AddInt64(1000)
357         builder.AddOp(vm.OP_MULFRACTION)
358         builder.AddOp(vm.OP_DUP)
359         builder.AddOp(vm.OP_0)
360         builder.AddOp(vm.OP_GREATERTHANOREQUAL)
361         builder.AddOp(vm.OP_VERIFY)
362         builder.AddOp(vm.OP_FROMALTSTACK)
363         builder.AddOp(vm.OP_SWAP)
364         builder.AddOp(vm.OP_ROT)
365         builder.AddOp(vm.OP_1)
366         builder.AddOp(vm.OP_4)
367         builder.AddOp(vm.OP_ROLL)
368         builder.AddOp(vm.OP_CHECKOUTPUT)
369         builder.AddJump(3)
370         builder.SetJumpTarget(0)
371         builder.AddOp(vm.OP_DROP)
372         builder.AddOp(vm.OP_6)
373         builder.AddOp(vm.OP_ROLL)
374         builder.AddOp(vm.OP_6)
375         builder.AddOp(vm.OP_ROLL)
376         builder.AddOp(vm.OP_TXSIGHASH)
377         builder.AddOp(vm.OP_SWAP)
378         builder.AddOp(vm.OP_CHECKSIG)
379         builder.SetJumpTarget(2)
380         builder.SetJumpTarget(3)
381         return builder.Build()
382 }