From 5bc1bfeaaef0c4d3a580aac973edff75cf358d39 Mon Sep 17 00:00:00 2001 From: tanyuan <1067598718@qq.com> Date: Mon, 25 Jun 2018 16:37:09 +0800 Subject: [PATCH] Add refresh gas table (#410) --- cmd/utils/flags.go | 2 +- core/genesis/genesis.go | 4 ++ core/store/ledgerstore/ledger_store.go | 17 ++++++- core/store/ledgerstore/tx_handler.go | 49 ++++++++++++++++++- .../native/global_params/global_params.go | 2 +- smartcontract/service/neovm/config.go | 28 +++++++++-- smartcontract/service/neovm/gas_cost.go | 4 +- smartcontract/service/neovm/storage.go | 12 +++-- 8 files changed, 103 insertions(+), 15 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index cc8c87bf..49f20f53 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -354,7 +354,7 @@ var ( TransactionGasLimitFlag = cli.Uint64Flag{ Name: "gaslimit", Usage: "Using to specifies the gas limit of the transaction. The gas limit of the transaction cannot be less than the minimum gas limit set by the node's transaction pool, otherwise the transaction will be rejected. Gasprice * gaslimit is actual ONG costs.", - Value: neovm.TRANSACTION_GAS, + Value: neovm.MIN_TRANSACTION_GAS, } //Asset setting diff --git a/core/genesis/genesis.go b/core/genesis/genesis.go index 4020c078..9c8c01dc 100644 --- a/core/genesis/genesis.go +++ b/core/genesis/genesis.go @@ -34,6 +34,7 @@ import ( "github.com/ontio/ontology/smartcontract/service/native/governance" "github.com/ontio/ontology/smartcontract/service/native/ont" nutils "github.com/ontio/ontology/smartcontract/service/native/utils" + "github.com/ontio/ontology/smartcontract/service/neovm" ) const ( @@ -180,6 +181,9 @@ func newParamInit() *types.Transaction { for k, v := range INIT_PARAM { params.SetParam(&global_params.Param{k, v}) } + for k, v := range neovm.GAS_TABLE { + params.SetParam(&global_params.Param{k, string(v)}) + } bf := new(bytes.Buffer) params.Serialize(bf) diff --git a/core/store/ledgerstore/ledger_store.go b/core/store/ledgerstore/ledger_store.go index 8c9a9d1a..de5edf9b 100644 --- a/core/store/ledgerstore/ledger_store.go +++ b/core/store/ledgerstore/ledger_store.go @@ -488,6 +488,18 @@ func (this *LedgerStoreImp) saveBlockToStateStore(block *types.Block) error { stateBatch := this.stateStore.NewStateBatch() + if block.Header.Height != 0 { + config := &smartcontract.Config{ + Time: block.Header.Timestamp, + Height: block.Header.Height, + Tx: &types.Transaction{}, + } + + if err := refreshGlobalParam(config, storage.NewCloneCache(this.stateStore.NewStateBatch()), this); err != nil { + return err + } + } + for _, tx := range block.Transactions { err := this.handleTransaction(stateBatch, block, tx) if err != nil { @@ -791,8 +803,9 @@ func (this *LedgerStoreImp) PreExecuteContract(tx *types.Transaction) (*sstate.P return nil, err } gasCost := math.MaxUint64 - sc.Gas - if gasCost < neovm.TRANSACTION_GAS { - gasCost = neovm.TRANSACTION_GAS + mixGas := neovm.MIN_TRANSACTION_GAS + if gasCost < mixGas { + gasCost = mixGas } if err != nil { return &sstate.PreExecResult{State: event.CONTRACT_STATE_FAIL, Gas: gasCost, Result: nil}, err diff --git a/core/store/ledgerstore/tx_handler.go b/core/store/ledgerstore/tx_handler.go index c9502bd3..81b5e659 100644 --- a/core/store/ledgerstore/tx_handler.go +++ b/core/store/ledgerstore/tx_handler.go @@ -22,6 +22,7 @@ import ( "bytes" "fmt" "math" + "strconv" "github.com/ontio/ontology/common" "github.com/ontio/ontology/common/config" @@ -35,6 +36,7 @@ import ( "github.com/ontio/ontology/core/types" "github.com/ontio/ontology/smartcontract" "github.com/ontio/ontology/smartcontract/event" + "github.com/ontio/ontology/smartcontract/service/native/global_params" ninit "github.com/ontio/ontology/smartcontract/service/native/init" "github.com/ontio/ontology/smartcontract/service/native/ont" "github.com/ontio/ontology/smartcontract/service/native/utils" @@ -118,6 +120,7 @@ func (self *StateStore) HandleInvokeTransaction(store store.LedgerStore, stateBa } cache := storage.NewCloneCache(stateBatch) + //init smart contract info sc := smartcontract.SmartContract{ Config: config, @@ -140,8 +143,9 @@ func (self *StateStore) HandleInvokeTransaction(store store.LedgerStore, stateBa var notifies []*event.NotifyEventInfo if isCharge { totalGas := tx.GasLimit - sc.Gas - if totalGas < neovm.TRANSACTION_GAS { - totalGas = neovm.TRANSACTION_GAS + mixGas := neovm.MIN_TRANSACTION_GAS + if totalGas < mixGas { + totalGas = mixGas } notifies, err = costGas(tx.Payer, gas, config, sc.CloneCache, store) if err != nil { @@ -212,6 +216,47 @@ func costGas(payer common.Address, gas uint64, config *smartcontract.Config, return sc.Notifications, nil } +func refreshGlobalParam(config *smartcontract.Config, cache *storage.CloneCache, store store.LedgerStore) error { + bf := new(bytes.Buffer) + if err := utils.WriteVarUint(bf, uint64(len(neovm.GAS_TABLE_KEYS))); err != nil { + return fmt.Errorf("write gas_table_keys length error:%s", err) + } + for _, value := range neovm.GAS_TABLE_KEYS { + if err := serialization.WriteString(bf, value); err != nil { + return fmt.Errorf("serialize param name error:%s", value) + } + } + + sc := smartcontract.SmartContract{ + Config: config, + CloneCache: cache, + Store: store, + Gas: math.MaxUint64, + } + + service, _ := sc.NewNativeService() + result, err := service.NativeCall(utils.ParamContractAddress, "getGlobalParam", bf.Bytes()) + if err != nil { + return err + } + params := new(global_params.Params) + if err := params.Deserialize(bytes.NewBuffer(result.([]byte))); err != nil { + fmt.Errorf("deserialize global params error:%s", err) + } + + for k, _ := range neovm.GAS_TABLE { + n, ps := params.GetParam(k) + if n != -1 && ps.Value != "" { + pu, err := strconv.ParseUint(ps.Value, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse uint %v", err) + } + neovm.GAS_TABLE[k] = pu + } + } + return nil +} + func getBalance(stateBatch *statestore.StateBatch, address, contract common.Address) (uint64, error) { bl, err := stateBatch.TryGet(scommon.ST_STORAGE, append(contract[:], address[:]...)) if err != nil { diff --git a/smartcontract/service/native/global_params/global_params.go b/smartcontract/service/native/global_params/global_params.go index 348569a8..0b0ff8e1 100644 --- a/smartcontract/service/native/global_params/global_params.go +++ b/smartcontract/service/native/global_params/global_params.go @@ -219,7 +219,7 @@ func GetGlobalParam(native *native.NativeService) ([]byte, error) { if index, value := storageParams.GetParam(paramName); index >= 0 { params.SetParam(value) } else { - return utils.BYTE_FALSE, errors.NewErr(fmt.Sprintf("get param, param %v doesn't exist!", paramName)) + params.SetParam(&Param{Key: paramName, Value: ""}) } } err = params.Serialize(result) diff --git a/smartcontract/service/neovm/config.go b/smartcontract/service/neovm/config.go index 6d70772a..fcab49e5 100644 --- a/smartcontract/service/neovm/config.go +++ b/smartcontract/service/neovm/config.go @@ -20,13 +20,13 @@ package neovm var ( //Gas Limit - TRANSACTION_GAS uint64 = 30000 // Per transaction base cost. + MIN_TRANSACTION_GAS uint64 = 20000 // Per transaction base cost. BLOCKCHAIN_GETHEADER_GAS uint64 = 100 BLOCKCHAIN_GETBLOCK_GAS uint64 = 200 BLOCKCHAIN_GETTRANSACTION_GAS uint64 = 100 BLOCKCHAIN_GETCONTRACT_GAS uint64 = 100 - CONTRACT_CREATE_GAS uint64 = 10000000 - CONTRACT_MIGRATE_GAS uint64 = 10000000 + CONTRACT_CREATE_GAS uint64 = 20000000 + CONTRACT_MIGRATE_GAS uint64 = 20000000 NATIVE_INVOKE_GAS uint64 = 10000 STORAGE_GET_GAS uint64 = 100 STORAGE_PUT_GAS uint64 = 1000 @@ -42,6 +42,7 @@ var ( METHOD_LENGTH_LIMIT int = 1024 MAX_STACK_SIZE int = 1024 + VM_STEP_LIMIT int = 400000 // API Name ATTRIBUTE_GETUSAGE_NAME = "Ontology.Attribute.GetUsage" @@ -126,5 +127,24 @@ var ( HASH256_NAME: HASH256_GAS, } - VM_STEP_LIMIT = 400000 + GAS_TABLE_KEYS = []string{ + BLOCKCHAIN_GETHEADER_NAME, + BLOCKCHAIN_GETBLOCK_NAME, + BLOCKCHAIN_GETTRANSACTION_NAME, + BLOCKCHAIN_GETCONTRACT_NAME, + CONTRACT_CREATE_NAME, + CONTRACT_MIGRATE_NAME, + STORAGE_GET_NAME, + STORAGE_PUT_NAME, + STORAGE_DELETE_NAME, + RUNTIME_CHECKWITNESS_NAME, + NATIVE_INVOKE_NAME, + APPCALL_NAME, + APPCALL_NAME, + TAILCALL_NAME, + SHA1_NAME, + SHA256_NAME, + HASH160_NAME, + HASH256_NAME, + } ) diff --git a/smartcontract/service/neovm/gas_cost.go b/smartcontract/service/neovm/gas_cost.go index 8880c38c..56749f53 100644 --- a/smartcontract/service/neovm/gas_cost.go +++ b/smartcontract/service/neovm/gas_cost.go @@ -23,11 +23,11 @@ import ( ) func StoreGasCost(engine *vm.ExecutionEngine) (uint64, error) { - key, err := vm.PeekNByteArray(0, engine) + key, err := vm.PeekNByteArray(1, engine) if err != nil { return 0, err } - value, err := vm.PeekNByteArray(1, engine) + value, err := vm.PeekNByteArray(2, engine) if err != nil { return 0, err } diff --git a/smartcontract/service/neovm/storage.go b/smartcontract/service/neovm/storage.go index be497725..c2d4c40b 100644 --- a/smartcontract/service/neovm/storage.go +++ b/smartcontract/service/neovm/storage.go @@ -31,6 +31,9 @@ import ( // StoragePut put smart contract storage item to cache func StoragePut(service *NeoVmService, engine *vm.ExecutionEngine) error { + if vm.EvaluationStackCount(engine) < 3 { + return errors.NewErr("[Context] Too few input parameters ") + } context, err := getContext(engine) if err != nil { return errors.NewDetailErr(err, errors.ErrNoCode, "[StoragePut] get pop context error!") @@ -60,6 +63,9 @@ func StoragePut(service *NeoVmService, engine *vm.ExecutionEngine) error { // StorageDelete delete smart contract storage item from cache func StorageDelete(service *NeoVmService, engine *vm.ExecutionEngine) error { + if vm.EvaluationStackCount(engine) < 2 { + return errors.NewErr("[Context] Too few input parameters ") + } context, err := getContext(engine) if err != nil { return errors.NewDetailErr(err, errors.ErrNoCode, "[StorageDelete] get pop context error!") @@ -81,6 +87,9 @@ func StorageDelete(service *NeoVmService, engine *vm.ExecutionEngine) error { // StorageGet push smart contract storage item from cache to vm stack func StorageGet(service *NeoVmService, engine *vm.ExecutionEngine) error { + if vm.EvaluationStackCount(engine) < 2 { + return errors.NewErr("[Context] Too few input parameters ") + } context, err := getContext(engine) if err != nil { return errors.NewDetailErr(err, errors.ErrNoCode, "[StorageGet] get pop context error!") @@ -124,9 +133,6 @@ func checkStorageContext(service *NeoVmService, context *StorageContext) error { } func getContext(engine *vm.ExecutionEngine) (*StorageContext, error) { - if vm.EvaluationStackCount(engine) < 2 { - return nil, errors.NewErr("[Context] Too few input parameters ") - } opInterface, err := vm.PopInteropInterface(engine) if err != nil { return nil, err