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/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/smartcontract/service/neovm/config.go b/smartcontract/service/neovm/config.go index 6c0f3ecd9d..3ba30ffb63 100644 --- a/smartcontract/service/neovm/config.go +++ b/smartcontract/service/neovm/config.go @@ -37,15 +37,18 @@ var ( STORAGE_DELETE_GAS uint64 = 100 RUNTIME_CHECKWITNESS_GAS uint64 = 200 RUNTIME_VERIFYMUTISIG_GAS uint64 = 400 - RUNTIME_ADDRESSTOBASE58_GAS uint64 = 40 - RUNTIME_BASE58TOADDRESS_GAS uint64 = 30 - APPCALL_GAS uint64 = 10 - TAILCALL_GAS uint64 = 10 - SHA1_GAS uint64 = 10 - SHA256_GAS uint64 = 10 - HASH160_GAS uint64 = 20 - HASH256_GAS uint64 = 20 - OPCODE_GAS uint64 = 1 + RUNTIME_JSON_MARSHAL_GAS uint64 = 400 + RUNTIME_JSON_UNMARSHAL_GAS uint64 = 400 + + RUNTIME_ADDRESSTOBASE58_GAS uint64 = 40 + RUNTIME_BASE58TOADDRESS_GAS uint64 = 30 + APPCALL_GAS uint64 = 10 + TAILCALL_GAS uint64 = 10 + SHA1_GAS uint64 = 10 + SHA256_GAS uint64 = 10 + HASH160_GAS uint64 = 20 + HASH256_GAS uint64 = 20 + OPCODE_GAS uint64 = 1 PER_UNIT_CODE_LEN int = 1024 METHOD_LENGTH_LIMIT int = 1024 @@ -104,6 +107,8 @@ var ( RUNTIME_ADDRESSTOBASE58_NAME = "Ontology.Runtime.AddressToBase58" RUNTIME_GETCURRENTBLOCKHASH_NAME = "Ontology.Runtime.GetCurrentBlockHash" RUNTIME_VERIFYMUTISIG_NAME = "Ontology.Runtime.VerifyMutiSig" + RUNTIME_JSON_MARSHAL_NAME = "Ontology.Runtime.JsonMarshal" + RUNTIME_JSON_UNMARSHAL_NAME = "Ontology.Runtime.JsonUnmarshal" NATIVE_INVOKE_NAME = "Ontology.Native.Invoke" @@ -195,5 +200,8 @@ func initGAS_TABLE() *sync.Map { m.Store(RUNTIME_VERIFYMUTISIG_NAME, RUNTIME_VERIFYMUTISIG_GAS) + m.Store(RUNTIME_JSON_MARSHAL_NAME, RUNTIME_JSON_MARSHAL_GAS) + m.Store(RUNTIME_JSON_UNMARSHAL_NAME, RUNTIME_JSON_UNMARSHAL_GAS) + return &m } diff --git a/smartcontract/service/neovm/neovm_service.go b/smartcontract/service/neovm/neovm_service.go index 8b4ea20554..445d443460 100644 --- a/smartcontract/service/neovm/neovm_service.go +++ b/smartcontract/service/neovm/neovm_service.go @@ -74,6 +74,8 @@ var ( RUNTIME_SERIALIZE_NAME: {Execute: RuntimeSerialize, Validator: validatorSerialize}, RUNTIME_DESERIALIZE_NAME: {Execute: RuntimeDeserialize, Validator: validatorDeserialize}, RUNTIME_VERIFYMUTISIG_NAME: {Execute: RuntimeVerifyMutiSig}, + RUNTIME_JSON_MARSHAL_NAME: {Execute: RuntimeJsonMarshal}, + RUNTIME_JSON_UNMARSHAL_NAME: {Execute: RuntimeJsonUnmarshal}, NATIVE_INVOKE_NAME: {Execute: NativeInvoke}, STORAGE_GET_NAME: {Execute: StorageGet}, STORAGE_PUT_NAME: {Execute: StoragePut}, diff --git a/smartcontract/service/neovm/runtime.go b/smartcontract/service/neovm/runtime.go index 820a55c7f1..a4eabc74ad 100644 --- a/smartcontract/service/neovm/runtime.go +++ b/smartcontract/service/neovm/runtime.go @@ -24,6 +24,7 @@ import ( "reflect" "sort" + "encoding/json" "github.com/ontio/ontology-crypto/keypair" "github.com/ontio/ontology/common" "github.com/ontio/ontology/common/serialization" @@ -34,8 +35,15 @@ import ( "github.com/ontio/ontology/smartcontract/event" vm "github.com/ontio/ontology/vm/neovm" vmtypes "github.com/ontio/ontology/vm/neovm/types" + "math/big" ) +//allow json depth +var JSON_DEPTH = 10 + +//max json string length +var MAX_JSONBYTES_LENGTH = 1024 + // HeaderGetNextConsensus put current block time to vm stack func RuntimeGetTime(service *NeoVmService, engine *vm.ExecutionEngine) error { vm.PushData(engine, int(service.Time)) @@ -212,6 +220,251 @@ func RuntimeGetCurrentBlockHash(service *NeoVmService, engine *vm.ExecutionEngin return nil } +func RuntimeJsonMarshal(service *NeoVmService, engine *vm.ExecutionEngine) error { + if vm.EvaluationStackCount(engine) < 1 { + return errors.NewErr("[RuntimeJsonMarshal] Too few input parameters") + } + item := vm.PopStackItem(engine) + + m := make(map[string]interface{}) + err := StackitemToMap(item, m, 0) + if err != nil { + return err + } + res, err := json.Marshal(m) + if err != nil { + return err + } + vm.PushData(engine, []byte(res)) + return nil + +} + +func RuntimeJsonUnmarshal(service *NeoVmService, engine *vm.ExecutionEngine) error { + if vm.EvaluationStackCount(engine) < 1 { + return errors.NewErr("[RuntimeJsonUnmarshal] Too few input parameters") + } + + jsonbytes, err := vm.PopByteArray(engine) + if err != nil { + return err + } + if len(jsonbytes) > MAX_JSONBYTES_LENGTH { + return errors.NewErr("[RuntimeJsonUnmarshal] Input Json bytes too long") + } + + m := make(map[string]interface{}) + err = json.Unmarshal(jsonbytes, &m) + if err != nil { + return err + } + + mapitem := vmtypes.NewMap() + err = MapToStackitem(m, *mapitem) + if err != nil { + return err + } + vm.PushData(engine, mapitem) + + return nil +} + +func MapToStackitem(m map[string]interface{}, mapitem vmtypes.Map) error { + + for k, v := range m { + vi, err := makeStackItem(v) + if err != nil { + return err + } + key := vmtypes.NewByteArray([]byte(k)) + mapitem.Add(key, vi) + } + return nil + +} + +func ArrayToStackItem(arr []interface{}, arritem *vmtypes.Array) error { + + for _, v := range arr { + vi, err := makeStackItem(v) + if err != nil { + return err + } + arritem.Add(vi) + } + return nil + +} + +func makeStackItem(v interface{}) (vmtypes.StackItems, error) { + switch v.(type) { + case []byte: + return vmtypes.NewByteArray(v.([]byte)), nil + + case string: + return vmtypes.NewByteArray([]byte(v.(string))), nil + + case float64: + return vmtypes.NewInteger(big.NewInt(int64(v.(float64)))), nil + + case bool: + return vmtypes.NewBoolean(v.(bool)), nil + + case map[string]interface{}: + item := vmtypes.NewMap() + err := MapToStackitem(v.(map[string]interface{}), *item) + if err != nil { + return nil, err + } + return item, nil + + case []interface{}: + item := vmtypes.NewArray(nil) + err := ArrayToStackItem(v.([]interface{}), item) + if err != nil { + return nil, err + } + return item, nil + + default: + return nil, errors.NewErr("not supported type") + } +} + +func StackitemToMap(item vmtypes.StackItems, m map[string]interface{}, depth int) error { + + depth, err := checkDepth(depth) + if err != nil { + return err + } + + itemMap, err := item.GetMap() + if err != nil { + return err + } + + for k, v := range itemMap { + switch k.(type) { + case *vmtypes.ByteArray: + key, err := k.GetByteArray() + if err != nil { + return err + } + switch v.(type) { + case *vmtypes.ByteArray: + val, err := v.GetByteArray() + if err != nil { + return err + } + m[string(key)] = string(val) + case *vmtypes.Integer, *vmtypes.Boolean: + val, err := v.GetByteArray() + if err != nil { + return err + } + m[string(key)] = common.ToHexString(val) + case *vmtypes.Array: + arr, err := v.GetArray() + if err != nil { + return err + } + err = StackitemArrayToMap(arr, m, string(key), depth) + if err != nil { + return err + } + case *vmtypes.Map: + tmp := make(map[string]interface{}) + m[string(key)] = tmp + err := StackitemToMap(v, tmp, depth) + if err != nil { + return err + } + default: + return errors.NewErr("Not support json value type") + } + + default: + return errors.NewErr("Not support json key type") + } + + } + return nil +} + +func StackitemArrayToMap(items []vmtypes.StackItems, m map[string]interface{}, key string, depth int) error { + depth, err := checkDepth(depth) + if err != nil { + return err + } + + tmparr := make([]interface{}, len(items)) + m[key] = tmparr + for i, v := range items { + switch v.(type) { + case *vmtypes.Array: + arr, err := v.GetArray() + if err != nil { + return err + } + subarr := make([]interface{}, len(arr)) + tmparr[i] = subarr + err = StackitemArrayToArray(arr, subarr, depth) + if err != nil { + return err + } + case *vmtypes.Map: + tmp := make(map[string]interface{}) + tmparr[i] = tmp + err = StackitemToMap(v, tmp, depth) + if err != nil { + return err + } + default: + return errors.NewErr("Not a supported type") + } + } + return nil +} + +func StackitemArrayToArray(items []vmtypes.StackItems, arr []interface{}, depth int) error { + depth, err := checkDepth(depth) + if err != nil { + return err + } + for i, item := range items { + switch item.(type) { + case *vmtypes.Map: + m := make(map[string]interface{}) + arr[i] = m + err = StackitemToMap(item, m, depth) + if err != nil { + return err + } + case *vmtypes.Array: + arritem, err := item.GetArray() + if err != nil { + return err + } + tmparr := make([]interface{}, len(arritem)) + arr[i] = tmparr + err = StackitemArrayToArray(arritem, tmparr, depth) + if err != nil { + return err + } + default: + return errors.NewErr("Not a supported type") + } + } + return nil +} + +func checkDepth(depth int) (int, error) { + if depth >= JSON_DEPTH { + return -1, errors.NewErr("json depth exceed!") + } + return depth + 1, nil +} + func SerializeStackItem(item vmtypes.StackItems) ([]byte, error) { if CircularRefAndDepthDetection(item) { return nil, errors.NewErr("runtime serialize: can not serialize circular reference data") diff --git a/smartcontract/service/neovm/runtime_test.go b/smartcontract/service/neovm/runtime_test.go index 3880d488ad..cb2d5ed4ca 100644 --- a/smartcontract/service/neovm/runtime_test.go +++ b/smartcontract/service/neovm/runtime_test.go @@ -23,7 +23,9 @@ import ( "math/big" "testing" + "encoding/json" "errors" + "fmt" "github.com/ontio/ontology/account" "github.com/ontio/ontology/vm/neovm" "github.com/ontio/ontology/vm/neovm/types" @@ -128,7 +130,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 +154,7 @@ func TestRuntimeBase58ToAddress(t *testing.T) { } func TestRuntimeAddressToBase58(t *testing.T) { - vm := neovm.NewExecutionEngine() + vm := neovm.NewExecutionEngine(0) acc := account.NewAccount("") addr := acc.Address @@ -175,3 +177,118 @@ func TestRuntimeAddressToBase58(t *testing.T) { assert.NoError(t, err) assert.Equal(t, base58, string(result)) } + +func TestRuntimeJsonMashalMap(t *testing.T) { + key := types.NewByteArray([]byte("keys")) + val := types.NewInteger(big.NewInt(123)) + item := types.NewMap() + item.Add(key, val) + + item2 := types.NewMap() + item2.Add(types.NewByteArray([]byte("keys2")), types.NewByteArray([]byte("values2"))) + + item.Add(types.NewByteArray([]byte("mkey")), item2) + + item3 := types.NewMap() + item3.Add(types.NewByteArray([]byte("keys3")), types.NewByteArray([]byte("values3"))) + + item4 := types.NewMap() + item4.Add(types.NewByteArray([]byte("keys4")), types.NewByteArray([]byte("values4"))) + arr := types.NewArray([]types.StackItems{item3, item4}) + + item.Add(types.NewByteArray([]byte("arraykey")), arr) + + item5 := types.NewMap() + item5.Add(types.NewByteArray([]byte("keys5")), types.NewByteArray([]byte("values5"))) + + iarr1 := types.NewArray([]types.StackItems{item5}) + + item6 := types.NewMap() + item6.Add(types.NewByteArray([]byte("keys6")), types.NewByteArray([]byte("values6"))) + + iarr2 := types.NewArray([]types.StackItems{item6}) + + iarr3 := types.NewArray([]types.StackItems{iarr1, iarr2}) + + item.Add(types.NewByteArray([]byte("bigarr")), iarr3) + m := make(map[string]interface{}) + err := StackitemToMap(item, m, 0) + assert.NoError(t, err) + + res, err := json.Marshal(m) + assert.NoError(t, err) + + assert.Equal(t, res, []byte(`{"arraykey":[{"keys3":"values3"},{"keys4":"values4"}],"bigarr":[[{"keys5":"values5"}],[{"keys6":"values6"}]],"keys":"7b","mkey":{"keys2":"values2"}}`)) +} + +func TestRuntimeJsonUnmarshal(t *testing.T) { + fmt.Println("===test simple json") + json1 := []byte(`{"key1":"value1"}`) + m := make(map[string]interface{}) + err := json.Unmarshal(json1, &m) + assert.Nil(t, err) + + mapitem := types.NewMap() + err = MapToStackitem(m, *mapitem) + assert.Nil(t, err) + + key := types.NewByteArray([]byte("key1")) + val := mapitem.TryGetValue(key) + valbytes, _ := val.GetByteArray() + assert.Equal(t, valbytes, []byte("value1")) + + fmt.Println("===test simple json: int value") + + json2 := []byte(`{"key1":100}`) + m = make(map[string]interface{}) + err = json.Unmarshal(json2, &m) + assert.Nil(t, err) + mapitem = types.NewMap() + err = MapToStackitem(m, *mapitem) + assert.Nil(t, err) + + key = types.NewByteArray([]byte("key1")) + val = mapitem.TryGetValue(key) + valint, _ := val.GetBigInteger() + assert.Equal(t, valint.Int64(), int64(100)) + + fmt.Println("===test simple json: int value") + json3 := []byte(`{"key1":"value1","key2":100}`) + m = make(map[string]interface{}) + err = json.Unmarshal(json3, &m) + assert.Nil(t, err) + mapitem = types.NewMap() + err = MapToStackitem(m, *mapitem) + assert.Nil(t, err) + key1 := types.NewByteArray([]byte("key1")) + val1 := mapitem.TryGetValue(key1) + valbytes, _ = val1.GetByteArray() + assert.Equal(t, valbytes, []byte("value1")) + + key2 := types.NewByteArray([]byte("key2")) + val2 := mapitem.TryGetValue(key2) + valint, _ = val2.GetBigInteger() + assert.Equal(t, valint.Int64(), int64(100)) + + fmt.Println("===test simple json: array value") + json4 := []byte(`{"arr1":[{"key1":"value1"},{"key2":100}]}`) + m = make(map[string]interface{}) + err = json.Unmarshal(json4, &m) + assert.Nil(t, err) + mapitem = types.NewMap() + err = MapToStackitem(m, *mapitem) + + assert.Nil(t, err) + + keyarr := types.NewByteArray([]byte("arr1")) + arrval := mapitem.TryGetValue(keyarr) + arritem, _ := arrval.GetArray() + assert.Equal(t, len(arritem), 2) + tmpmap1, _ := arritem[0].(*types.Map) + val1bytes, _ := tmpmap1.TryGetValue(key1).GetByteArray() + assert.Equal(t, val1bytes, []byte("value1")) + tmpmap2, _ := arritem[1].(*types.Map) + val2int, _ := tmpmap2.TryGetValue(key2).GetBigInteger() + assert.Equal(t, val2int.Int64(), int64(100)) + +} 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 }