OSDN Git Service

add the replacement of defined variable for AST and adjusting the structural format...
[bytom/equity.git] / compiler / compile.go
1 package compiler
2
3 import (
4         "encoding/json"
5         "fmt"
6         "io"
7         "io/ioutil"
8
9         chainjson "github.com/bytom/encoding/json"
10         "github.com/bytom/errors"
11         "github.com/bytom/protocol/vm"
12         "github.com/bytom/protocol/vm/vmutil"
13 )
14
15 // Compile parses a sequence of Equity contracts from the supplied reader
16 // and produces Contract objects containing the compiled bytecode and
17 // other analysis. If argMap is non-nil, it maps contract names to
18 // lists of arguments with which to instantiate them as programs, with
19 // the results placed in the contract's Program field. A contract
20 // named in argMap but not found in the input is silently ignored.
21 func Compile(r io.Reader) ([]*Contract, error) {
22         inp, err := ioutil.ReadAll(r)
23         if err != nil {
24                 return nil, errors.Wrap(err, "reading input")
25         }
26         contracts, err := parse(inp)
27         if err != nil {
28                 return nil, errors.Wrap(err, "parse error")
29         }
30
31         globalEnv := newEnviron(nil)
32         for _, k := range keywords {
33                 globalEnv.add(k, nilType, roleKeyword)
34         }
35         for _, b := range builtins {
36                 globalEnv.add(b.name, nilType, roleBuiltin)
37         }
38
39         // All contracts must be checked for recursiveness before any are
40         // compiled.
41         for _, contract := range contracts {
42                 contract.Recursive = checkRecursive(contract)
43         }
44
45         for _, contract := range contracts {
46                 err = globalEnv.addContract(contract)
47                 if err != nil {
48                         return nil, err
49                 }
50         }
51
52         for _, contract := range contracts {
53                 err = compileContract(contract, globalEnv)
54                 if err != nil {
55                         return nil, errors.Wrap(err, "compiling contract")
56                 }
57         }
58
59         return contracts, nil
60 }
61
62 func Instantiate(body []byte, params []*Param, recursive bool, args []ContractArg) ([]byte, error) {
63         if len(args) != len(params) {
64                 return nil, fmt.Errorf("got %d argument(s), want %d", len(args), len(params))
65         }
66
67         // typecheck args against param types
68         for i, param := range params {
69                 arg := args[i]
70                 switch param.Type {
71                 case amountType, intType:
72                         if arg.I == nil {
73                                 return nil, fmt.Errorf("type mismatch in arg %d (want integer)", i)
74                         }
75                 case assetType, hashType, progType, pubkeyType, sigType, signType, strType:
76                         if arg.S == nil {
77                                 return nil, fmt.Errorf("type mismatch in arg %d (want string)", i)
78                         }
79                 case boolType:
80                         if arg.B == nil {
81                                 return nil, fmt.Errorf("type mismatch in arg %d (want boolean)", i)
82                         }
83                 }
84         }
85
86         b := vmutil.NewBuilder()
87
88         for i := len(args) - 1; i >= 0; i-- {
89                 a := args[i]
90                 switch {
91                 case a.B != nil:
92                         var n int64
93                         if *a.B {
94                                 n = 1
95                         }
96                         b.AddInt64(n)
97                 case a.I != nil:
98                         b.AddInt64(*a.I)
99                 case a.S != nil:
100                         b.AddData(*a.S)
101                 }
102         }
103
104         if recursive {
105                 // <argN> <argN-1> ... <arg1> <body> DEPTH OVER 0 CHECKPREDICATE
106                 b.AddData(body)
107                 b.AddOp(vm.OP_DEPTH).AddOp(vm.OP_OVER)
108         } else {
109                 // <argN> <argN-1> ... <arg1> DEPTH <body> 0 CHECKPREDICATE
110                 b.AddOp(vm.OP_DEPTH)
111                 b.AddData(body)
112         }
113         b.AddInt64(0)
114         b.AddOp(vm.OP_CHECKPREDICATE)
115         return b.Build()
116 }
117
118 func compileContract(contract *Contract, globalEnv *environ) error {
119         var err error
120
121         if len(contract.Clauses) == 0 {
122                 return fmt.Errorf("empty contract")
123         }
124         env := newEnviron(globalEnv)
125         for _, p := range contract.Params {
126                 err = env.add(p.Name, p.Type, roleContractParam)
127                 if err != nil {
128                         return err
129                 }
130         }
131
132         // value is spilt with valueAmount and valueAsset
133         if err = env.add(contract.Value.Amount, amountType, roleContractValue); err != nil {
134                 return err
135         }
136         if err = env.add(contract.Value.Asset, assetType, roleContractValue); err != nil {
137                 return err
138         }
139
140         for _, c := range contract.Clauses {
141                 err = env.add(c.Name, nilType, roleClause)
142                 if err != nil {
143                         return err
144                 }
145         }
146
147         err = prohibitSigParams(contract)
148         if err != nil {
149                 return err
150         }
151         err = requireAllParamsUsedInClauses(contract.Params, contract.Clauses)
152         if err != nil {
153                 return err
154         }
155
156         var stk stack
157
158         if len(contract.Clauses) > 1 {
159                 stk = stk.add("<clause selector>")
160         }
161
162         for i := len(contract.Params) - 1; i >= 0; i-- {
163                 p := contract.Params[i]
164                 stk = stk.add(p.Name)
165         }
166
167         if contract.Recursive {
168                 stk = stk.add(contract.Name)
169         }
170
171         b := &builder{}
172         sequence := 0 // sequence is used to count the number of ifStatements
173
174         if len(contract.Clauses) == 1 {
175                 err = compileClause(b, stk, contract, env, contract.Clauses[0], &sequence)
176                 if err != nil {
177                         return err
178                 }
179         } else {
180                 if len(contract.Params) > 0 {
181                         // A clause selector is at the bottom of the stack. Roll it to the
182                         // top.
183                         n := len(contract.Params)
184                         if contract.Recursive {
185                                 n++
186                         }
187                         stk = b.addRoll(stk, n) // stack: [<clause params> <contract params> [<maybe contract body>] <clause selector>]
188                 }
189
190                 var stk2 stack
191
192                 // clauses 2..N-1
193                 for i := len(contract.Clauses) - 1; i >= 2; i-- {
194                         stk = b.addDup(stk)                                                   // stack: [... <clause selector> <clause selector>]
195                         stk = b.addInt64(stk, int64(i))                                       // stack: [... <clause selector> <clause selector> <i>]
196                         stk = b.addNumEqual(stk, fmt.Sprintf("(<clause selector> == %d)", i)) // stack: [... <clause selector> <i == clause selector>]
197                         stk = b.addJumpIf(stk, contract.Clauses[i].Name)                      // stack: [... <clause selector>]
198                         stk2 = stk                                                            // stack starts here for clauses 2 through N-1
199                 }
200
201                 // clause 1
202                 stk = b.addJumpIf(stk, contract.Clauses[1].Name) // consumes the clause selector
203
204                 // no jump needed for clause 0
205
206                 for i, clause := range contract.Clauses {
207                         if i > 1 {
208                                 // Clauses 0 and 1 have no clause selector on top of the
209                                 // stack. Clauses 2 and later do.
210                                 stk = stk2
211                         }
212
213                         b.addJumpTarget(stk, clause.Name)
214
215                         if i > 1 {
216                                 stk = b.addDrop(stk)
217                         }
218
219                         err = compileClause(b, stk, contract, env, clause, &sequence)
220                         if err != nil {
221                                 return errors.Wrapf(err, "compiling clause \"%s\"", clause.Name)
222                         }
223                         b.forgetPendingVerify()
224                         if i < len(contract.Clauses)-1 {
225                                 b.addJump(stk, "_end")
226                         }
227                 }
228                 b.addJumpTarget(stk, "_end")
229         }
230
231         opcodes := optimize(b.opcodes())
232         prog, err := vm.Assemble(opcodes)
233         if err != nil {
234                 return err
235         }
236
237         contract.Body = prog
238         contract.Opcodes = opcodes
239
240         contract.Steps = b.steps()
241
242         return nil
243 }
244
245 func compileClause(b *builder, contractStk stack, contract *Contract, env *environ, clause *Clause, sequence *int) error {
246         var err error
247
248         // copy env to leave outerEnv unchanged
249         env = newEnviron(env)
250         for _, p := range clause.Params {
251                 err = env.add(p.Name, p.Type, roleClauseParam)
252                 if err != nil {
253                         return err
254                 }
255         }
256
257         if err = assignIndexes(clause); err != nil {
258                 return err
259         }
260
261         var stk stack
262         for _, p := range clause.Params {
263                 // NOTE: the order of clause params is not reversed, unlike
264                 // contract params (and also unlike the arguments to Equity
265                 // function-calls).
266                 stk = stk.add(p.Name)
267         }
268         stk = stk.addFromStack(contractStk)
269
270         // a count of the number of times each variable is referenced
271         counts := make(map[string]int)
272         for _, stat := range clause.statements {
273                 counts = countsVarRef(stat, counts)
274         }
275
276         for _, stat := range clause.statements {
277                 if stk, err = compileStatement(b, stk, contract, env, clause, counts, stat, sequence); err != nil {
278                         return err
279                 }
280         }
281
282         var condValues []CondValueInfo
283         tempVariables := map[string]ExpressionInfo{}
284         for _, stmt := range clause.statements {
285                 valueInfo := calClauseValues(contract, env, stmt, &condValues, tempVariables)
286                 if valueInfo != nil {
287                         clause.Values = append(clause.Values, *valueInfo)
288                 } else {
289                         clause.CondValues = condValues
290                 }
291         }
292
293         err = typeCheckClause(contract, clause, env)
294         if err != nil {
295                 return err
296         }
297         err = requireAllParamsUsedInClause(clause.Params, clause)
298         if err != nil {
299                 return err
300         }
301
302         return nil
303 }
304
305 func compileStatement(b *builder, stk stack, contract *Contract, env *environ, clause *Clause, counts map[string]int, stat statement, sequence *int) (stack, error) {
306         var err error
307         switch stmt := stat.(type) {
308         case *ifStatement:
309                 // sequence add 1 when the statement is ifStatement
310                 *sequence++
311                 strSequence := fmt.Sprintf("%d", *sequence)
312
313                 // compile the contract valueAmount and valueAsset for expression
314                 stk, counts = compileContractValue(b, stmt.condition, contract.Value, stk, counts)
315
316                 // compile condition expression
317                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.condition)
318                 if err != nil {
319                         return stk, errors.Wrapf(err, "in check condition of ifStatement in clause \"%s\"", clause.Name)
320                 }
321
322                 // jump to falseBody when condition is false, while the JUMPIF instruction will be run success when
323                 // the value of dataStack is true, therefore add this negation
324                 conditionExpr := stk.str
325                 stk = b.addNot(stk, fmt.Sprintf("!%s", conditionExpr))
326
327                 // add nop instruction to differ with clause selector for JUMPIF instruction
328                 stk = b.addNop(stk)
329
330                 // add label
331                 var label string
332                 if len(stmt.body.falseBody) != 0 {
333                         label = "else_" + strSequence
334                 } else {
335                         label = "endif_" + strSequence
336                 }
337                 stk = b.addJumpIf(stk, label)
338                 b.addJumpTarget(stk, "if_"+strSequence)
339
340                 // temporary store stack and counts for falseBody
341                 condStk := stk
342                 elseCounts := make(map[string]int)
343                 for k, v := range counts {
344                         elseCounts[k] = v
345                 }
346
347                 // compile trueBody statements
348                 if len(stmt.body.trueBody) != 0 {
349                         for _, st := range stmt.body.trueBody {
350                                 st.countVarRefs(counts)
351                         }
352
353                         for _, st := range stmt.body.trueBody {
354                                 if stk, err = compileStatement(b, stk, contract, env, clause, counts, st, sequence); err != nil {
355                                         return stk, err
356                                 }
357                         }
358                 }
359
360                 // compile falseBody statements
361                 if len(stmt.body.falseBody) != 0 {
362                         counts := make(map[string]int)
363                         for k, v := range elseCounts {
364                                 counts[k] = v
365                         }
366
367                         for _, st := range stmt.body.falseBody {
368                                 st.countVarRefs(counts)
369                         }
370
371                         stk = condStk
372                         b.addJump(stk, "endif_"+strSequence)
373                         b.addJumpTarget(stk, "else_"+strSequence)
374
375                         for _, st := range stmt.body.falseBody {
376                                 if stk, err = compileStatement(b, stk, contract, env, clause, counts, st, sequence); err != nil {
377                                         return stk, err
378                                 }
379                         }
380                 }
381                 b.addJumpTarget(stk, "endif_"+strSequence)
382
383         case *defineStatement:
384                 // add environ for define variable
385                 if err = env.add(stmt.variable.Name, stmt.variable.Type, roleClauseVariable); err != nil {
386                         return stk, err
387                 }
388
389                 // check whether the variable is used or not
390                 if counts[stmt.variable.Name] == 0 {
391                         return stk, fmt.Errorf("the defined variable \"%s\" is unused in clause \"%s\"", stmt.variable.Name, clause.Name)
392                 }
393
394                 if stmt.expr != nil {
395                         // compile the contract valueAmount and valueAsset for expression
396                         stk, counts = compileContractValue(b, stmt.expr, contract.Value, stk, counts)
397
398                         // variable
399                         stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.expr)
400                         if err != nil {
401                                 return stk, errors.Wrapf(err, "in define statement in clause \"%s\"", clause.Name)
402                         }
403
404                         // modify stack name
405                         stk.str = stmt.variable.Name
406                 }
407
408         case *assignStatement:
409                 // find variable from environ with roleClauseVariable
410                 if entry := env.lookup(string(stmt.variable.Name)); entry != nil {
411                         if entry.r != roleClauseVariable {
412                                 return stk, fmt.Errorf("the type of variable is not roleClauseVariable in assign statement in clause \"%s\"", clause.Name)
413                         }
414                         stmt.variable.Type = entry.t
415                 } else {
416                         return stk, fmt.Errorf("the variable \"%s\" is not defined before the assign statement in clause \"%s\"", stmt.variable.Name, clause.Name)
417                 }
418
419                 // temporary store the counts of defined variable
420                 varCount := counts[stmt.variable.Name]
421
422                 // calculate the counts of variable for assign statement
423                 tmpCounts := make(map[string]int)
424                 stmt.countVarRefs(tmpCounts)
425
426                 // modify the map counts of defined variable to 1 and minus the number of defined variable
427                 // when the assign expression contains the defined variable
428                 if tmpCounts[stmt.variable.Name] > 0 {
429                         counts[stmt.variable.Name] = 1
430                         varCount -= tmpCounts[stmt.variable.Name]
431                 } else {
432                         depth := stk.find(stmt.variable.Name)
433                         switch depth {
434                         case 0:
435                                 break
436                         case 1:
437                                 stk = b.addSwap(stk)
438                         default:
439                                 stk = b.addRoll(stk, depth)
440                         }
441                         stk = b.addDrop(stk)
442                 }
443
444                 // compile the contract valueAmount and valueAsset for expression
445                 stk, counts = compileContractValue(b, stmt.expr, contract.Value, stk, counts)
446
447                 // variable
448                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.expr)
449                 if err != nil {
450                         return stk, errors.Wrapf(err, "in define statement in clause \"%s\"", clause.Name)
451                 }
452
453                 // restore the defined variable counts
454                 if tmpCounts[stmt.variable.Name] > 0 {
455                         counts[stmt.variable.Name] = varCount
456                 }
457
458                 // modify stack name
459                 stk.str = stmt.variable.Name
460
461         case *verifyStatement:
462                 // compile the contract valueAmount and valueAsset for expression
463                 stk, counts = compileContractValue(b, stmt.expr, contract.Value, stk, counts)
464
465                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.expr)
466                 if err != nil {
467                         return stk, errors.Wrapf(err, "in verify statement in clause \"%s\"", clause.Name)
468                 }
469                 stk = b.addVerify(stk)
470
471                 // special-case reporting of certain function calls
472                 if c, ok := stmt.expr.(*callExpr); ok && len(c.args) == 1 {
473                         if b := referencedBuiltin(c.fn); b != nil {
474                                 switch b.name {
475                                 case "below":
476                                         clause.BlockHeight = append(clause.BlockHeight, c.args[0].String())
477                                 case "above":
478                                         clause.BlockHeight = append(clause.BlockHeight, c.args[0].String())
479                                 }
480                         }
481                 }
482
483         case *lockStatement:
484                 // index
485                 stk = b.addInt64(stk, stmt.index)
486
487                 // TODO: permit more complex expressions for locked,
488                 // like "lock x+y with foo" (?)
489
490                 if stmt.lockedAmount.String() == contract.Value.Amount && stmt.lockedAsset.String() == contract.Value.Asset {
491                         stk = b.addAmount(stk, contract.Value.Amount)
492                         stk = b.addAsset(stk, contract.Value.Asset)
493                 } else {
494                         // calculate the counts of variable for lockStatement
495                         lockCounts := make(map[string]int)
496                         stmt.countVarRefs(lockCounts)
497
498                         // amount
499                         switch {
500                         case stmt.lockedAmount.String() == contract.Value.Amount:
501                                 stk = b.addAmount(stk, contract.Value.Amount)
502                         case stmt.lockedAmount.String() != contract.Value.Amount && lockCounts[contract.Value.Amount] > 0:
503                                 counts[contract.Value.Amount] = lockCounts[contract.Value.Amount]
504                                 stk = b.addAmount(stk, contract.Value.Amount)
505                                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAmount)
506                                 if err != nil {
507                                         return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
508                                 }
509                         default:
510                                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAmount)
511                                 if err != nil {
512                                         return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
513                                 }
514                         }
515
516                         // asset
517                         switch {
518                         case stmt.lockedAsset.String() == contract.Value.Asset:
519                                 stk = b.addAsset(stk, contract.Value.Asset)
520                         case stmt.lockedAsset.String() != contract.Value.Asset && lockCounts[contract.Value.Asset] > 0:
521                                 counts[contract.Value.Asset] = lockCounts[contract.Value.Asset]
522                                 stk = b.addAsset(stk, contract.Value.Asset)
523                                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAsset)
524                                 if err != nil {
525                                         return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
526                                 }
527                         default:
528                                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.lockedAsset)
529                                 if err != nil {
530                                         return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
531                                 }
532                         }
533                 }
534
535                 // version
536                 stk = b.addInt64(stk, 1)
537
538                 // prog
539                 stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.program)
540                 if err != nil {
541                         return stk, errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
542                 }
543
544                 stk = b.addCheckOutput(stk, fmt.Sprintf("checkOutput(%s, %s, %s)",
545                         stmt.lockedAmount.String(), stmt.lockedAsset.String(), stmt.program))
546                 stk = b.addVerify(stk)
547
548         case *unlockStatement:
549                 if len(clause.statements) == 1 {
550                         // This is the only statement in the clause, make sure TRUE is
551                         // on the stack.
552                         stk = b.addBoolean(stk, true)
553                 }
554         }
555
556         return stk, nil
557 }
558
559 func compileExpr(b *builder, stk stack, contract *Contract, clause *Clause, env *environ, counts map[string]int, expr expression) (stack, error) {
560         var err error
561
562         switch e := expr.(type) {
563         case *binaryExpr:
564                 // Do typechecking after compiling subexpressions (because other
565                 // compilation errors are more interesting than type mismatch
566                 // errors).
567
568                 stk, err = compileExpr(b, stk, contract, clause, env, counts, e.left)
569                 if err != nil {
570                         return stk, errors.Wrapf(err, "in left operand of \"%s\" expression", e.op.op)
571                 }
572                 stk, err = compileExpr(b, stk, contract, clause, env, counts, e.right)
573                 if err != nil {
574                         return stk, errors.Wrapf(err, "in right operand of \"%s\" expression", e.op.op)
575                 }
576
577                 lType := e.left.typ(env)
578                 if e.op.left != "" && ((e.op.left == intType && !(lType == amountType || lType == intType)) ||
579                         (e.op.left == boolType && !(lType == boolType))) {
580                         return stk, fmt.Errorf("in \"%s\", left operand has type \"%s\", must be \"%s\"", e, lType, e.op.left)
581                 }
582
583                 rType := e.right.typ(env)
584                 if e.op.right != "" && ((e.op.right == intType && !(rType == amountType || rType == intType)) ||
585                         (e.op.right == boolType && !(rType == boolType))) {
586                         return stk, fmt.Errorf("in \"%s\", right operand has type \"%s\", must be \"%s\"", e, rType, e.op.right)
587                 }
588
589                 switch e.op.op {
590                 case "==", "!=":
591                         if lType != rType {
592                                 // Maybe one is Hash and the other is (more-specific-Hash subtype).
593                                 // TODO(bobg): generalize this mechanism
594                                 if lType == hashType && isHashSubtype(rType) {
595                                         propagateType(contract, clause, env, rType, e.left)
596                                 } else if rType == hashType && isHashSubtype(lType) {
597                                         propagateType(contract, clause, env, lType, e.right)
598                                 } else {
599                                         return stk, fmt.Errorf("type mismatch in \"%s\": left operand has type \"%s\", right operand has type \"%s\"", e, lType, rType)
600                                 }
601                         }
602                         if lType == "Boolean" {
603                                 return stk, fmt.Errorf("in \"%s\": using \"%s\" on Boolean values not allowed", e, e.op.op)
604                         }
605                 }
606
607                 stk = b.addOps(stk.dropN(2), e.op.opcodes, e.String())
608
609         case *unaryExpr:
610                 // Do typechecking after compiling subexpression (because other
611                 // compilation errors are more interesting than type mismatch
612                 // errors).
613
614                 var err error
615                 stk, err = compileExpr(b, stk, contract, clause, env, counts, e.expr)
616                 if err != nil {
617                         return stk, errors.Wrapf(err, "in \"%s\" expression", e.op.op)
618                 }
619
620                 if e.op.operand != "" && e.expr.typ(env) != e.op.operand {
621                         return stk, fmt.Errorf("in \"%s\", operand has type \"%s\", must be \"%s\"", e, e.expr.typ(env), e.op.operand)
622                 }
623                 b.addOps(stk.drop(), e.op.opcodes, e.String())
624
625         case *callExpr:
626                 bi := referencedBuiltin(e.fn)
627                 if bi == nil {
628                         if v, ok := e.fn.(varRef); ok {
629                                 if entry := env.lookup(string(v)); entry != nil && entry.t == contractType {
630                                         clause.Contracts = append(clause.Contracts, entry.c.Name)
631
632                                         partialName := fmt.Sprintf("%s(...)", v)
633                                         stk = b.addData(stk, nil)
634
635                                         if len(e.args) != len(entry.c.Params) {
636                                                 return stk, fmt.Errorf("contract \"%s\" expects %d argument(s), got %d", entry.c.Name, len(entry.c.Params), len(e.args))
637                                         }
638
639                                         for i := len(e.args) - 1; i >= 0; i-- {
640                                                 arg := e.args[i]
641                                                 if entry.c.Params[i].Type != "" && arg.typ(env) != entry.c.Params[i].Type &&
642                                                         !(arg.typ(env) == intType && entry.c.Params[i].Type == amountType) {
643                                                         return stk, fmt.Errorf("argument %d to contract \"%s\" has type \"%s\", must be \"%s\"", i, entry.c.Name, arg.typ(env), entry.c.Params[i].Type)
644                                                 }
645                                                 stk, err = compileExpr(b, stk, contract, clause, env, counts, arg)
646                                                 if err != nil {
647                                                         return stk, err
648                                                 }
649                                                 stk = b.addCatPushdata(stk, partialName)
650                                         }
651
652                                         switch {
653                                         case entry.c == contract:
654                                                 // Recursive call - cannot use entry.c.Body
655                                                 // <argN> <argN-1> ... <arg1> <body> DEPTH OVER 0 CHECKPREDICATE
656                                                 stk, err = compileRef(b, stk, counts, varRef(contract.Name))
657                                                 if err != nil {
658                                                         return stk, errors.Wrap(err, "compiling contract call")
659                                                 }
660                                                 stk = b.addCatPushdata(stk, partialName)
661                                                 stk = b.addData(stk, []byte{byte(vm.OP_DEPTH), byte(vm.OP_OVER)})
662                                                 stk = b.addCat(stk, partialName)
663
664                                         case entry.c.Recursive:
665                                                 // Non-recursive call to a (different) recursive contract
666                                                 // <argN> <argN-1> ... <arg1> <body> DEPTH OVER 0 CHECKPREDICATE
667                                                 if len(entry.c.Body) == 0 {
668                                                         // TODO(bobg): sort input contracts topologically to permit forward calling
669                                                         return stk, fmt.Errorf("contract \"%s\" not defined", entry.c.Name)
670                                                 }
671                                                 stk = b.addData(stk, entry.c.Body)
672                                                 stk = b.addCatPushdata(stk, partialName)
673                                                 stk = b.addData(stk, []byte{byte(vm.OP_DEPTH), byte(vm.OP_OVER)})
674                                                 stk = b.addCat(stk, partialName)
675
676                                         default:
677                                                 // Non-recursive call to non-recursive contract
678                                                 // <argN> <argN-1> ... <arg1> DEPTH <body> 0 CHECKPREDICATE
679                                                 stk = b.addData(stk, []byte{byte(vm.OP_DEPTH)})
680                                                 stk = b.addCat(stk, partialName)
681                                                 if len(entry.c.Body) == 0 {
682                                                         // TODO(bobg): sort input contracts topologically to permit forward calling
683                                                         return stk, fmt.Errorf("contract \"%s\" not defined", entry.c.Name)
684                                                 }
685                                                 stk = b.addData(stk, entry.c.Body)
686                                                 stk = b.addCatPushdata(stk, partialName)
687                                         }
688                                         stk = b.addData(stk, vm.Int64Bytes(0))
689                                         stk = b.addCatPushdata(stk, partialName)
690                                         stk = b.addData(stk, []byte{byte(vm.OP_CHECKPREDICATE)})
691                                         stk = b.addCat(stk, e.String())
692
693                                         return stk, nil
694                                 }
695                         }
696                         return stk, fmt.Errorf("unknown function \"%s\"", e.fn)
697                 }
698
699                 if len(e.args) != len(bi.args) {
700                         return stk, fmt.Errorf("wrong number of args for \"%s\": have %d, want %d", bi.name, len(e.args), len(bi.args))
701                 }
702
703                 // WARNING WARNING WOOP WOOP
704                 // special-case hack
705                 // WARNING WARNING WOOP WOOP
706                 if bi.name == "checkTxMultiSig" {
707                         if _, ok := e.args[0].(listExpr); !ok {
708                                 return stk, fmt.Errorf("checkTxMultiSig expects list literals, got %T for argument 0", e.args[0])
709                         }
710                         if _, ok := e.args[1].(listExpr); !ok {
711                                 return stk, fmt.Errorf("checkTxMultiSig expects list literals, got %T for argument 1", e.args[1])
712                         }
713
714                         var k1, k2 int
715
716                         stk, k1, err = compileArg(b, stk, contract, clause, env, counts, e.args[1])
717                         if err != nil {
718                                 return stk, err
719                         }
720
721                         // stack: [... sigM ... sig1 M]
722
723                         var altEntry string
724                         stk, altEntry = b.addToAltStack(stk) // stack: [... sigM ... sig1]
725                         stk = b.addTxSigHash(stk)            // stack: [... sigM ... sig1 txsighash]
726
727                         stk, k2, err = compileArg(b, stk, contract, clause, env, counts, e.args[0])
728                         if err != nil {
729                                 return stk, err
730                         }
731
732                         // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 N]
733
734                         stk = b.addFromAltStack(stk, altEntry) // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 N M]
735                         stk = b.addSwap(stk)                   // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 M N]
736                         stk = b.addCheckMultisig(stk, k1+k2, e.String())
737
738                         return stk, nil
739                 }
740
741                 var k int
742
743                 for i := len(e.args) - 1; i >= 0; i-- {
744                         a := e.args[i]
745                         var k2 int
746                         var err error
747                         stk, k2, err = compileArg(b, stk, contract, clause, env, counts, a)
748                         if err != nil {
749                                 return stk, errors.Wrapf(err, "compiling argument %d in call expression", i)
750                         }
751                         k += k2
752                 }
753
754                 // Do typechecking after compiling subexpressions (because other
755                 // compilation errors are more interesting than type mismatch
756                 // errors).
757                 for i, actual := range e.args {
758                         if bi.args[i] != "" && actual.typ(env) != bi.args[i] {
759                                 return stk, fmt.Errorf("argument %d to \"%s\" has type \"%s\", must be \"%s\"", i, bi.name, actual.typ(env), bi.args[i])
760                         }
761                 }
762
763                 stk = b.addOps(stk.dropN(k), bi.opcodes, e.String())
764
765                 // special-case reporting
766                 switch bi.name {
767                 case "sha3", "sha256":
768                         clause.HashCalls = append(clause.HashCalls, HashCall{bi.name, e.args[0].String(), string(e.args[0].typ(env))})
769                 }
770
771         case varRef:
772                 return compileRef(b, stk, counts, e)
773
774         case integerLiteral:
775                 stk = b.addInt64(stk, int64(e))
776
777         case bytesLiteral:
778                 stk = b.addData(stk, []byte(e))
779
780         case booleanLiteral:
781                 stk = b.addBoolean(stk, bool(e))
782
783         case listExpr:
784                 // Lists are excluded here because they disobey the invariant of
785                 // this function: namely, that it increases the stack size by
786                 // exactly one. (A list pushes its items and its length on the
787                 // stack.) But they're OK as function-call arguments because the
788                 // function (presumably) consumes all the stack items added.
789                 return stk, fmt.Errorf("encountered list outside of function-call context")
790         }
791         return stk, nil
792 }
793
794 func compileArg(b *builder, stk stack, contract *Contract, clause *Clause, env *environ, counts map[string]int, expr expression) (stack, int, error) {
795         var n int
796         if list, ok := expr.(listExpr); ok {
797                 for i := 0; i < len(list); i++ {
798                         elt := list[len(list)-i-1]
799                         var err error
800                         stk, err = compileExpr(b, stk, contract, clause, env, counts, elt)
801                         if err != nil {
802                                 return stk, 0, err
803                         }
804                         n++
805                 }
806                 stk = b.addInt64(stk, int64(len(list)))
807                 n++
808                 return stk, n, nil
809         }
810         var err error
811         stk, err = compileExpr(b, stk, contract, clause, env, counts, expr)
812         return stk, 1, err
813 }
814
815 func compileContractValue(b *builder, expr expression, contractValue ValueInfo, stk stack, counts map[string]int) (stack, map[string]int) {
816         valueCounts := make(map[string]int)
817         expr.countVarRefs(valueCounts)
818         if valueCounts[contractValue.Amount] > 0 {
819                 counts[contractValue.Amount] = valueCounts[contractValue.Amount]
820                 stk = b.addAmount(stk, contractValue.Amount)
821         }
822
823         if valueCounts[contractValue.Asset] > 0 {
824                 counts[contractValue.Asset] = valueCounts[contractValue.Asset]
825                 stk = b.addAsset(stk, contractValue.Asset)
826         }
827
828         return stk, counts
829 }
830
831 func compileRef(b *builder, stk stack, counts map[string]int, ref varRef) (stack, error) {
832         depth := stk.find(string(ref))
833         if depth < 0 {
834                 return stk, fmt.Errorf("undefined reference: \"%s\"", ref)
835         }
836
837         var isFinal bool
838         if count, ok := counts[string(ref)]; ok && count > 0 {
839                 count--
840                 counts[string(ref)] = count
841                 isFinal = count == 0
842         }
843
844         switch depth {
845         case 0:
846                 if !isFinal {
847                         stk = b.addDup(stk)
848                 }
849         case 1:
850                 if isFinal {
851                         stk = b.addSwap(stk)
852                 } else {
853                         stk = b.addOver(stk)
854                 }
855         default:
856                 if isFinal {
857                         stk = b.addRoll(stk, depth)
858                 } else {
859                         stk = b.addPick(stk, depth)
860                 }
861         }
862         return stk, nil
863 }
864
865 func (a *ContractArg) UnmarshalJSON(b []byte) error {
866         var m map[string]json.RawMessage
867         err := json.Unmarshal(b, &m)
868         if err != nil {
869                 return err
870         }
871         if r, ok := m["boolean"]; ok {
872                 var bval bool
873                 err = json.Unmarshal(r, &bval)
874                 if err != nil {
875                         return err
876                 }
877                 a.B = &bval
878                 return nil
879         }
880         if r, ok := m["integer"]; ok {
881                 var ival int64
882                 err = json.Unmarshal(r, &ival)
883                 if err != nil {
884                         return err
885                 }
886                 a.I = &ival
887                 return nil
888         }
889         r, ok := m["string"]
890         if !ok {
891                 return fmt.Errorf("contract arg must define one of boolean, integer, string")
892         }
893         var sval chainjson.HexBytes
894         err = json.Unmarshal(r, &sval)
895         if err != nil {
896                 return err
897         }
898         a.S = &sval
899         return nil
900 }