From ad3ceebebe61718e4eb88ee77eef86d9844fc241 Mon Sep 17 00:00:00 2001
From: Meng-Ying Yang <garfield@dexon.org>
Date: Mon, 15 Apr 2019 12:14:04 +0800
Subject: core: vm: sqlvm: add built-in function MSG_SENDER()

---
 core/vm/sqlvm/runtime/functions.go      | 12 ++++++++
 core/vm/sqlvm/runtime/functions_test.go | 54 +++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+)

(limited to 'core/vm')

diff --git a/core/vm/sqlvm/runtime/functions.go b/core/vm/sqlvm/runtime/functions.go
index c180f1714..fad6e475a 100644
--- a/core/vm/sqlvm/runtime/functions.go
+++ b/core/vm/sqlvm/runtime/functions.go
@@ -19,6 +19,7 @@ const (
 	BLOCKTIMESTAMP = "BLOCK_TIMESTAMP"
 	BLOCKCOINBASE  = "BLOCK_COINBASE"
 	BLOCKGASLIMIT  = "BLOCK_GAS_LIMIT"
+	MSGSENDER      = "MSG_SENDER"
 	NOW            = "NOW"
 )
 
@@ -32,6 +33,7 @@ var (
 		NOW:            fnBlockTimestamp,
 		BLOCKCOINBASE:  fnBlockCoinBase,
 		BLOCKGASLIMIT:  fnBlockGasLimit,
+		MSGSENDER:      fnMsgSender,
 	}
 )
 
@@ -131,3 +133,13 @@ func fnBlockGasLimit(ctx *common.Context, ops []*Operand, length uint64) (result
 	)
 	return
 }
+
+func fnMsgSender(ctx *common.Context, ops []*Operand, length uint64) (result *Operand, err error) {
+	r := &Raw{Bytes: ctx.Contract.CallerAddress.Bytes()}
+	result = assignFuncResult(
+		[]ast.DataType{ast.ComposeDataType(ast.DataTypeMajorAddress, 0)},
+		r.clone, length,
+	)
+	return
+}
+
diff --git a/core/vm/sqlvm/runtime/functions_test.go b/core/vm/sqlvm/runtime/functions_test.go
index 638d8e2ec..cb122e28d 100644
--- a/core/vm/sqlvm/runtime/functions_test.go
+++ b/core/vm/sqlvm/runtime/functions_test.go
@@ -305,3 +305,57 @@ func (s *FunctionSuite) TestFnGasLimit() {
 		}
 	}
 }
+
+func (s *FunctionSuite) TestFnMsgSender() {
+	type txMsgSenderCase struct {
+		Name    string
+		Address dexCommon.Address
+		Length  uint64
+		Res     []byte
+		Err     error
+	}
+
+	res := []byte{
+		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+		0x01, 0x23, 0x45, 0x67}
+	address := dexCommon.BytesToAddress(res)
+
+	testcases := []txMsgSenderCase{
+		{"address with length 1", address, 1, res, nil},
+		{"address with length 10", address, 10, res, nil},
+		{"address with length 0", address, 0, res, nil},
+	}
+
+	callFn := func(c txMsgSenderCase) (*Operand, error) {
+		return fnMsgSender(
+			&common.Context{
+				Contract: &vm.Contract{CallerAddress: c.Address},
+			},
+			nil,
+			c.Length)
+	}
+
+	meta := []ast.DataType{ast.ComposeDataType(ast.DataTypeMajorAddress, 0)}
+
+	for idx, tCase := range testcases {
+		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().Equal(
+				tCase.Res, r.Data[i][0].Bytes,
+				"Index: %v. Data Index: %v. Value not equal: %v != %v",
+				idx, i, tCase.Res, r.Data[i][0].Bytes)
+		}
+	}
+}
+
-- 
cgit v1.2.3