aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJhih-Ming Huang <jm.huang@cobinhood.com>2019-02-11 15:24:39 +0800
committerJhih-Ming Huang <jm.huang@cobinhood.com>2019-03-26 17:48:21 +0800
commit86ee06b89ace2443e112e5c00a3cf3b30ca0b3bf (patch)
tree84d35de20b50c2cdca9578b5500127e066f75b83
parent3292a673720e99d56495bc07ff0fc03f325c0737 (diff)
downloaddexon-86ee06b89ace2443e112e5c00a3cf3b30ca0b3bf.tar
dexon-86ee06b89ace2443e112e5c00a3cf3b30ca0b3bf.tar.gz
dexon-86ee06b89ace2443e112e5c00a3cf3b30ca0b3bf.tar.bz2
dexon-86ee06b89ace2443e112e5c00a3cf3b30ca0b3bf.tar.lz
dexon-86ee06b89ace2443e112e5c00a3cf3b30ca0b3bf.tar.xz
dexon-86ee06b89ace2443e112e5c00a3cf3b30ca0b3bf.tar.zst
dexon-86ee06b89ace2443e112e5c00a3cf3b30ca0b3bf.zip
core: vm: sqlvm: shared interfaces and params
After reconstructing commits, we move shared interfaces and params as first runtime implementation. In this commit we define OP codes, runtime flow and entrypoint, and basic operand structs and minor helper components.
-rw-r--r--core/vm/sqlvm/common/context.go11
-rw-r--r--core/vm/sqlvm/errors/errors.go14
-rw-r--r--core/vm/sqlvm/runtime/instructions.go63
-rw-r--r--core/vm/sqlvm/runtime/jumptable.go3
-rw-r--r--core/vm/sqlvm/runtime/opcodes.go135
-rw-r--r--core/vm/sqlvm/runtime/runtime.go19
6 files changed, 245 insertions, 0 deletions
diff --git a/core/vm/sqlvm/common/context.go b/core/vm/sqlvm/common/context.go
new file mode 100644
index 000000000..7c4305e3e
--- /dev/null
+++ b/core/vm/sqlvm/common/context.go
@@ -0,0 +1,11 @@
+package common
+
+import "github.com/dexon-foundation/dexon/core/vm"
+
+// Context holds SQL VM required params.
+type Context struct {
+ vm.Context
+
+ StateDB vm.StateDB
+ Contract *vm.Contract
+}
diff --git a/core/vm/sqlvm/errors/errors.go b/core/vm/sqlvm/errors/errors.go
index 60dee909b..f6b91ebae 100644
--- a/core/vm/sqlvm/errors/errors.go
+++ b/core/vm/sqlvm/errors/errors.go
@@ -89,6 +89,13 @@ const (
ErrorCodeEscapeSequenceTooShort
ErrorCodeInvalidUnicodeCodePoint
ErrorCodeUnknownEscapeSequence
+ // Runtime Error
+ ErrorCodeInvalidDataType
+ ErrorCodeOverflow
+ ErrorCodeUnderflow
+ ErrorCodeIndexOutOfRange
+ ErrorCodeInvalidCastType
+ ErrorCodeDividedByZero
)
var errorCodeMap = [...]string{
@@ -101,6 +108,13 @@ var errorCodeMap = [...]string{
ErrorCodeEscapeSequenceTooShort: "escape sequence too short",
ErrorCodeInvalidUnicodeCodePoint: "invalid unicode code point",
ErrorCodeUnknownEscapeSequence: "unknown escape sequence",
+ // Runtime Error
+ ErrorCodeInvalidDataType: "invalid data type",
+ ErrorCodeOverflow: "overflow",
+ ErrorCodeUnderflow: "underflow",
+ ErrorCodeIndexOutOfRange: "index out of range",
+ ErrorCodeInvalidCastType: "invalid cast type",
+ ErrorCodeDividedByZero: "divide by zero",
}
func (c ErrorCode) Error() string {
diff --git a/core/vm/sqlvm/runtime/instructions.go b/core/vm/sqlvm/runtime/instructions.go
new file mode 100644
index 000000000..f642a2515
--- /dev/null
+++ b/core/vm/sqlvm/runtime/instructions.go
@@ -0,0 +1,63 @@
+package runtime
+
+import (
+ "fmt"
+ "math/big"
+ "strings"
+
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/common"
+)
+
+var tupleJoin = "|"
+
+// OpFunction type
+// data could be fields Fields, pattern []byte, order Orders
+type OpFunction func(ctx *common.Context, ops []*Operand, registers []*Operand, output int) error
+
+// Instruction represents single instruction with essential information
+// collection.
+type Instruction struct {
+ op OpCode
+ input []*Operand
+ output int
+}
+
+// Raw with embedded big.Int value or byte slice which represents the real value
+// of basic operand unit.
+type Raw struct {
+ MajorType ast.DataTypeMajor
+ MinorType ast.DataTypeMinor
+
+ // for not bytes
+ Value *big.Int
+ Max, Min *big.Int
+ // for bytes
+ Bytes []byte
+}
+
+func (r *Raw) String() string {
+ return fmt.Sprintf(
+ "MajorType: %v, MinorType: %v, Value: %v, Bytes: %v",
+ r.MajorType, r.MinorType, r.Value, r.Bytes)
+}
+
+// Tuple is collection of Raw.
+type Tuple []*Raw
+
+func (t Tuple) String() string {
+ rawStr := []string{}
+ for i := 0; i < len(t); i++ {
+ rawStr = append(rawStr, t[i].String())
+ }
+ return strings.Join(rawStr, tupleJoin)
+}
+
+// Operand would be array-based value associated with meta to describe type of
+// array element.
+type Operand struct {
+ IsImmediate bool
+ Meta []ast.DataType
+ Data []Tuple
+ RegisterIndex *int
+}
diff --git a/core/vm/sqlvm/runtime/jumptable.go b/core/vm/sqlvm/runtime/jumptable.go
new file mode 100644
index 000000000..13ffef361
--- /dev/null
+++ b/core/vm/sqlvm/runtime/jumptable.go
@@ -0,0 +1,3 @@
+package runtime
+
+var jumpTable = map[OpCode]OpFunction{}
diff --git a/core/vm/sqlvm/runtime/opcodes.go b/core/vm/sqlvm/runtime/opcodes.go
new file mode 100644
index 000000000..22628b28e
--- /dev/null
+++ b/core/vm/sqlvm/runtime/opcodes.go
@@ -0,0 +1,135 @@
+package runtime
+
+// OpCode type
+type OpCode byte
+
+// 0x10 range - arithmetic ops. (array-based)
+const (
+ ADD OpCode = iota + 0x10
+ // ADD(t1, t2) res
+ // res = t1 + t2 = [1, 2] + [2, 3] = [3, 5]
+ MUL
+ // MUL(t1, t2) res
+ // res = t1 * t2 = [1, 2] * [2, 3] = [2, 6]
+ SUB
+ // SUB(t1, t2) res
+ // res = t1 - t2 = [1, 2] - [2, 3] = [-1, -1]
+ DIV
+ // DIV(t1, t2) res
+ // res = t1 / t2 = [1, 2] / [2, 3] = [0, 0]
+ MOD
+ // MOD(t1, t2) res
+ // res = t1 % t2 = [1, 2] % [2, 3] = [1, 2]
+
+)
+
+// 0x20 range - comparison ops.
+const (
+ LT OpCode = iota + 0x20
+ // LT(t1, t2) res
+ // res = t1 < t2 = [1, 2] < [2, 3] = [true, true]
+ GT
+ // GT(t1, t2) res
+ // res = t1 > t2 = [1, 2] > [2, 3] = [false, false]
+ EQ
+ // EQ(t1, t2) res
+ // res = t1 == t2 = [1, 2] == [2, 3] = [false, false]
+ AND
+ // AND(t1, t2) res
+ // res = t1 && t2 = [true, true] && [true, false] = [true, false]
+ OR
+ // OR(t1, t2) res
+ // res = t1 || t2 = [false, false] || [true, false] = [true, false]
+ NOT
+ // NOT(t1) res
+ // res = !t1 = ![false, true] = [true, false]
+ UNION
+ // UNION(t1, t2) res
+ // res = t1 ∪ t2 = [1, 2] ∪ [2, 3] = [1, 2, 3]
+ INTXN
+ // INTXN(t1, t2) res
+ // res = t1 ∩ t2 = [1, 2] ∩ [2, 3] = [2]
+ LIKE
+ // LIKE(t1, pattern) res
+ // res = t1 like '%abc%' =
+ // ['_abc_', '123'] like '%abc%' = [true, false]
+)
+
+// 0x30 range - pk/index/field meta ops
+const (
+ REPEATPK OpCode = iota + 0x30
+ // REPEATPK(pk) res res = [id1, id2, id3, ...]
+ // REPEATPK([tables, table_id, primary]) = [1, 2, 3, 5, 6, 7, ...]
+ REPEATIDX
+ // Scan given index value(s)
+ // REPEATIDX(base, idxv) res res = [id2, id4, id5, id6]
+ // REPEATIDX(
+ // [tables, table_id, indices, name_idx],
+ // [val1, val3]
+ // ) = [5, 6, 7, 10, 11, ... ]
+ REPEATIDXV
+ // Get possible values from index value meta
+ // REPEATIDXV(idx) res res = [val1, val2, val3, ...]
+ // REPEATIDXV(
+ // [tables, table_id, indices, name_idx]
+ // ) = ["alice", "bob", "foo", "bar", ... ]
+)
+
+// 0x40 range - format/output ops
+const (
+ ZIP OpCode = iota + 0x40
+ // ZIP(tgr, new) = res
+ // ZIP([f1, f2, f3], [c1, c2, c3]) = [(f1, c1), (f2, c2), (f3, c3)]
+ // ZIP(
+ // [(f1, c1), (f2, c2), (f3, c3)],
+ // [(x1, (y1)), (x2, (y2)), (x3, (y3))]
+ // ) = [(f1, c1, x1, (y1)), (f2, c2, x2, (y2)), (f3, c3, x2, (y2))]
+ FIELD
+ // (src, fields) = res
+ // (
+ // [(r1f1, r1f2, r1f3), (r2f1, r2f2, r2f3),...], [2,3]
+ // ) = [(r1f2, r1f3), (r2f2, r2f3), ...]
+ SORT
+ // SORT(src, [(field, order, null order)] ) = res
+ // SORT(
+ // [(a1, a2, a3), (b1, a2, null), (a1, b2, null), ...],
+ // [(1, asc, null_first), (2, desc, null_last), (3, asc, null_last)]
+ // ) = [(a1, a2, a3), (a1, b2, null), (b1, a2, null), ...]
+ FILTER
+ // FILTER(src, cond) = res
+ // FILTER([1, 2, 3, 4, 5], [true, false, true, false, false]) = [1, 3]
+ CAST
+ // CAST(t1, types) t2
+)
+
+// 0x60 range - storage ops
+const (
+ STOREPK OpCode = iota + 0x60
+ // STOREPK(pk, [uint256, uint256, ...])
+ LOADPK
+ // LOADPK(pk) array array = [uint256, uint256, ...]
+ STORE
+ // STORE(base, ids, values, fields, idxes)
+ // STORE(
+ // [tables, table_id, primary],
+ // [],
+ // [field1, field2, [field3.1, field3.2]],
+ // []
+ // )
+ // STORE(
+ // [tables, table_id, primary],
+ // [1, 2],
+ // [updated_field1, updated_field2],
+ // [1, 2]
+ // )
+ LOAD
+ // LOAD(base, ids, fields) array
+ // LOAD(
+ // [tables, table_id, primary], [1], []
+ // ) = [(field1, field2, [field3.1, field3.2])]
+ // LOAD(
+ // [tables, table_id, primary, [1], [1,3]
+ // ) =[(field1, [field3.1, field3.2])]
+ DELETE
+ // DELETE(base, ids, idxes)
+)
diff --git a/core/vm/sqlvm/runtime/runtime.go b/core/vm/sqlvm/runtime/runtime.go
new file mode 100644
index 000000000..ebb4d4579
--- /dev/null
+++ b/core/vm/sqlvm/runtime/runtime.go
@@ -0,0 +1,19 @@
+package runtime
+
+import (
+ "github.com/dexon-foundation/dexon/core/vm"
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/common"
+)
+
+// Run is runtime entrypoint.
+func Run(stateDB vm.StateDB, ins []Instruction, registers []*Operand) (ret []byte, err error) {
+ for _, in := range ins {
+ opFunc := jumpTable[in.op]
+ err = opFunc(&common.Context{}, in.input, registers, in.output)
+ if err != nil {
+ return nil, err
+ }
+ }
+ // TODO: ret = ABIEncode(ins[len(ins)-1].output)
+ return
+}