Skip to content

Commit

Permalink
add invoke and deploy gas cost by code length (#435)
Browse files Browse the repository at this point in the history
* add invoke and deploy gas cost by code length

* gofmt

* update gas code length cost

* optimize code

* fix vm execute ingore cost gas

* optimize code

* fix deploy and invoke gas bug

* optimize contract execute less than min transaction gas

* fix get ong from db bug

* go fmt.

Signed-off-by: luodanwg <[email protected]>
  • Loading branch information
tanZiWen authored and Arbio5zt committed Jun 27, 2018
1 parent 31dcf5e commit 5aec5da
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 100 deletions.
122 changes: 89 additions & 33 deletions core/store/ledgerstore/ledger_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,19 @@
package ledgerstore

import (
"bytes"
"fmt"
"math"
"os"
"sort"
"strings"
"sync"

"github.com/ontio/ontology-crypto/keypair"
"github.com/ontio/ontology/common"
"github.com/ontio/ontology/common/config"
"github.com/ontio/ontology/common/log"
"github.com/ontio/ontology/common/serialization"
"github.com/ontio/ontology/core/payload"
"github.com/ontio/ontology/core/signature"
"github.com/ontio/ontology/core/states"
Expand All @@ -36,14 +44,12 @@ import (
"github.com/ontio/ontology/smartcontract"
scommon "github.com/ontio/ontology/smartcontract/common"
"github.com/ontio/ontology/smartcontract/event"
"github.com/ontio/ontology/smartcontract/service/native/global_params"
"github.com/ontio/ontology/smartcontract/service/native/utils"
"github.com/ontio/ontology/smartcontract/service/neovm"
sstate "github.com/ontio/ontology/smartcontract/states"
"github.com/ontio/ontology/smartcontract/storage"
"math"
"os"
"sort"
"strings"
"sync"
"strconv"
)

const (
Expand Down Expand Up @@ -623,7 +629,6 @@ func (this *LedgerStoreImp) handleTransaction(stateBatch *statestore.StateBatch,
if err != nil {
if stateBatch.Error() == nil {
log.Debugf("HandleDeployTransaction tx %x error %s", txHash, err)
SaveNotify(this.eventStore, txHash, []*event.NotifyEventInfo{}, false)
} else {
return fmt.Errorf("HandleDeployTransaction tx %x error %s", txHash, stateBatch.Error())
}
Expand All @@ -633,7 +638,6 @@ func (this *LedgerStoreImp) handleTransaction(stateBatch *statestore.StateBatch,
if err != nil {
if stateBatch.Error() == nil {
log.Debugf("HandleInvokeTransaction tx %x error %s", txHash, err)
SaveNotify(this.eventStore, txHash, []*event.NotifyEventInfo{}, false)
} else {
return fmt.Errorf("HandleInvokeTransaction tx %x error %s", txHash, stateBatch.Error())
}
Expand Down Expand Up @@ -765,52 +769,104 @@ func (this *LedgerStoreImp) GetEventNotifyByBlock(height uint32) ([]*event.Execu

//PreExecuteContract return the result of smart contract execution without commit to store
func (this *LedgerStoreImp) PreExecuteContract(tx *types.Transaction) (*sstate.PreExecResult, error) {
if tx.TxType != types.Invoke {
return nil, errors.NewErr("transaction type error")
}

invoke, ok := tx.Payload.(*payload.InvokeCode)
if !ok {
return nil, errors.NewErr("transaction type error")
}

header, err := this.GetHeaderByHeight(this.GetCurrentBlockHeight())
if err != nil {
return nil, errors.NewDetailErr(err, errors.ErrNoCode, "[PreExecuteContract] Get current block error!")
}
// init smart contract configuration info

config := &smartcontract.Config{
Time: header.Timestamp,
Height: header.Height,
Tx: tx,
}

//init smart contract info
cache := storage.NewCloneCache(this.stateStore.NewStateBatch())
preGas, err := this.getPreGas(config, cache)
if err != nil {
return nil, err
}

if tx.TxType == types.Invoke {
invoke, ok := tx.Payload.(*payload.InvokeCode)
if !ok {
return nil, errors.NewErr("transaction payload not invokeCode!")
}

sc := smartcontract.SmartContract{
Config: config,
Store: this,
CloneCache: cache,
Gas: math.MaxUint64 - calcGasByCodeLen(len(invoke.Code), preGas[neovm.UINT_INVOKE_CODE_LEN_NAME]),
}

//start the smart contract executive function
engine, err := sc.NewExecuteEngine(invoke.Code)
if err != nil {
return nil, err
}
result, err := engine.Invoke()
if err != nil {
return nil, err
}
gasCost := math.MaxUint64 - sc.Gas
mixGas := neovm.MIN_TRANSACTION_GAS
if gasCost < mixGas {
gasCost = mixGas
}
return &sstate.PreExecResult{State: event.CONTRACT_STATE_SUCCESS, Gas: gasCost, Result: scommon.ConvertNeoVmTypeHexString(result)}, nil
} else if tx.TxType == types.Deploy {
deploy, ok := tx.Payload.(*payload.DeployCode)
if !ok {
return nil, errors.NewErr("transaction payload not deployCode!")
}

return &sstate.PreExecResult{State: event.CONTRACT_STATE_SUCCESS, Gas: preGas[neovm.CONTRACT_CREATE_NAME] + calcGasByCodeLen(len(deploy.Code), preGas[neovm.UINT_DEPLOY_CODE_LEN_NAME]), Result: nil}, nil
} else {
return nil, errors.NewErr("transaction type error")
}
}

func (this *LedgerStoreImp) getPreGas(config *smartcontract.Config, cache *storage.CloneCache) (map[string]uint64, error) {
bf := new(bytes.Buffer)
names := []string{neovm.CONTRACT_CREATE_NAME, neovm.UINT_INVOKE_CODE_LEN_NAME, neovm.UINT_DEPLOY_CODE_LEN_NAME}
if err := utils.WriteVarUint(bf, uint64(len(names))); err != nil {
return nil, fmt.Errorf("write gas_table_keys length error:%s", err)
}

for _, v := range names {
if err := serialization.WriteString(bf, v); err != nil {
return nil, fmt.Errorf("serialize param name error:%s", err)
}
}

sc := smartcontract.SmartContract{
Config: config,
CloneCache: cache,
Store: this,
CloneCache: storage.NewCloneCache(this.stateStore.NewStateBatch()),
Gas: math.MaxUint64,
}

//start the smart contract executive function
engine, err := sc.NewExecuteEngine(invoke.Code)
if err != nil {
return nil, err
}
result, err := engine.Invoke()
service, _ := sc.NewNativeService()
result, err := service.NativeCall(utils.ParamContractAddress, "getGlobalParam", bf.Bytes())
if err != nil {
return nil, err
}
gasCost := math.MaxUint64 - sc.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
params := new(global_params.Params)
if err := params.Deserialize(bytes.NewBuffer(result.([]byte))); err != nil {
return nil, fmt.Errorf("deserialize global params error:%s", err)
}
m := make(map[string]uint64, 0)
for _, v := range names {
n, ps := params.GetParam(v)
if n != -1 && ps.Value != "" {
pu, err := strconv.ParseUint(ps.Value, 10, 64)
if err != nil {
return nil, fmt.Errorf("failed to parse uint %v", err)
}
m[v] = pu
}
}
return &sstate.PreExecResult{State: event.CONTRACT_STATE_SUCCESS, Gas: gasCost, Result: scommon.ConvertNeoVmTypeHexString(result)}, nil
return m, nil
}

//Close ledger store.
Expand Down
Loading

0 comments on commit 5aec5da

Please sign in to comment.