diff options
author | Meng-Ying Yang <garfield@dexon.org> | 2019-04-15 11:55:20 +0800 |
---|---|---|
committer | Jhih-Ming Huang <jm.huang@cobinhood.com> | 2019-05-06 10:44:05 +0800 |
commit | 28f6d4ebc66bafea0fa9580cd61457645fe37794 (patch) | |
tree | f22b924ac7a5f7bddc736c690454a7a776792cb5 | |
parent | bb29b970cf211535cf76eee0217dc8de7dcf88bc (diff) | |
download | dexon-28f6d4ebc66bafea0fa9580cd61457645fe37794.tar.gz dexon-28f6d4ebc66bafea0fa9580cd61457645fe37794.tar.zst dexon-28f6d4ebc66bafea0fa9580cd61457645fe37794.zip |
core: vm: sqlvm: add built-in function BLOCK_NUMBER()
-rw-r--r-- | core/vm/sqlvm/runtime/functions.go | 15 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/functions_test.go | 57 |
2 files changed, 70 insertions, 2 deletions
diff --git a/core/vm/sqlvm/runtime/functions.go b/core/vm/sqlvm/runtime/functions.go index 74fa50fc1..49e86160b 100644 --- a/core/vm/sqlvm/runtime/functions.go +++ b/core/vm/sqlvm/runtime/functions.go @@ -11,14 +11,16 @@ import ( // function identifier const ( - BLOCKHASH = "BLOCK_HASH" + BLOCKHASH = "BLOCK_HASH" + BLOCKNUMBER = "BLOCK_NUMBER" ) type fn func(*common.Context, []*Operand, uint64) (*Operand, error) var ( fnTable = map[string]fn{ - BLOCKHASH: fnBlockHash, + BLOCKHASH: fnBlockHash, + BLOCKNUMBER: fnBlockNumber, } ) @@ -74,3 +76,12 @@ 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) { + r := &Raw{Value: decimal.NewFromBigInt(ctx.BlockNumber, 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 fe8fa0791..a507403dc 100644 --- a/core/vm/sqlvm/runtime/functions_test.go +++ b/core/vm/sqlvm/runtime/functions_test.go @@ -92,3 +92,60 @@ func (s *FunctionSuite) TestFnBlockHash() { } } } + +func (s *FunctionSuite) TestFnBlockNumber() { + type blockNumberCase struct { + Name string + RawNum *big.Int + Length uint64 + ResNum decimal.Decimal + Err error + AsserPanic bool + } + + testcases := []blockNumberCase{ + {"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 blockNumberCase) (*Operand, error) { + return fnBlockNumber( + &common.Context{ + Context: vm.Context{BlockNumber: c.RawNum}, + }, + 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.ResNum.Equal(r.Data[i][0].Value), + "Index: %v Data index: %v. Value not equal: %v != %v", + idx, i, tCase.ResNum, r.Data[i][0].Value) + } + } + } +} + |