diff options
author | Meng-Ying Yang <garfield@dexon.org> | 2019-05-03 11:02:46 +0800 |
---|---|---|
committer | Meng-Ying Yang <garfield@dexon.org> | 2019-05-06 17:38:02 +0800 |
commit | b70b3ff7d0b09eb9245b98ead0c53af7cdc5867b (patch) | |
tree | 6248b7f744b743141abda065dd0282a4a4915c38 | |
parent | 28dfe769a5cab65ed3ea981a784e2598c818afc4 (diff) | |
download | dexon-b70b3ff7d0b09eb9245b98ead0c53af7cdc5867b.tar.gz dexon-b70b3ff7d0b09eb9245b98ead0c53af7cdc5867b.tar.zst dexon-b70b3ff7d0b09eb9245b98ead0c53af7cdc5867b.zip |
core: vm: sqlvm: built-in functions support gas model
-rw-r--r-- | core/vm/sqlvm/runtime/functions.go | 151 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/functions_test.go | 18 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/instructions.go | 7 |
3 files changed, 117 insertions, 59 deletions
diff --git a/core/vm/sqlvm/runtime/functions.go b/core/vm/sqlvm/runtime/functions.go index 45d6cec65..1dc9e76ba 100644 --- a/core/vm/sqlvm/runtime/functions.go +++ b/core/vm/sqlvm/runtime/functions.go @@ -34,26 +34,79 @@ const ( SUBSTRING ) -type fn func(*common.Context, []*Operand, uint64) (*Operand, error) +type fn func(*common.Context, Instruction, uint64) (*Operand, error) + +type fnUnit struct { + Fn fn + GasFunc GasFunction +} var ( - fnTable = []fn{ - BLOCKHASH: fnBlockHash, - BLOCKNUMBER: fnBlockNumber, - BLOCKTIMESTAMP: fnBlockTimestamp, - NOW: fnBlockTimestamp, - BLOCKCOINBASE: fnBlockCoinBase, - BLOCKGASLIMIT: fnBlockGasLimit, - MSGSENDER: fnMsgSender, - MSGDATA: fnMsgData, - TXORIGIN: fnTxOrigin, - RAND: fnRand, - BITAND: fnBitAnd, - BITOR: fnBitOr, - BITXOR: fnBitXor, - BITNOT: fnBitNot, - OCTETLENGTH: fnOctetLength, - SUBSTRING: fnSubString, + fnTable = []fnUnit{ + BLOCKHASH: { + Fn: fnBlockHash, + GasFunc: constGasFunc(GasMemAlloc), + }, + BLOCKNUMBER: { + Fn: fnBlockNumber, + GasFunc: constGasFunc(GasMemAlloc), + }, + BLOCKTIMESTAMP: { + Fn: fnBlockTimestamp, + GasFunc: constGasFunc(GasMemAlloc), + }, + NOW: { + Fn: fnBlockTimestamp, + GasFunc: constGasFunc(GasMemAlloc), + }, + BLOCKCOINBASE: { + Fn: fnBlockCoinBase, + GasFunc: constGasFunc(GasMemAlloc), + }, + BLOCKGASLIMIT: { + Fn: fnBlockGasLimit, + GasFunc: constGasFunc(GasMemAlloc), + }, + MSGSENDER: { + Fn: fnMsgSender, + GasFunc: constGasFunc(GasMemAlloc), + }, + MSGDATA: { + Fn: fnMsgData, + GasFunc: constGasFunc(GasMemAlloc), + }, + TXORIGIN: { + Fn: fnTxOrigin, + GasFunc: constGasFunc(GasMemAlloc), + }, + RAND: { + Fn: fnRand, + GasFunc: constGasFunc(GasMemAlloc), + }, + BITAND: { + Fn: fnBitAnd, + GasFunc: constGasFunc(GasBitCmp), + }, + BITOR: { + Fn: fnBitOr, + GasFunc: constGasFunc(GasBitCmp), + }, + BITXOR: { + Fn: fnBitXor, + GasFunc: constGasFunc(GasBitCmp), + }, + BITNOT: { + Fn: fnBitNot, + GasFunc: constGasFunc(GasBitCmp), + }, + OCTETLENGTH: { + Fn: fnOctetLength, + GasFunc: constGasFunc(GasMemAlloc), + }, + SUBSTRING: { + Fn: fnSubString, + GasFunc: constGasFunc(GasMemFree), + }, } ) @@ -80,8 +133,8 @@ func evalBlockHash(ctx *common.Context, num, cur decimal.Decimal) (r *Raw, err e return } -func fnBlockHash(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { - if len(ops) != 1 { +func fnBlockHash(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { + if len(in.Input) != 1 { err = se.ErrorCodeInvalidOperandNum return } @@ -89,9 +142,9 @@ func fnBlockHash(ctx *common.Context, ops []*Operand, length uint64) (result *Op meta := []ast.DataType{ast.ComposeDataType(ast.DataTypeMajorFixedBytes, 3)} cNum := decimal.NewFromBigInt(ctx.BlockNumber, 0) - if ops[0].IsImmediate { + if in.Input[0].IsImmediate { var r *Raw - r, err = evalBlockHash(ctx, ops[0].Data[0][0].Value, cNum) + r, err = evalBlockHash(ctx, in.Input[0].Data[0][0].Value, cNum) if err != nil { return } @@ -100,7 +153,7 @@ func fnBlockHash(ctx *common.Context, ops []*Operand, length uint64) (result *Op result = &Operand{Meta: meta, Data: make([]Tuple, length)} for i := uint64(0); i < length; i++ { var r *Raw - r, err = evalBlockHash(ctx, ops[0].Data[i][0].Value, cNum) + r, err = evalBlockHash(ctx, in.Input[0].Data[i][0].Value, cNum) if err != nil { return } @@ -110,7 +163,7 @@ func fnBlockHash(ctx *common.Context, ops []*Operand, length uint64) (result *Op return } -func fnBlockNumber(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { +func fnBlockNumber(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { r := &Raw{Value: decimal.NewFromBigInt(ctx.BlockNumber, 0)} result = assignFuncResult( []ast.DataType{ast.ComposeDataType(ast.DataTypeMajorUint, 31)}, @@ -119,7 +172,7 @@ func fnBlockNumber(ctx *common.Context, ops []*Operand, length uint64) (result * return } -func fnBlockTimestamp(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { +func fnBlockTimestamp(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { r := &Raw{Value: decimal.NewFromBigInt(ctx.Time, 0)} result = assignFuncResult( []ast.DataType{ast.ComposeDataType(ast.DataTypeMajorUint, 31)}, @@ -128,7 +181,7 @@ func fnBlockTimestamp(ctx *common.Context, ops []*Operand, length uint64) (resul return } -func fnBlockCoinBase(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { +func fnBlockCoinBase(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { r := &Raw{Bytes: ctx.Coinbase.Bytes()} result = assignFuncResult( []ast.DataType{ast.ComposeDataType(ast.DataTypeMajorAddress, 0)}, @@ -137,7 +190,7 @@ func fnBlockCoinBase(ctx *common.Context, ops []*Operand, length uint64) (result return } -func fnBlockGasLimit(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { +func fnBlockGasLimit(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { r := &Raw{} if ctx.GasLimit > uint64(math.MaxInt64) { r.Value, err = decimal.NewFromString(fmt.Sprint(ctx.GasLimit)) @@ -154,7 +207,7 @@ func fnBlockGasLimit(ctx *common.Context, ops []*Operand, length uint64) (result return } -func fnMsgSender(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { +func fnMsgSender(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { r := &Raw{Bytes: ctx.Contract.CallerAddress.Bytes()} result = assignFuncResult( []ast.DataType{ast.ComposeDataType(ast.DataTypeMajorAddress, 0)}, @@ -163,7 +216,7 @@ func fnMsgSender(ctx *common.Context, ops []*Operand, length uint64) (result *Op return } -func fnMsgData(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { +func fnMsgData(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { r := &Raw{Bytes: ctx.Contract.Input} result = assignFuncResult( []ast.DataType{ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0)}, @@ -172,7 +225,7 @@ func fnMsgData(ctx *common.Context, ops []*Operand, length uint64) (result *Oper return } -func fnTxOrigin(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { +func fnTxOrigin(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { r := &Raw{Bytes: ctx.Origin.Bytes()} result = assignFuncResult( []ast.DataType{ast.ComposeDataType(ast.DataTypeMajorAddress, 0)}, @@ -181,7 +234,7 @@ func fnTxOrigin(ctx *common.Context, ops []*Operand, length uint64) (result *Ope return } -func fnRand(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { +func fnRand(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { binaryOriginNonce := make([]byte, binary.MaxVarintLen64) binary.PutUvarint(binaryOriginNonce, ctx.Storage.GetNonce(ctx.Origin)) @@ -283,8 +336,8 @@ func (r *Raw) fromBytes(bytes []byte, dType ast.DataType) { type bitBinFunc func(b1, b2 byte) byte -func fnBitAnd(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { - n, op1, op2, err := extractOps(ops) +func fnBitAnd(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { + n, op1, op2, err := extractOps(in.Input) if err != nil { return } @@ -327,8 +380,8 @@ func (r *Raw) bitBinOp(r2 *Raw, dType ast.DataType, bFn bitBinFunc) (r3 *Raw) { return } -func fnBitOr(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { - n, op1, op2, err := extractOps(ops) +func fnBitOr(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { + n, op1, op2, err := extractOps(in.Input) if err != nil { return } @@ -345,8 +398,8 @@ func fnBitOr(ctx *common.Context, ops []*Operand, length uint64) (result *Operan return } -func fnBitXor(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { - n, op1, op2, err := extractOps(ops) +func fnBitXor(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { + n, op1, op2, err := extractOps(in.Input) if err != nil { return } @@ -365,13 +418,13 @@ func fnBitXor(ctx *common.Context, ops []*Operand, length uint64) (result *Opera type bitUnFunc func(b byte) byte -func fnBitNot(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { - if len(ops) < 1 { +func fnBitNot(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { + if len(in.Input) < 1 { err = se.ErrorCodeInvalidOperandNum return } - op := ops[0] + op := in.Input[0] if !metaAllBitOp(op) { err = se.ErrorCodeInvalidDataType return @@ -410,13 +463,13 @@ func (r *Raw) bitUnOp(dType ast.DataType, bFn bitUnFunc) (r2 *Raw) { return } -func fnOctetLength(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { - if len(ops) < 1 { +func fnOctetLength(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { + if len(in.Input) < 1 { err = se.ErrorCodeInvalidOperandNum return } - op := ops[0] + op := in.Input[0] if !metaAllDynBytes(op) { err = se.ErrorCodeInvalidDataType @@ -442,19 +495,19 @@ func fnOctetLength(ctx *common.Context, ops []*Operand, length uint64) (result * return } -func fnSubString(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) { - if len(ops) < 3 { +func fnSubString(ctx *common.Context, in Instruction, length uint64) (result *Operand, err error) { + if len(in.Input) < 3 { err = se.ErrorCodeInvalidOperandNum return } - if len(ops[0].Data) != len(ops[1].Data) || - len(ops[0].Data) != len(ops[2].Data) { + if len(in.Input[0].Data) != len(in.Input[1].Data) || + len(in.Input[0].Data) != len(in.Input[2].Data) { err = se.ErrorCodeIndexOutOfRange return } - op := ops[0] + op := in.Input[0] if !metaAllDynBytes(op) { err = se.ErrorCodeInvalidDataType @@ -470,7 +523,7 @@ func fnSubString(ctx *common.Context, ops []*Operand, length uint64) (result *Op result.Meta[i] = dynBytesType } - starts, ends := ops[1], ops[2] + starts, ends := in.Input[1], in.Input[2] var start, end uint64 for i := 0; i < len(op.Data); i++ { diff --git a/core/vm/sqlvm/runtime/functions_test.go b/core/vm/sqlvm/runtime/functions_test.go index 828c43efa..29a67e10f 100644 --- a/core/vm/sqlvm/runtime/functions_test.go +++ b/core/vm/sqlvm/runtime/functions_test.go @@ -67,7 +67,7 @@ func (s *FunctionSuite) TestFnBlockHash() { BlockNumber: c.Cur, }, }, - c.Ops, + Instruction{Input: c.Ops}, c.Length, ) } @@ -117,7 +117,7 @@ func (s *FunctionSuite) TestFnBlockNumber() { &common.Context{ Context: vm.Context{BlockNumber: c.RawNum}, }, - nil, + Instruction{}, c.Length) } @@ -173,7 +173,7 @@ func (s *FunctionSuite) TestFnBlockTimestamp() { &common.Context{ Context: vm.Context{Time: c.Timestamp}, }, - nil, + Instruction{}, c.Length) } @@ -233,7 +233,7 @@ func (s *FunctionSuite) TestFnCoinBase() { &common.Context{ Context: vm.Context{Coinbase: c.Address}, }, - nil, + Instruction{}, c.Length) } @@ -279,7 +279,7 @@ func (s *FunctionSuite) TestFnGasLimit() { &common.Context{ Context: vm.Context{GasLimit: c.Limit}, }, - nil, + Instruction{}, c.Length) } @@ -332,7 +332,7 @@ func (s *FunctionSuite) TestFnMsgSender() { &common.Context{ Contract: &vm.Contract{CallerAddress: c.Address}, }, - nil, + Instruction{}, c.Length) } @@ -383,7 +383,7 @@ func (s *FunctionSuite) TestFnMsgData() { &common.Context{ Contract: &vm.Contract{Input: c.Res}, }, - nil, + Instruction{}, c.Length) } @@ -436,7 +436,7 @@ func (s *FunctionSuite) TestFnTxOrigin() { &common.Context{ Context: vm.Context{Origin: c.Address}, }, - nil, + Instruction{}, c.Length) } @@ -488,7 +488,7 @@ func (s *FunctionSuite) TestFnRand() { Context: vm.Context{Origin: c.Origin, Randomness: res}, Storage: newStorage(), }, - nil, + Instruction{}, c.Length) } diff --git a/core/vm/sqlvm/runtime/instructions.go b/core/vm/sqlvm/runtime/instructions.go index 93e43709f..d07f66533 100644 --- a/core/vm/sqlvm/runtime/instructions.go +++ b/core/vm/sqlvm/runtime/instructions.go @@ -1886,7 +1886,12 @@ func opFunc(ctx *common.Context, in Instruction) (err error) { return } - result, err = fnTable[id](ctx, in.Input[2:], length) + fUnit := fnTable[id] + + in.Input = in.Input[2:] + in.GasFunc = fUnit.GasFunc + + result, err = fUnit.Fn(ctx, in, length) if err != nil { return } |