github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/equity/compiler/compile.go (about)

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