OSDN Git Service

Hulk did something
[bytom/vapor.git] / equity / equity / util / shift.go
diff --git a/equity/equity/util/shift.go b/equity/equity/util/shift.go
new file mode 100644 (file)
index 0000000..c9cc003
--- /dev/null
@@ -0,0 +1,62 @@
+package equity
+
+import (
+       "bytes"
+       "encoding/binary"
+       "encoding/hex"
+       "errors"
+
+       "github.com/vapor/protocol/vm"
+
+       "github.com/vapor/equity/compiler"
+)
+
+const (
+       firstClauseShift string = "00000000"
+       endingClauseName string = "ending"
+)
+
+// Shift statistics contract clause's offset
+func Shift(contract *compiler.Contract) (map[string]string, error) {
+       clauseMap := make(map[string]string)
+       if len(contract.Clauses) == 1 {
+               clauseMap[contract.Clauses[0].Name] = firstClauseShift
+               return clauseMap, nil
+       }
+
+       instructions, err := vm.ParseProgram(contract.Body)
+       if err != nil {
+               return nil, err
+       }
+
+       var jumpifData [][]byte
+       for i, inst := range instructions {
+               if inst.Op.String() == "JUMPIF" {
+                       if i > 0 && instructions[i-1].Op.String() == "NOP" {
+                               continue
+                       }
+                       jumpifData = append([][]byte{inst.Data}, jumpifData...)
+               }
+       }
+
+       // Check the number of contract's clause
+       if len(contract.Clauses) != len(jumpifData)+1 {
+               return nil, errors.New("the number of contract's clause is not equal to the number of jumpif instruction")
+       }
+
+       for i, clause := range contract.Clauses {
+               if i == 0 {
+                       clauseMap[clause.Name] = firstClauseShift
+                       continue
+               }
+               clauseMap[clause.Name] = hex.EncodeToString(jumpifData[i-1])
+       }
+
+       var buffer bytes.Buffer
+       if err := binary.Write(&buffer, binary.LittleEndian, uint32(len(contract.Body))); err != nil {
+               return nil, err
+       }
+       clauseMap[endingClauseName] = hex.EncodeToString(buffer.Bytes())
+
+       return clauseMap, nil
+}