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 }