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

     1  package compiler
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  )
     8  
     9  type builder struct {
    10  	items         []*builderItem
    11  	pendingVerify *builderItem
    12  }
    13  
    14  type builderItem struct {
    15  	opcodes string
    16  	stk     stack
    17  }
    18  
    19  func (b *builder) add(opcodes string, newstack stack) stack {
    20  	if b.pendingVerify != nil {
    21  		b.items = append(b.items, b.pendingVerify)
    22  		b.pendingVerify = nil
    23  	}
    24  	item := &builderItem{opcodes: opcodes, stk: newstack}
    25  	if opcodes == "VERIFY" {
    26  		b.pendingVerify = item
    27  	} else {
    28  		b.items = append(b.items, item)
    29  	}
    30  	return newstack
    31  }
    32  
    33  func (b *builder) addRoll(stk stack, n int) stack {
    34  	b.addInt64(stk, int64(n))
    35  	return b.add("ROLL", stk.roll(n))
    36  }
    37  
    38  func (b *builder) addDup(stk stack) stack {
    39  	return b.add("DUP", stk.dup())
    40  }
    41  
    42  func (b *builder) addInt64(stk stack, n int64) stack {
    43  	s := strconv.FormatInt(n, 10)
    44  	return b.add(s, stk.add(s))
    45  }
    46  
    47  func (b *builder) addNot(stk stack, desc string) stack {
    48  	return b.add("NOT", stk.drop().add(desc))
    49  }
    50  
    51  func (b *builder) addEqual(stk stack, desc string) stack {
    52  	return b.add("EQUAL", stk.dropN(2).add(desc))
    53  }
    54  
    55  func (b *builder) addNumEqual(stk stack, desc string) stack {
    56  	return b.add("NUMEQUAL", stk.dropN(2).add(desc))
    57  }
    58  
    59  func (b *builder) addJumpIf(stk stack, label string) stack {
    60  	return b.add(fmt.Sprintf("JUMPIF:$%s", label), stk.drop())
    61  }
    62  
    63  func (b *builder) addJumpTarget(stk stack, label string) stack {
    64  	return b.add("$"+label, stk)
    65  }
    66  
    67  func (b *builder) addDrop(stk stack) stack {
    68  	return b.add("DROP", stk.drop())
    69  }
    70  
    71  func (b *builder) forgetPendingVerify() {
    72  	b.pendingVerify = nil
    73  }
    74  
    75  func (b *builder) addJump(stk stack, label string) stack {
    76  	return b.add(fmt.Sprintf("JUMP:$%s", label), stk)
    77  }
    78  
    79  func (b *builder) addVerify(stk stack) stack {
    80  	return b.add("VERIFY", stk.drop())
    81  }
    82  
    83  func (b *builder) addData(stk stack, data []byte) stack {
    84  	var s string
    85  	switch len(data) {
    86  	case 0:
    87  		s = "0"
    88  	case 1:
    89  		s = strconv.FormatInt(int64(data[0]), 10)
    90  	default:
    91  		s = fmt.Sprintf("0x%x", data)
    92  	}
    93  	return b.add(s, stk.add(s))
    94  }
    95  
    96  func (b *builder) addAmount(stk stack, desc string) stack {
    97  	return b.add("AMOUNT", stk.add(desc))
    98  }
    99  
   100  func (b *builder) addAsset(stk stack, desc string) stack {
   101  	return b.add("ASSET", stk.add(desc))
   102  }
   103  
   104  func (b *builder) addCheckOutput(stk stack, desc string) stack {
   105  	return b.add("CHECKOUTPUT", stk.dropN(5).add(desc))
   106  }
   107  
   108  func (b *builder) addBoolean(stk stack, val bool) stack {
   109  	if val {
   110  		return b.add("TRUE", stk.add("true"))
   111  	}
   112  	return b.add("FALSE", stk.add("false"))
   113  }
   114  
   115  func (b *builder) addOps(stk stack, ops string, desc string) stack {
   116  	return b.add(ops, stk.add(desc))
   117  }
   118  
   119  func (b *builder) addToAltStack(stk stack) (stack, string) {
   120  	t := stk.top()
   121  	return b.add("TOALTSTACK", stk.drop()), t
   122  }
   123  
   124  func (b *builder) addTxSigHash(stk stack) stack {
   125  	return b.add("TXSIGHASH", stk.add("<txsighash>"))
   126  }
   127  
   128  func (b *builder) addFromAltStack(stk stack, alt string) stack {
   129  	return b.add("FROMALTSTACK", stk.add(alt))
   130  }
   131  
   132  func (b *builder) addSwap(stk stack) stack {
   133  	return b.add("SWAP", stk.swap())
   134  }
   135  
   136  func (b *builder) addCheckMultisig(stk stack, n int, desc string) stack {
   137  	return b.add("CHECKMULTISIG", stk.dropN(n).add(desc))
   138  }
   139  
   140  func (b *builder) addOver(stk stack) stack {
   141  	return b.add("OVER", stk.over())
   142  }
   143  
   144  func (b *builder) addPick(stk stack, n int) stack {
   145  	b.addInt64(stk, int64(n))
   146  	return b.add("PICK", stk.pick(n))
   147  }
   148  
   149  func (b *builder) addCatPushdata(stk stack, desc string) stack {
   150  	return b.add("CATPUSHDATA", stk.dropN(2).add(desc))
   151  }
   152  
   153  func (b *builder) addCat(stk stack, desc string) stack {
   154  	return b.add("CAT", stk.dropN(2).add(desc))
   155  }
   156  
   157  func (b *builder) addNop(stk stack) stack {
   158  	return b.add("NOP", stk)
   159  }
   160  
   161  func (b *builder) opcodes() string {
   162  	var ops []string
   163  	for _, item := range b.items {
   164  		ops = append(ops, item.opcodes)
   165  	}
   166  	return strings.Join(ops, " ")
   167  }
   168  
   169  // This is for producing listings like:
   170  // 5                 |  [... <clause selector> borrower lender deadline balanceAmount balanceAsset 5]
   171  // ROLL              |  [... borrower lender deadline balanceAmount balanceAsset <clause selector>]
   172  // JUMPIF:$default   |  [... borrower lender deadline balanceAmount balanceAsset]
   173  // $repay            |  [... borrower lender deadline balanceAmount balanceAsset]
   174  // 0                 |  [... borrower lender deadline balanceAmount balanceAsset 0]
   175  // 0                 |  [... borrower lender deadline balanceAmount balanceAsset 0 0]
   176  // 3                 |  [... borrower lender deadline balanceAmount balanceAsset 0 0 3]
   177  // ROLL              |  [... borrower lender deadline balanceAsset 0 0 balanceAmount]
   178  // 3                 |  [... borrower lender deadline balanceAsset 0 0 balanceAmount 3]
   179  // ROLL              |  [... borrower lender deadline 0 0 balanceAmount balanceAsset]
   180  // 1                 |  [... borrower lender deadline 0 0 balanceAmount balanceAsset 1]
   181  // 6                 |  [... borrower lender deadline 0 0 balanceAmount balanceAsset 1 6]
   182  // ROLL              |  [... borrower deadline 0 0 balanceAmount balanceAsset 1 lender]
   183  // CHECKOUTPUT       |  [... borrower deadline checkOutput(payment, lender)]
   184  // VERIFY            |  [... borrower deadline]
   185  // 1                 |  [... borrower deadline 1]
   186  // 0                 |  [... borrower deadline 1 0]
   187  // AMOUNT            |  [... borrower deadline 1 0 <amount>]
   188  // ASSET             |  [... borrower deadline 1 0 <amount> <asset>]
   189  // 1                 |  [... borrower deadline 1 0 <amount> <asset> 1]
   190  // 6                 |  [... borrower deadline 1 0 <amount> <asset> 1 6]
   191  // ROLL              |  [... deadline 1 0 <amount> <asset> 1 borrower]
   192  // CHECKOUTPUT       |  [... deadline checkOutput(collateral, borrower)]
   193  // JUMP:$_end        |  [... borrower lender deadline balanceAmount balanceAsset]
   194  // $default          |  [... borrower lender deadline balanceAmount balanceAsset]
   195  // 2                 |  [... borrower lender deadline balanceAmount balanceAsset 2]
   196  // ROLL              |  [... borrower lender balanceAmount balanceAsset deadline]
   197  // MINTIME LESSTHAN  |  [... borrower lender balanceAmount balanceAsset after(deadline)]
   198  // VERIFY            |  [... borrower lender balanceAmount balanceAsset]
   199  // 0                 |  [... borrower lender balanceAmount balanceAsset 0]
   200  // 0                 |  [... borrower lender balanceAmount balanceAsset 0 0]
   201  // AMOUNT            |  [... borrower lender balanceAmount balanceAsset 0 0 <amount>]
   202  // ASSET             |  [... borrower lender balanceAmount balanceAsset 0 0 <amount> <asset>]
   203  // 1                 |  [... borrower lender balanceAmount balanceAsset 0 0 <amount> <asset> 1]
   204  // 7                 |  [... borrower lender balanceAmount balanceAsset 0 0 <amount> <asset> 1 7]
   205  // ROLL              |  [... borrower balanceAmount balanceAsset 0 0 <amount> <asset> 1 lender]
   206  // CHECKOUTPUT       |  [... borrower balanceAmount balanceAsset checkOutput(collateral, lender)]
   207  // $_end             |  [... borrower lender deadline balanceAmount balanceAsset]
   208  
   209  type (
   210  	Step struct {
   211  		Opcodes string `json:"opcodes"`
   212  		Stack   string `json:"stack"`
   213  	}
   214  )
   215  
   216  func (b *builder) steps() []Step {
   217  	var result []Step
   218  	for _, item := range b.items {
   219  		result = append(result, Step{item.opcodes, item.stk.String()})
   220  	}
   221  	return result
   222  }