aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMeng-Ying Yang <garfield@dexon.org>2019-02-13 15:58:55 +0800
committerJhih-Ming Huang <jm.huang@cobinhood.com>2019-05-06 10:44:03 +0800
commitd7ee3523a6b67a240d9f9e4924f286586c6613b2 (patch)
tree562e7d772a1fb516bbea23f1512efd9c67ad79b3
parent762c0baf7f42ebd3bdfbc408112351894ff555b5 (diff)
downloaddexon-d7ee3523a6b67a240d9f9e4924f286586c6613b2.tar.gz
dexon-d7ee3523a6b67a240d9f9e4924f286586c6613b2.tar.zst
dexon-d7ee3523a6b67a240d9f9e4924f286586c6613b2.zip
core: vm: sqlvm: types support data range
The data range is deterministic for specific type, `GetMinMax` is helper function to generate min, max value for clients.
-rw-r--r--core/vm/sqlvm/ast/types.go46
-rw-r--r--core/vm/sqlvm/ast/types_test.go36
2 files changed, 82 insertions, 0 deletions
diff --git a/core/vm/sqlvm/ast/types.go b/core/vm/sqlvm/ast/types.go
index 48e7b1fb5..cb8c62c04 100644
--- a/core/vm/sqlvm/ast/types.go
+++ b/core/vm/sqlvm/ast/types.go
@@ -15,12 +15,26 @@ var (
bigIntTen = big.NewInt(10)
)
+type decPair struct {
+ Min, Max decimal.Decimal
+}
+
+var (
+ decOne = decimal.New(1, 0)
+
+ decFalse = decimal.Zero
+ decTrue = decimal.New(1, 0)
+
+ decPairMap = make(map[DataType]decPair)
+)
+
// Error defines.
var (
ErrDataTypeEncode = errors.New("data type encode failed")
ErrDataTypeDecode = errors.New("data type decode failed")
ErrDecimalEncode = errors.New("decimal encode failed")
ErrDecimalDecode = errors.New("decimal decode failed")
+ ErrGetMinMax = errors.New("get (min, max) failed")
)
// DataTypeMajor defines type for high byte of DataType.
@@ -272,3 +286,35 @@ func DecimalDecode(dt DataType, b []byte) (decimal.Decimal, error) {
return decimal.Zero, ErrDecimalDecode
}
+
+// GetMinMax returns min, max pair according to given data type.
+func GetMinMax(dt DataType) (min, max decimal.Decimal, err error) {
+ cached, ok := decPairMap[dt]
+ if ok {
+ min, max = cached.Min, cached.Max
+ return
+ }
+
+ major, minor := DecomposeDataType(dt)
+ switch major {
+ case DataTypeMajorBool:
+ min, max = decFalse, decTrue
+ case DataTypeMajorAddress:
+ bigUMax := new(big.Int).Lsh(bigIntOne, common.AddressLength*8)
+ max = decimal.NewFromBigInt(bigUMax, 0).Sub(decOne)
+ case DataTypeMajorInt:
+ bigMax := new(big.Int).Lsh(bigIntOne, (uint(minor)+1)*8-1)
+ decMax := decimal.NewFromBigInt(bigMax, 0)
+ min, max = decMax.Neg(), decMax.Sub(decOne)
+ case DataTypeMajorUint,
+ DataTypeMajorFixedBytes:
+ bigUMax := new(big.Int).Lsh(bigIntOne, (uint(minor)+1)*8)
+ max = decimal.NewFromBigInt(bigUMax, 0).Sub(decOne)
+ default:
+ err = ErrGetMinMax
+ return
+ }
+
+ decPairMap[dt] = decPair{Max: max, Min: min}
+ return
+}
diff --git a/core/vm/sqlvm/ast/types_test.go b/core/vm/sqlvm/ast/types_test.go
index aa726c7ba..8280cf73f 100644
--- a/core/vm/sqlvm/ast/types_test.go
+++ b/core/vm/sqlvm/ast/types_test.go
@@ -3,6 +3,7 @@ package ast
import (
"testing"
+ "github.com/dexon-foundation/dexon/common"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/suite"
)
@@ -152,6 +153,41 @@ func (s *TypesTestSuite) TestEncodeAndDecodeDecimal() {
3)
}
+func (s *TypesTestSuite) TestGetMinMax() {
+ decAddressMax := decimal.New(2, 0).Pow(decimal.New(common.AddressLength*8, 0)).Sub(decOne)
+ testcases := []struct {
+ Name string
+ In DataType
+ Min, Max decimal.Decimal
+ Err error
+ }{
+ {"Bool", ComposeDataType(DataTypeMajorBool, 0), decFalse, decTrue, nil},
+ {"Address", ComposeDataType(DataTypeMajorAddress, 0), decimal.Zero, decAddressMax, nil},
+ {"Int8", ComposeDataType(DataTypeMajorInt, 0), decimal.New(-128, 0), decimal.New(127, 0), nil},
+ {"Int16", ComposeDataType(DataTypeMajorInt, 1), decimal.New(-32768, 0), decimal.New(32767, 0), nil},
+ {"UInt8", ComposeDataType(DataTypeMajorUint, 0), decimal.Zero, decimal.New(255, 0), nil},
+ {"UInt16", ComposeDataType(DataTypeMajorUint, 1), decimal.Zero, decimal.New(65535, 0), nil},
+ {"Bytes1", ComposeDataType(DataTypeMajorFixedBytes, 0), decimal.Zero, decimal.New(255, 0), nil},
+ {"Bytes2", ComposeDataType(DataTypeMajorFixedBytes, 1), decimal.Zero, decimal.New(65535, 0), nil},
+ {"Dynamic Bytes", ComposeDataType(DataTypeMajorDynamicBytes, 0), decimal.Zero, decimal.Zero, ErrGetMinMax},
+ }
+
+ var (
+ min, max decimal.Decimal
+ err error
+ )
+ for _, t := range testcases {
+ min, max, err = GetMinMax(t.In)
+ s.Require().Equal(t.Err, err, "Case: %v. Error not equal: %v != %v", t.Name, t.Err, err)
+ if t.Err != nil {
+ continue
+ }
+
+ s.Require().True(t.Min.Equal(min), "Case: %v. Min not equal: %v != %v", t.Name, t.Min, min)
+ s.Require().True(t.Max.Equal(max), "Case: %v. Max not equal: %v != %v", t.Name, t.Max, max)
+ }
+}
+
func TestTypes(t *testing.T) {
suite.Run(t, new(TypesTestSuite))
}