diff --git a/common/config/config.go b/common/config/config.go index d52a6e4bd8..971558e217 100644 --- a/common/config/config.go +++ b/common/config/config.go @@ -114,6 +114,16 @@ func GetStateHashCheckHeight(id uint32) uint32 { return STATE_HASH_CHECK_HEIGHT[id] } +var OPCODE_UPDATE_CHECK_HEIGHT = map[uint32]uint32{ + NETWORK_ID_MAIN_NET: constants.OPCODE_HEIGHT_UPDATE_FIRST_MAINNET, //Network main + NETWORK_ID_POLARIS_NET: constants.OPCODE_HEIGHT_UPDATE_FIRST_POLARIS, //Network polaris + NETWORK_ID_SOLO_NET: 0, //Network solo +} + +func GetOpcodeUpdateCheckHeight(id uint32) uint32 { + return OPCODE_UPDATE_CHECK_HEIGHT[id] +} + func GetNetworkName(id uint32) string { name, ok := NETWORK_NAME[id] if ok { diff --git a/common/constants/constants.go b/common/constants/constants.go index c863bc956a..e0d9bb5508 100644 --- a/common/constants/constants.go +++ b/common/constants/constants.go @@ -82,3 +82,7 @@ const ( // ledger state hash check height const STATE_HASH_HEIGHT_MAINNET = 3000000 const STATE_HASH_HEIGHT_POLARIS = 850000 + +// neovm opcode update check height +const OPCODE_HEIGHT_UPDATE_FIRST_MAINNET = 6000000 +const OPCODE_HEIGHT_UPDATE_FIRST_POLARIS = 2100000 diff --git a/consensus/vbft/msg_types_test.go b/consensus/vbft/msg_types_test.go index 04e75422f3..ad5f765614 100644 --- a/consensus/vbft/msg_types_test.go +++ b/consensus/vbft/msg_types_test.go @@ -434,3 +434,31 @@ func TestBlockFetchRespMsgDeserialize(t *testing.T) { } t.Logf("BlockFetchRespMsg Serialize succ: %v\n", respmsg.BlockNumber) } + +func TestBlockSerialization(t *testing.T) { + blk, err := constructBlock() + if err != nil { + t.Errorf("constructBlock failed: %v", err) + return + } + + data, err := blk.Serialize() + if err != nil { + t.Fatalf("serialize blk: %s", err) + } + + blk2 := &Block{} + if err := blk2.Deserialize(data); err != nil { + t.Fatalf("deserialize blk: %s", err) + } + + blk.EmptyBlock = nil + data2, err := blk.Serialize() + if err != nil { + t.Fatalf("serialize blk2: %s", err) + } + blk3 := &Block{} + if err := blk3.Deserialize(data2); err != nil { + t.Fatalf("deserialize blk2: %s", err) + } +} diff --git a/consensus/vbft/node_utils_test.go b/consensus/vbft/node_utils_test.go index d00485cae6..4d0aa6e56d 100644 --- a/consensus/vbft/node_utils_test.go +++ b/consensus/vbft/node_utils_test.go @@ -206,7 +206,7 @@ func testCalcParticipantPeers(t *testing.T, n, c int) { for _, p := range pc { peers[p] = true } - if len(peers) <= 2*c+1 { + if len(peers) < 2*c+1 { t.Fatalf("peers(%d, %d, %d, %d, %d, %d): %v, %v, %v", n, c, len(peers), len(pp), len(pe), len(pc), pp, pe, pc) } } diff --git a/consensus/vbft/types.go b/consensus/vbft/types.go index 564ba884c0..3e5a54d72d 100644 --- a/consensus/vbft/types.go +++ b/consensus/vbft/types.go @@ -24,7 +24,6 @@ import ( "io" "github.com/ontio/ontology/common" - "github.com/ontio/ontology/common/log" "github.com/ontio/ontology/consensus/vbft/config" "github.com/ontio/ontology/core/types" ) @@ -78,6 +77,7 @@ func (blk *Block) Serialize() ([]byte, error) { payload := common.NewZeroCopySink(nil) payload.WriteVarBytes(sink.Bytes()) + payload.WriteBool(blk.EmptyBlock != nil) if blk.EmptyBlock != nil { sink2 := common.NewZeroCopySink(nil) blk.EmptyBlock.Serialization(sink2) @@ -109,22 +109,29 @@ func (blk *Block) Deserialize(data []byte) error { } var emptyBlock *types.Block - if source.Len() > 0 { + hasEmptyBlock, irr, eof := source.NextBool() + if irr { + return fmt.Errorf("read empty-block-bool: %s", common.ErrIrregularData) + } + if eof { + return fmt.Errorf("read empty-block-bool: %s", io.ErrUnexpectedEOF) + } + if hasEmptyBlock { buf2, _, irregular, eof := source.NextVarBytes() - if irregular == false && eof == false { - block2, err := types.BlockFromRawBytes(buf2) - if err == nil { - emptyBlock = block2 - } + if irregular || eof { + return fmt.Errorf("read empty block failed: %v, %v", irregular, eof) + } + block2, err := types.BlockFromRawBytes(buf2) + if err != nil { + return fmt.Errorf("deserialize empty blk failed: %s", err) } + emptyBlock = block2 } + var merkleRoot common.Uint256 - if source.Len() > 0 { - merkleRoot, eof = source.NextHash() - if eof { - log.Errorf("Block Deserialize merkleRoot") - return io.ErrUnexpectedEOF - } + merkleRoot, eof = source.NextHash() + if eof { + return fmt.Errorf("block deserialize merkleRoot: %s", io.ErrUnexpectedEOF) } blk.Block = block blk.EmptyBlock = emptyBlock diff --git a/docs/specifications/restful_api.md b/docs/specifications/restful_api.md index 8053b2c374..463f64434b 100644 --- a/docs/specifications/restful_api.md +++ b/docs/specifications/restful_api.md @@ -47,6 +47,7 @@ This document describes the restful api format for the http/https used in the On | [post_raw_tx](#21-post_raw_tx) | post /api/v1/transaction?preExec=0 | send transaction to ontology network | | [get_networkid](#22-get_networkid) | GET /api/v1/networkid | return the networkid | | [get_grantong](#23-get_grantong) | GET /api/v1/grantong/:addr | get grant ong | +| [sendpretransactions](#24-sendpretransactions) | POST /api/v1/pretransactions | Batch execution of pre-executed transactions | ### 1 get_conn_count @@ -872,6 +873,73 @@ curl -i http://localhost:20334/api/v1/grantong/AKDFapcoUhewN9Kaj6XhHusurfHzUiZqU } ``` +### 24 sendpretransactions + +Batch execution of pre-executed transactions + +POST +``` +/api/v1/pretransactions +``` +#### Request Example: +``` +curl -i http://localhost:20334/api/v1/pretransactions +``` + +#### post parameters + +```json +{ + "jsonrpc": "2.0", + "Action": "sendpretransactions", + "Data": [ + "00d1de5655540000000000000000000000000000000000000000000000000000000000000000000000004d14322df60ebaddf100501817f2171930d79ae81f660962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d1c9657e8b0000000000000000000000000000000000000000000000000000000000000000000000004d1498dee28a01a16f116f8c6e6b437af92a190e2c750962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d11aec11060000000000000000000000000000000000000000000000000000000000000000000000004d149e1969e4c7813787a8214e73d1b1206f3d2ffbcc0962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d1452edb510000000000000000000000000000000000000000000000000000000000000000000000004d14e224ca2cd7482712bdd64b2cc02b10db21494fd90962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000" + ], + "id": 0 + +} +``` + +#### Response +``` +{ + "Action": "sendpretransactions", + "Desc": "SUCCESS", + "Error": 0, + "Result": [ + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + } + ], + "Version": "1.0.0" +} +``` + + ## Error Code | Field | Type | Description | diff --git a/docs/specifications/restful_api_CN.md b/docs/specifications/restful_api_CN.md index 20dacede25..f8da1c2253 100644 --- a/docs/specifications/restful_api_CN.md +++ b/docs/specifications/restful_api_CN.md @@ -47,6 +47,7 @@ | [post_raw_tx](#21-post_raw_tx) | post /api/v1/transaction?preExec=0 | 向ontology网络发送交易 | | [get_networkid](#22-get_networkid) | GET /api/v1/networkid | 得到network id | | [get_grantong](#23-get_grantong) | GET /api/v1/grantong/:addr | 得到grant ong | +| [sendpretransactions](#24-sendpretransactions) | POST /api/v1/pretransactions | 预执行交易批量执行 | ### 1 get_conn_count @@ -871,6 +872,72 @@ curl -i http://localhost:20334/api/v1/grantong/AKDFapcoUhewN9Kaj6XhHusurfHzUiZqU } ``` +### 24 sendpretransactions + +批量执行预执行交易 + +POST +``` +/api/v1/pretransactions +``` +#### Request Example: +``` +curl -i http://localhost:20334/api/v1/pretransactions +``` + +#### post parameters + +```json +{ + "jsonrpc": "2.0", + "Action": "sendpretransactions", + "Data": [ + "00d1de5655540000000000000000000000000000000000000000000000000000000000000000000000004d14322df60ebaddf100501817f2171930d79ae81f660962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d1c9657e8b0000000000000000000000000000000000000000000000000000000000000000000000004d1498dee28a01a16f116f8c6e6b437af92a190e2c750962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d11aec11060000000000000000000000000000000000000000000000000000000000000000000000004d149e1969e4c7813787a8214e73d1b1206f3d2ffbcc0962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d1452edb510000000000000000000000000000000000000000000000000000000000000000000000004d14e224ca2cd7482712bdd64b2cc02b10db21494fd90962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000" + ], + "id": 0 + +} +``` + +#### Response +``` +{ + "Action": "sendpretransactions", + "Desc": "SUCCESS", + "Error": 0, + "Result": [ + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + } + ], + "Version": "1.0.0" +} +``` + ## 错误代码 | Field | Type | Description | diff --git a/docs/specifications/rpc_api.md b/docs/specifications/rpc_api.md index f08ce99424..9eb1be38b5 100644 --- a/docs/specifications/rpc_api.md +++ b/docs/specifications/rpc_api.md @@ -97,6 +97,7 @@ There are some description of parameter used in rpc: | [getblocktxsbyheight](#20-getblocktxsbyheight) | height | return transaction hashes | | | [getnetworkid](#21-getnetworkid) | | Get the network id | | | [getgrantong](#22-getgrantong) | | Get grant ong | | +| [sendpretransactions](#23-sendpretransactions) | POST /api/v1/sendpretransactions | Batch execution of pre-executed transactions | ### 1. getbestblockhash @@ -1099,6 +1100,73 @@ Response: } ``` +### 23 sendpretransactions + +Batch execution of pre-executed transactions + +POST +``` +/api/v1/sendpretransactions +``` +#### Request Example: +``` +curl -i http://localhost:20336/api/v1/sendpretransactions +``` + +#### post parameters + +```json +{ + "jsonrpc": "2.0", + "method": "sendpretransactions", + "params": [ + "00d1de5655540000000000000000000000000000000000000000000000000000000000000000000000004d14322df60ebaddf100501817f2171930d79ae81f660962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d1c9657e8b0000000000000000000000000000000000000000000000000000000000000000000000004d1498dee28a01a16f116f8c6e6b437af92a190e2c750962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d11aec11060000000000000000000000000000000000000000000000000000000000000000000000004d149e1969e4c7813787a8214e73d1b1206f3d2ffbcc0962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d1452edb510000000000000000000000000000000000000000000000000000000000000000000000004d14e224ca2cd7482712bdd64b2cc02b10db21494fd90962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000" + ], + "id": 0 + +} +``` + +#### Response +``` +{ + "Action": "sendpretransactions", + "Desc": "SUCCESS", + "Error": 0, + "Result": [ + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + } + ], + "Version": "1.0.0" +} +``` + + ## Error Code errorcode instruction diff --git a/docs/specifications/rpc_api_CN.md b/docs/specifications/rpc_api_CN.md index 9ce23f3313..0c83448318 100644 --- a/docs/specifications/rpc_api_CN.md +++ b/docs/specifications/rpc_api_CN.md @@ -97,6 +97,7 @@ | [getblocktxsbyheight](#20-getblocktxsbyheight) | height | 返回该高度对应的区块落账的交易的哈希 | | | [getnetworkid](#21-getnetworkid) | | 获取 network id | | | [getgrantong](#22-getgrantong) | | 获取 grant ong | | +| [sendpretransactions](#23-sendpretransactions) | POST /api/v1/sendpretransactions | 预执行交易批量执行 | ### 1. getbestblockhash @@ -1111,6 +1112,73 @@ Response: } ``` +### 23 sendpretransactions + +批量执行预执行交易 + +POST +``` +/api/v1/sendpretransactions +``` +#### Request Example: +``` +curl -i http://localhost:20336/api/v1/sendpretransactions +``` + +#### post parameters + +```json +{ + "jsonrpc": "2.0", + "method": "sendpretransactions", + "params": [ + "00d1de5655540000000000000000000000000000000000000000000000000000000000000000000000004d14322df60ebaddf100501817f2171930d79ae81f660962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d1c9657e8b0000000000000000000000000000000000000000000000000000000000000000000000004d1498dee28a01a16f116f8c6e6b437af92a190e2c750962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d11aec11060000000000000000000000000000000000000000000000000000000000000000000000004d149e1969e4c7813787a8214e73d1b1206f3d2ffbcc0962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000", + "00d1452edb510000000000000000000000000000000000000000000000000000000000000000000000004d14e224ca2cd7482712bdd64b2cc02b10db21494fd90962616c616e63654f661400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650000" + ], + "id": 0 + +} +``` + +#### Response +``` +{ + "Action": "sendpretransactions", + "Desc": "SUCCESS", + "Error": 0, + "Result": [ + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + }, + { + "State": 1, + "Gas": 20000, + "Result": "", + "Notify": null + } + ], + "Version": "1.0.0" +} +``` + + ## 错误代码 错误码定义 diff --git a/http/base/common/common.go b/http/base/common/common.go index bedd09dde9..5a54ca15ce 100644 --- a/http/base/common/common.go +++ b/http/base/common/common.go @@ -45,6 +45,7 @@ import ( const MAX_SEARCH_HEIGHT uint32 = 100 const MAX_REQUEST_BODY_SIZE = 1 << 20 +const MAX_MULTI_TX_SIZE = 100 type BalanceOfRsp struct { Ont string `json:"ont"` diff --git a/http/base/rest/interfaces.go b/http/base/rest/interfaces.go index 180dafa2ec..e19e88ccbd 100644 --- a/http/base/rest/interfaces.go +++ b/http/base/rest/interfaces.go @@ -287,6 +287,45 @@ func SendRawTransaction(cmd map[string]interface{}) map[string]interface{} { return resp } +// multi pre tx, [tx1, tx2,tx3] +func SendPreTransactions(params map[string]interface{}) map[string]interface{} { + if len(params) < 1 { + return ResponsePack(berr.INVALID_PARAMS) + } + paras, ok := params["Data"].([]interface{}) + if !ok || len(paras) < 1 || len(paras) > bcomn.MAX_MULTI_TX_SIZE { + return ResponsePack(berr.INVALID_PARAMS) + } + res := make([]interface{}, 0) + for _, param := range paras { + txStr, ok := param.(string) + if !ok { + return ResponsePack(berr.INVALID_PARAMS) + } + raw, err := common.HexToBytes(txStr) + if err != nil { + return ResponsePack(berr.INVALID_PARAMS) + } + txn, err := types.TransactionFromRawBytes(raw) + if err != nil { + return ResponsePack(berr.INVALID_TRANSACTION) + } + hash := txn.Hash() + log.Debugf("SendRawTransaction recv %s", hash.ToHexString()) + if txn.TxType == types.Invoke || txn.TxType == types.Deploy { + result, err := bactor.PreExecuteContract(txn) + if err != nil { + log.Infof("PreExec: ", err) + return ResponsePack(berr.SMARTCODE_ERROR) + } + res = append(res, result) + } + } + resp := ResponsePack(berr.SUCCESS) + resp["Result"] = res + return resp +} + //get smartcontract event by height func GetSmartCodeEventTxsByHeight(cmd map[string]interface{}) map[string]interface{} { resp := ResponsePack(berr.SUCCESS) diff --git a/http/base/rpc/interfaces.go b/http/base/rpc/interfaces.go index 3731b4b4c5..befd32aacc 100644 --- a/http/base/rpc/interfaces.go +++ b/http/base/rpc/interfaces.go @@ -303,6 +303,39 @@ func SendRawTransaction(params []interface{}) map[string]interface{} { return responseSuccess(hash.ToHexString()) } +// multi pre tx, [tx1, tx2,tx3] +func SendPreTransactions(params []interface{}) map[string]interface{} { + if len(params) < 1 || len(params) > bcomn.MAX_MULTI_TX_SIZE { + return responsePack(berr.INVALID_PARAMS, nil) + } + res := make([]interface{}, 0) + for _, param := range params { + txStr, ok := param.(string) + if !ok { + return responsePack(berr.INVALID_PARAMS, "") + } + raw, err := common.HexToBytes(txStr) + if err != nil { + return responsePack(berr.INVALID_PARAMS, err.Error()) + } + txn, err := types.TransactionFromRawBytes(raw) + if err != nil { + return responsePack(berr.INVALID_TRANSACTION, "") + } + hash := txn.Hash() + log.Debugf("SendRawTransaction recv %s", hash.ToHexString()) + if txn.TxType == types.Invoke || txn.TxType == types.Deploy { + result, err := bactor.PreExecuteContract(txn) + if err != nil { + log.Infof("PreExec: ", err) + return responsePack(berr.SMARTCODE_ERROR, err.Error()) + } + res = append(res, result) + } + } + return responseSuccess(res) +} + //get node version func GetNodeVersion(params []interface{}) map[string]interface{} { return responseSuccess(config.Version) diff --git a/http/jsonrpc/rpc_server.go b/http/jsonrpc/rpc_server.go index e00f9f0149..22775b4363 100644 --- a/http/jsonrpc/rpc_server.go +++ b/http/jsonrpc/rpc_server.go @@ -42,6 +42,7 @@ func StartRPCServer() error { rpc.HandleFunc("getrawtransaction", rpc.GetRawTransaction) rpc.HandleFunc("sendrawtransaction", rpc.SendRawTransaction) + rpc.HandleFunc("sendpretransactions", rpc.SendPreTransactions) rpc.HandleFunc("getstorage", rpc.GetStorage) rpc.HandleFunc("getversion", rpc.GetNodeVersion) rpc.HandleFunc("getnetworkid", rpc.GetNetworkId) diff --git a/http/restful/restful/server.go b/http/restful/restful/server.go index 52240e1d4b..5f38d3c506 100644 --- a/http/restful/restful/server.go +++ b/http/restful/restful/server.go @@ -76,7 +76,8 @@ const ( GET_VERSION = "/api/v1/version" GET_NETWORKID = "/api/v1/networkid" - POST_RAW_TX = "/api/v1/transaction" + POST_RAW_TX = "/api/v1/transaction" + POST_MULTI_RAW_TX = "/api/v1/pretransactions" ) //init restful server @@ -158,7 +159,8 @@ func (this *restServer) registryMethod() { } postMethodMap := map[string]Action{ - POST_RAW_TX: {name: "sendrawtransaction", handler: rest.SendRawTransaction}, + POST_RAW_TX: {name: "sendrawtransaction", handler: rest.SendRawTransaction}, + POST_MULTI_RAW_TX: {name: "sendpretransactions", handler: rest.SendPreTransactions}, } this.postMap = postMethodMap this.getMap = getMethodMap @@ -220,6 +222,8 @@ func (this *restServer) getParams(r *http.Request, url string, req map[string]in req["Hash"], req["Raw"] = getParam(r, "hash"), r.FormValue("raw") case POST_RAW_TX: req["PreExec"] = r.FormValue("preExec") + case POST_MULTI_RAW_TX: + req["PreExec"] = r.FormValue("preExec") case GET_STORAGE: req["Hash"], req["Key"] = getParam(r, "hash"), getParam(r, "key") case GET_SMTCOCE_EVT_TXS: diff --git a/smartcontract/service/neovm/runtime_test.go b/smartcontract/service/neovm/runtime_test.go index 3880d488ad..4e4e31e332 100644 --- a/smartcontract/service/neovm/runtime_test.go +++ b/smartcontract/service/neovm/runtime_test.go @@ -128,7 +128,7 @@ func TestStructRef(t *testing.T) { } func TestRuntimeBase58ToAddress(t *testing.T) { - vm := neovm.NewExecutionEngine() + vm := neovm.NewExecutionEngine(0) acc := account.NewAccount("") addr := acc.Address @@ -152,7 +152,7 @@ func TestRuntimeBase58ToAddress(t *testing.T) { } func TestRuntimeAddressToBase58(t *testing.T) { - vm := neovm.NewExecutionEngine() + vm := neovm.NewExecutionEngine(0) acc := account.NewAccount("") addr := acc.Address diff --git a/smartcontract/smart_contract.go b/smartcontract/smart_contract.go index 95f04b2773..581e852af9 100644 --- a/smartcontract/smart_contract.go +++ b/smartcontract/smart_contract.go @@ -126,6 +126,7 @@ func (this *SmartContract) NewExecuteEngine(code []byte) (context.Engine, error) if !this.checkContexts() { return nil, fmt.Errorf("%s", "engine over max limit!") } + service := &neovm.NeoVmService{ Store: this.Store, CacheDB: this.CacheDB, @@ -135,7 +136,7 @@ func (this *SmartContract) NewExecuteEngine(code []byte) (context.Engine, error) Time: this.Config.Time, Height: this.Config.Height, BlockHash: this.Config.BlockHash, - Engine: vm.NewExecutionEngine(), + Engine: vm.NewExecutionEngine(this.Config.Height), PreExec: this.PreExec, } return service, nil diff --git a/smartcontract/test/height_test.go b/smartcontract/test/height_test.go new file mode 100644 index 0000000000..5a21bca5ab --- /dev/null +++ b/smartcontract/test/height_test.go @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + +package test + +import ( + "github.com/ontio/ontology/smartcontract" + "github.com/ontio/ontology/vm/neovm" + "github.com/ontio/ontology/vm/neovm/errors" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestHeight(t *testing.T) { + byteCode0 := []byte{ + byte(neovm.NEWMAP), + byte(neovm.PUSH0), + byte(neovm.HASKEY), + } + + byteCode1 := []byte{ + byte(neovm.NEWMAP), + byte(neovm.KEYS), + } + + byteCode2 := []byte{ + byte(neovm.NEWMAP), + byte(neovm.VALUES), + } + + bytecode := [...][]byte{byteCode0, byteCode1, byteCode2} + + for i := 0; i < 3; i++ { + config := &smartcontract.Config{ + Time: 10, + Height: 10, + //Tx: &types.Transaction{}, + } + sc := smartcontract.SmartContract{ + Config: config, + Gas: 100, + CacheDB: nil, + } + engine, err := sc.NewExecuteEngine(bytecode[i]) + + _, err = engine.Invoke() + + assert.EqualError(t, err, "[NeoVmService] vm execution error!: "+errors.ERR_NOT_SUPPORT_OPCODE.Error()) + } +} diff --git a/vm/neovm/common_test.go b/vm/neovm/common_test.go index 7b25a32fb2..f35469cc67 100644 --- a/vm/neovm/common_test.go +++ b/vm/neovm/common_test.go @@ -26,7 +26,7 @@ import ( ) func TestHash(t *testing.T) { - engine := NewExecutionEngine() + engine := NewExecutionEngine(0) engine.OpCode = HASH160 data := []byte{1, 2, 3, 4, 5, 6, 7, 8} diff --git a/vm/neovm/execution_engine.go b/vm/neovm/execution_engine.go index 814a20fcb7..fa6173f46a 100644 --- a/vm/neovm/execution_engine.go +++ b/vm/neovm/execution_engine.go @@ -22,12 +22,13 @@ import ( "github.com/ontio/ontology/vm/neovm/errors" ) -func NewExecutionEngine() *ExecutionEngine { +func NewExecutionEngine(BlockHeight uint32) *ExecutionEngine { var engine ExecutionEngine engine.EvaluationStack = NewRandAccessStack() engine.AltStack = NewRandAccessStack() engine.State = BREAK engine.OpCode = 0 + engine.BlockHeight = BlockHeight return &engine } @@ -37,6 +38,7 @@ type ExecutionEngine struct { State VMState Contexts []*ExecutionContext Context *ExecutionContext + BlockHeight uint32 OpCode OpCode OpExec OpExec } diff --git a/vm/neovm/func_array.go b/vm/neovm/func_array.go index c41ffaf3ec..5e9f5073d2 100644 --- a/vm/neovm/func_array.go +++ b/vm/neovm/func_array.go @@ -87,7 +87,7 @@ func opPickItem(e *ExecutionEngine) (VMState, error) { PushData(e, s[i]) case *types.Map: PushData(e, items.(*types.Map).TryGetValue(index)) - case *types.ByteArray: + default: bi, _ := index.GetBigInteger() i := int(bi.Int64()) a, _ := items.GetByteArray() diff --git a/vm/neovm/func_validate.go b/vm/neovm/func_validate.go index 3ba7639017..d2987b34f4 100644 --- a/vm/neovm/func_validate.go +++ b/vm/neovm/func_validate.go @@ -26,6 +26,7 @@ import ( "fmt" "github.com/ontio/ontology/common" + "github.com/ontio/ontology/common/config" "github.com/ontio/ontology/vm/neovm/errors" "github.com/ontio/ontology/vm/neovm/types" ) @@ -480,7 +481,7 @@ func validatePickItem(e *ExecutionEngine) error { if v := item.(*types.Map).TryGetValue(key); v == nil { return errors.ERR_MAP_NOT_EXIST } - case *types.ByteArray: + default: index, err := PeekBigInteger(e) if err != nil { return err @@ -495,8 +496,6 @@ func validatePickItem(e *ExecutionEngine) error { if index.Cmp(big.NewInt(int64(len(barr)))) >= 0 { return errors.ERR_OVER_MAX_ARRAY_SIZE } - default: - return fmt.Errorf("validatePickItem error: %s", errors.ERR_NOT_SUPPORT_TYPE) } return nil } @@ -670,6 +669,11 @@ func LogStackTrace(e *ExecutionEngine, needStackCount int, desc string) error { } func validatorHasKey(e *ExecutionEngine) error { + OpCodeUpdateHeight := config.GetOpcodeUpdateCheckHeight(config.DefConfig.P2PNode.NetworkId) + if e.BlockHeight <= OpCodeUpdateHeight { + return errors.ERR_NOT_SUPPORT_OPCODE + } + if err := LogStackTrace(e, 2, "[validatorHasKey]"); err != nil { return err } @@ -682,6 +686,11 @@ func validatorHasKey(e *ExecutionEngine) error { } func validatorKeys(e *ExecutionEngine) error { + OpCodeUpdateHeight := config.GetOpcodeUpdateCheckHeight(config.DefConfig.P2PNode.NetworkId) + if e.BlockHeight <= OpCodeUpdateHeight { + return errors.ERR_NOT_SUPPORT_OPCODE + } + if err := LogStackTrace(e, 1, "[validatorKeys]"); err != nil { return err } @@ -690,6 +699,11 @@ func validatorKeys(e *ExecutionEngine) error { } func validatorValues(e *ExecutionEngine) error { + OpCodeUpdateHeight := config.GetOpcodeUpdateCheckHeight(config.DefConfig.P2PNode.NetworkId) + if e.BlockHeight <= OpCodeUpdateHeight { + return errors.ERR_NOT_SUPPORT_OPCODE + } + if err := LogStackTrace(e, 1, "[validatorValues]"); err != nil { return err } @@ -698,6 +712,11 @@ func validatorValues(e *ExecutionEngine) error { } func validateDCALL(e *ExecutionEngine) error { + OpCodeUpdateHeight := config.GetOpcodeUpdateCheckHeight(config.DefConfig.P2PNode.NetworkId) + if e.BlockHeight <= OpCodeUpdateHeight { + return errors.ERR_NOT_SUPPORT_OPCODE + } + if err := LogStackTrace(e, 1, "[validatorValues]"); err != nil { return err }