aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMeng-Ying Yang <garfield@dexon.org>2019-04-15 11:59:58 +0800
committerJhih-Ming Huang <jm.huang@cobinhood.com>2019-05-06 10:44:05 +0800
commit65362012ce4028c1438fe85dcaf8f17576423a2f (patch)
tree955721396f2036c39a59df6103c6b58fbda0416a
parent28f6d4ebc66bafea0fa9580cd61457645fe37794 (diff)
downloaddexon-65362012ce4028c1438fe85dcaf8f17576423a2f.tar.gz
dexon-65362012ce4028c1438fe85dcaf8f17576423a2f.tar.zst
dexon-65362012ce4028c1438fe85dcaf8f17576423a2f.zip
core: vm: sqlvm: add built-in function BLOCK_TIMESTAMP() and NOW()
-rw-r--r--core/vm/sqlvm/runtime/functions.go22
-rw-r--r--core/vm/sqlvm/runtime/functions_test.go56
2 files changed, 74 insertions, 4 deletions
diff --git a/core/vm/sqlvm/runtime/functions.go b/core/vm/sqlvm/runtime/functions.go
index 49e86160b..90b1a93fe 100644
--- a/core/vm/sqlvm/runtime/functions.go
+++ b/core/vm/sqlvm/runtime/functions.go
@@ -11,16 +11,20 @@ import (
// function identifier
const (
- BLOCKHASH = "BLOCK_HASH"
- BLOCKNUMBER = "BLOCK_NUMBER"
+ BLOCKHASH = "BLOCK_HASH"
+ BLOCKNUMBER = "BLOCK_NUMBER"
+ BLOCKTIMESTAMP = "BLOCK_TIMESTAMP"
+ NOW = "NOW"
)
type fn func(*common.Context, []*Operand, uint64) (*Operand, error)
var (
fnTable = map[string]fn{
- BLOCKHASH: fnBlockHash,
- BLOCKNUMBER: fnBlockNumber,
+ BLOCKHASH: fnBlockHash,
+ BLOCKNUMBER: fnBlockNumber,
+ BLOCKTIMESTAMP: fnBlockTimestamp,
+ NOW: fnBlockTimestamp,
}
)
@@ -85,3 +89,13 @@ func fnBlockNumber(ctx *common.Context, ops []*Operand, length uint64) (result *
)
return
}
+
+func fnBlockTimestamp(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) {
+ r := &Raw{Value: decimal.NewFromBigInt(ctx.Time, 0)}
+ result = assignFuncResult(
+ []ast.DataType{ast.ComposeDataType(ast.DataTypeMajorUint, 31)},
+ r.clone, length,
+ )
+ return
+}
+
diff --git a/core/vm/sqlvm/runtime/functions_test.go b/core/vm/sqlvm/runtime/functions_test.go
index a507403dc..e90e9b6c6 100644
--- a/core/vm/sqlvm/runtime/functions_test.go
+++ b/core/vm/sqlvm/runtime/functions_test.go
@@ -149,3 +149,59 @@ func (s *FunctionSuite) TestFnBlockNumber() {
}
}
+func (s *FunctionSuite) TestFnBlockTimestamp() {
+ type blockTimestampCase struct {
+ Name string
+ Timestamp *big.Int
+ Length uint64
+ Res decimal.Decimal
+ Err error
+ AsserPanic bool
+ }
+
+ testcases := []blockTimestampCase{
+ {"number 1 with length 1", big.NewInt(1), 1, decimal.New(1, 0), nil, false},
+ {"number 10 with length 10", big.NewInt(10), 10, decimal.New(10, 0), nil, false},
+ {"number 1 with length 0", big.NewInt(1), 0, decimal.New(1, 0), nil, false},
+ {"panic on invalid context", nil, 0, decimal.New(1, 0), nil, true},
+ }
+
+ callFn := func(c blockTimestampCase) (*Operand, error) {
+ return fnBlockTimestamp(
+ &common.Context{
+ Context: vm.Context{Time: c.Timestamp},
+ },
+ nil,
+ c.Length)
+ }
+
+ meta := []ast.DataType{ast.ComposeDataType(ast.DataTypeMajorUint, 31)}
+
+ for idx, tCase := range testcases {
+ if tCase.AsserPanic {
+ s.Require().Panicsf(
+ func() { callFn(tCase) },
+ "Index: %v. Not Panic on '%v'", idx, tCase.Name,
+ )
+ } else {
+ r, err := callFn(tCase)
+ s.Require().Equal(
+ tCase.Err, err,
+ "Index: %v. Error not expected: %v != %v", idx, tCase.Err, err)
+ s.Require().Equal(
+ meta, r.Meta,
+ "Index: %v. Meta not equal: %v != %v", idx, meta, r.Meta)
+ s.Require().Equal(
+ uint64(len(r.Data)), tCase.Length,
+ "Index: %v. Length not equal: %v != %v", idx, len(r.Data), tCase.Length)
+
+ for i := 0; i < len(r.Data); i++ {
+ s.Require().True(
+ tCase.Res.Equal(r.Data[i][0].Value),
+ "Index: %v. Data Index: %v. Value not equal: %v != %v",
+ idx, i, tCase.Res, r.Data[i][0].Value)
+ }
+ }
+ }
+}
+