diff options
author | Meng-Ying Yang <garfield@dexon.org> | 2019-02-13 15:58:55 +0800 |
---|---|---|
committer | Jhih-Ming Huang <jm.huang@cobinhood.com> | 2019-03-26 17:48:21 +0800 |
commit | 42b72399fd5c7321a926b3b1dcf337de94cab6c7 (patch) | |
tree | 077756338abc51d0041325d4c6b4d49edd052469 | |
parent | 77648c442fc13211c3b65229e420471290fcd935 (diff) | |
download | dexon-42b72399fd5c7321a926b3b1dcf337de94cab6c7.tar.gz dexon-42b72399fd5c7321a926b3b1dcf337de94cab6c7.tar.zst dexon-42b72399fd5c7321a926b3b1dcf337de94cab6c7.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.go | 46 | ||||
-rw-r--r-- | core/vm/sqlvm/ast/types_test.go | 36 |
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)) } |