func (d *DriverBase) GetActionName(tx *types.Transaction) string {
	return tx.ActionName()
}
GetActionName get action name
package dapp
import (
	"bytes"
	"reflect"
	"github.com/33cn/chain33/account"
	"github.com/33cn/chain33/client"
	"github.com/33cn/chain33/client/api"
	"github.com/33cn/chain33/common/address"
	dbm "github.com/33cn/chain33/common/db"
	log "github.com/33cn/chain33/common/log/log15"
	nonetypes "github.com/33cn/chain33/system/dapp/none/types"
	"github.com/33cn/chain33/types"
)
var blog = log.New("module", "execs.base")
const (
	TxIndexFrom = 1
	TxIndexTo = 2
	ExecLocalSameTime = int64(1)
)
type Driver interface {
	SetStateDB(dbm.KV)
	SetCoinsAccount(*account.DB)
	GetCoinsAccount() *account.DB
	SetLocalDB(dbm.KVDB)
	GetCurrentExecName() string
	GetDriverName() string
	GetName() string
	GetExecutorAPI() api.ExecutorAPI
	SetName(string)
	SetCurrentExecName(string)
	Allow(tx *types.Transaction, index int) error
	IsFriend(myexec []byte, writekey []byte, othertx *types.Transaction) bool
	GetActionName(tx *types.Transaction) string
	SetEnv(height, blocktime int64, difficulty uint64)
	SetBlockInfo([]byte, []byte, int64)
	CheckTx(tx *types.Transaction, index int) error
	Exec(tx *types.Transaction, index int) (*types.Receipt, error)
	ExecLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error)
	ExecDelLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error)
	Query(funcName string, params []byte) (types.Message, error)
	IsFree() bool
	SetAPI(client.QueueProtocolAPI)
	SetExecutorAPI(queueapi client.QueueProtocolAPI, chain33api types.Chain33Client)
	SetTxs(txs []*types.Transaction)
	SetReceipt(receipts []*types.ReceiptData)
	GetTxs() []*types.Transaction
	GetTxGroup(index int) ([]*types.Transaction, error)
	GetPayloadValue() types.Message
	GetFuncMap() map[string]reflect.Method
	GetExecutorType() types.ExecutorType
	CheckReceiptExecOk() bool
	ExecutorOrder() int64
	Upgrade() (*types.LocalDBSet, error)
}
type DriverBase struct {
	statedb              dbm.KV
	localdb              dbm.KVDB
	coinsaccount         *account.DB
	height               int64
	blocktime            int64
	parentHash, mainHash []byte
	mainHeight           int64
	name                 string
	curname              string
	child                Driver
	childValue           reflect.Value
	isFree               bool
	difficulty           uint64
	api                  client.QueueProtocolAPI
	execapi              api.ExecutorAPI
	txs                  []*types.Transaction
	receipts             []*types.ReceiptData
	ety                  types.ExecutorType
}
func (d *DriverBase) Upgrade() (*types.LocalDBSet, error) {
	blog.Info("upgrade ", "dapp", d.GetName())
	return nil, nil
}
func (d *DriverBase) GetPayloadValue() types.Message {
	if d.ety == nil {
		return nil
	}
	return d.ety.GetPayload()
}
func (d *DriverBase) GetExecutorType() types.ExecutorType {
	return d.ety
}
func (d *DriverBase) ExecutorOrder() int64 {
	return 0
}
func (d *DriverBase) GetLastHash() []byte {
	types.AssertConfig(d.api)
	cfg := d.api.GetConfig()
	if cfg.IsPara() {
		return d.mainHash
	}
	return d.parentHash
}
func (d *DriverBase) GetParentHash() []byte {
	return d.parentHash
}
func (d *DriverBase) GetFuncMap() map[string]reflect.Method {
	if d.ety == nil {
		return nil
	}
	return d.ety.GetExecFuncMap()
}
func (d *DriverBase) SetAPI(queueapi client.QueueProtocolAPI) {
	d.api = queueapi
}
func (d *DriverBase) SetExecutorAPI(queueapi client.QueueProtocolAPI, chain33api types.Chain33Client) {
	d.execapi = api.New(queueapi, chain33api)
}
func (d *DriverBase) GetAPI() client.QueueProtocolAPI {
	return d.api
}
func (d *DriverBase) GetExecutorAPI() api.ExecutorAPI {
	return d.execapi
}
func (d *DriverBase) SetEnv(height, blocktime int64, difficulty uint64) {
	d.height = height
	d.blocktime = blocktime
	d.difficulty = difficulty
}
func (d *DriverBase) SetBlockInfo(parentHash, mainHash []byte, mainHeight int64) {
	d.parentHash = parentHash
	d.mainHash = mainHash
	d.mainHeight = mainHeight
}
func (d *DriverBase) SetIsFree(isFree bool) {
	d.isFree = isFree
}
func (d *DriverBase) IsFree() bool {
	return d.isFree
}
func (d *DriverBase) SetExecutorType(e types.ExecutorType) {
	d.ety = e
}
func (d *DriverBase) SetChild(e Driver) {
	d.child = e
	d.childValue = reflect.ValueOf(e)
}
func (d *DriverBase) ExecLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
	lset, err := d.callLocal("ExecLocal_", tx, receipt, index)
	if err != nil || lset == nil {  
		return &types.LocalDBSet{}, nil
	}
	return lset, nil
}
func (d *DriverBase) ExecDelLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
	lset, err := d.callLocal("ExecDelLocal_", tx, receipt, index)
	if err != nil || lset == nil {  
		blog.Error("call ExecDelLocal", "execer", string(tx.Execer), "err", err)
		return &types.LocalDBSet{}, nil
	}
	return lset, nil
}
func (d *DriverBase) callLocal(prefix string, tx *types.Transaction, receipt *types.ReceiptData, index int) (set *types.LocalDBSet, err error) {
	if d.ety == nil {
		return nil, types.ErrActionNotSupport
	}
	if d.ety.ActionName(tx) == nonetypes.UnknownActionName {
		return nil, types.ErrActionNotSupport
	}
	if d.child.CheckReceiptExecOk() {
		if receipt.GetTy() != types.ExecOk {
			return &types.LocalDBSet{}, nil
		}
	}
	defer func() {
		if r := recover(); r != nil {
			blog.Error("call localexec error", "prefix", prefix, "tx.exec", string(tx.Execer), "info", r)
			err = types.ErrActionNotSupport
			set = nil
		}
	}()
	name, value, err := d.ety.DecodePayloadValue(tx)
	if err != nil {
		return nil, err
	}
	funcname := prefix + name
	funcmap := d.child.GetFuncMap()
	if _, ok := funcmap[funcname]; !ok {
		return nil, types.ErrActionNotSupport
	}
	valueret := funcmap[funcname].Func.Call([]reflect.Value{d.childValue, value, reflect.ValueOf(tx), reflect.ValueOf(receipt), reflect.ValueOf(index)})
	if !types.IsOK(valueret, 2) {
		return nil, types.ErrMethodReturnType
	}
	r1 := valueret[0].Interface()
	if r1 != nil {
		if r, ok := r1.(*types.LocalDBSet); ok {
			set = r
		} else {
			return nil, types.ErrMethodReturnType
		}
	}
	r2 := valueret[1].Interface()
	err = nil
	if r2 != nil {
		if r, ok := r2.(error); ok {
			err = r
		} else {
			return nil, types.ErrMethodReturnType
		}
	}
	return set, err
}
func CheckAddress(cfg *types.Chain33Config, addr string, height int64) error {
	if IsDriverAddress(addr, height) {
		return nil
	}
	err := address.CheckAddress(addr)
	if !cfg.IsFork(height, "ForkMultiSignAddress") && err == address.ErrCheckVersion {
		return nil
	}
	if !cfg.IsFork(height, "ForkBase58AddressCheck") && err == address.ErrAddressChecksum {
		return nil
	}
	return err
}
func (d *DriverBase) Exec(tx *types.Transaction, index int) (receipt *types.Receipt, err error) {
	if d.ety == nil {
		return nil, nil
	}
	if d.ety.ActionName(tx) == nonetypes.UnknownActionName {
		return nil, nil
	}
	defer func() {
		if r := recover(); r != nil {
			blog.Error("call exec error", "tx.exec", string(tx.Execer), "info", r)
			err = types.ErrActionNotSupport
			receipt = nil
		}
	}()
	if d.child.GetPayloadValue() == nil {
		return nil, nil
	}
	name, value, err := d.ety.DecodePayloadValue(tx)
	if err != nil {
		return nil, err
	}
	funcmap := d.child.GetFuncMap()
	funcname := "Exec_" + name
	if _, ok := funcmap[funcname]; !ok {
		return nil, types.ErrActionNotSupport
	}
	valueret := funcmap[funcname].Func.Call([]reflect.Value{d.childValue, value, reflect.ValueOf(tx), reflect.ValueOf(index)})
	if !types.IsOK(valueret, 2) {
		return nil, types.ErrMethodReturnType
	}
	r1 := valueret[0].Interface()
	if r1 != nil {
		if r, ok := r1.(*types.Receipt); ok {
			receipt = r
		} else {
			return nil, types.ErrMethodReturnType
		}
	}
	r2 := valueret[1].Interface()
	err = nil
	if r2 != nil {
		if r, ok := r2.(error); ok {
			err = r
		} else {
			return nil, types.ErrMethodReturnType
		}
	}
	return receipt, err
}
func (d *DriverBase) CheckTx(tx *types.Transaction, index int) error {
	execer := string(tx.Execer)
	if ExecAddress(execer) != tx.To {
		return types.ErrToAddrNotSameToExecAddr
	}
	return nil
}
func (d *DriverBase) SetStateDB(db dbm.KV) {
	if d.coinsaccount == nil {
		types.AssertConfig(d.api)
		d.coinsaccount = account.NewCoinsAccount(d.api.GetConfig())
	}
	d.statedb = db
	d.coinsaccount.SetDB(db)
}
func (d *DriverBase) GetTxGroup(index int) ([]*types.Transaction, error) {
	if len(d.txs) <= index {
		return nil, types.ErrTxGroupIndex
	}
	tx := d.txs[index]
	c := int(tx.GroupCount)
	if c <= 0 || c > int(types.MaxTxGroupSize) {
		return nil, types.ErrTxGroupCount
	}
	types.AssertConfig(d.api)
	cfg := d.api.GetConfig()
	for i := index; i >= 0 && i >= index-c; i-- {
		if bytes.Equal(d.txs[i].Header, d.txs[i].Hash()) {  
			txgroup := types.Transactions{Txs: d.txs[i : i+c]}
			err := txgroup.Check(cfg, d.GetHeight(), cfg.GetMinTxFeeRate(), cfg.GetMaxTxFee())
			if err != nil {
				return nil, err
			}
			return txgroup.Txs, nil
		}
	}
	return nil, types.ErrTxGroupFormat
}
func (d *DriverBase) GetReceipt() []*types.ReceiptData {
	return d.receipts
}
func (d *DriverBase) SetReceipt(receipts []*types.ReceiptData) {
	d.receipts = receipts
}
func (d *DriverBase) GetStateDB() dbm.KV {
	return d.statedb
}
func (d *DriverBase) SetLocalDB(db dbm.KVDB) {
	d.localdb = db
}
func (d *DriverBase) GetLocalDB() dbm.KVDB {
	return d.localdb
}
func (d *DriverBase) GetHeight() int64 {
	return d.height
}
func (d *DriverBase) GetMainHeight() int64 {
	types.AssertConfig(d.api)
	if d.api.GetConfig().IsPara() {
		return d.mainHeight
	}
	return d.height
}
func (d *DriverBase) GetBlockTime() int64 {
	return d.blocktime
}
func (d *DriverBase) GetDifficulty() uint64 {
	return d.difficulty
}
func (d *DriverBase) GetName() string {
	if d.name == "" {
		return d.child.GetDriverName()
	}
	return d.name
}
func (d *DriverBase) GetCurrentExecName() string {
	if d.curname == "" {
		return d.child.GetDriverName()
	}
	return d.curname
}
func (d *DriverBase) SetName(name string) {
	d.name = name
}
func (d *DriverBase) SetCurrentExecName(name string) {
	d.curname = name
}