func (stub *ChaincodeStub) CalcFee(content string) (*big.Int, error) {
	return stub.handler.handleCalcFee(content, stub.TxID)
}
calc fee by passed paramaters
package shim
import (
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"strings"
	"unicode/utf8"
	"math/big"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes/timestamp"
	"github.com/inklabsfoundation/inkchain/bccsp/factory"
	"github.com/inklabsfoundation/inkchain/common/flogging"
	commonledger "github.com/inklabsfoundation/inkchain/common/ledger"
	"github.com/inklabsfoundation/inkchain/core/comm"
	"github.com/inklabsfoundation/inkchain/core/wallet"
	"github.com/inklabsfoundation/inkchain/protos/ledger/queryresult"
	"github.com/inklabsfoundation/inkchain/protos/ledger/transet/kvtranset"
	pb "github.com/inklabsfoundation/inkchain/protos/peer"
	"github.com/inklabsfoundation/inkchain/protos/utils"
	putils "github.com/inklabsfoundation/inkchain/protos/utils"
	"github.com/op/go-logging"
	"github.com/spf13/viper"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)
var chaincodeLogger = logging.MustGetLogger("shim")
var logOutput = os.Stderr
const (
	minUnicodeRuneValue   = 0             
	maxUnicodeRuneValue   = utf8.MaxRune  
	compositeKeyNamespace = "\x00"
	emptyKeySubstitute    = "\x01"
)
type ChaincodeStub struct {
	TxID           string
	Sender         string
	SenderPubKey   string
	chaincodeEvent *pb.ChaincodeEvent
	args           [][]byte
	handler        *Handler
	signedProposal *pb.SignedProposal
	proposal       *pb.Proposal
	creator   []byte
	transient map[string][]byte
	binding   []byte
}
var peerAddress string
type peerStreamGetter func(name string) (PeerChaincodeStream, error)
var streamGetter peerStreamGetter
func userChaincodeStreamGetter(name string) (PeerChaincodeStream, error) {
	flag.StringVar(&peerAddress, "peer.address", "", "peer address")
	flag.Parse()
	chaincodeLogger.Debugf("Peer address: %s", getPeerAddress())
	clientConn, err := newPeerClientConnection()
	if err != nil {
		chaincodeLogger.Errorf("Error trying to connect to local peer: %s", err)
		return nil, fmt.Errorf("Error trying to connect to local peer: %s", err)
	}
	chaincodeLogger.Debugf("os.Args returns: %s", os.Args)
	chaincodeSupportClient := pb.NewChaincodeSupportClient(clientConn)
	stream, err := chaincodeSupportClient.Register(context.Background())
	if err != nil {
		return nil, fmt.Errorf("Error chatting with leader at address=%s:  %s", getPeerAddress(), err)
	}
	return stream, nil
}
func Start(cc Chaincode) error {
	SetupChaincodeLogging()
	chaincodename := viper.GetString("chaincode.id.name")
	if chaincodename == "" {
		return fmt.Errorf("Error chaincode id not provided")
	}
	err := factory.InitFactories(factory.GetDefaultOpts())
	if err != nil {
		return fmt.Errorf("Internal error, BCCSP could not be initialized with default options: %s", err)
	}
	if streamGetter == nil {
		streamGetter = userChaincodeStreamGetter
	}
	stream, err := streamGetter(chaincodename)
	if err != nil {
		return err
	}
	err = chatWithPeer(chaincodename, stream, cc)
	return err
}
func IsEnabledForLogLevel(logLevel string) bool {
	lvl, _ := logging.LogLevel(logLevel)
	return chaincodeLogger.IsEnabledFor(lvl)
}
func SetupChaincodeLogging() {
	viper.SetEnvPrefix("CORE")
	viper.AutomaticEnv()
	replacer := strings.NewReplacer(".", "_")
	viper.SetEnvKeyReplacer(replacer)
	logFormat := flogging.SetFormat(viper.GetString("chaincode.logging.format"))
	flogging.InitBackend(logFormat, logOutput)
	chaincodeLogLevelString := viper.GetString("chaincode.logging.level")
	if chaincodeLogLevelString == "" {
		chaincodeLogger.Infof("Chaincode log level not provided; defaulting to: %s", flogging.DefaultLevel())
		flogging.InitFromSpec(flogging.DefaultLevel())
	} else {
		_, err := LogLevel(chaincodeLogLevelString)
		if err == nil {
			flogging.InitFromSpec(chaincodeLogLevelString)
		} else {
			chaincodeLogger.Warningf("Error: '%s' for chaincode log level: %s; defaulting to %s", err, chaincodeLogLevelString, flogging.DefaultLevel())
			flogging.InitFromSpec(flogging.DefaultLevel())
		}
	}
	shimLogLevelString := viper.GetString("chaincode.logging.shim")
	if shimLogLevelString != "" {
		shimLogLevel, err := LogLevel(shimLogLevelString)
		if err == nil {
			SetLoggingLevel(shimLogLevel)
		} else {
			chaincodeLogger.Warningf("Error: %s for shim log level: %s", err, shimLogLevelString)
		}
	}
	buildLevel := viper.GetString("chaincode.buildlevel")
	chaincodeLogger.Infof("Chaincode (build level: %s) starting up ...", buildLevel)
}
func StartInProc(env []string, args []string, cc Chaincode, recv <-chan *pb.ChaincodeMessage, send chan<- *pb.ChaincodeMessage) error {
	chaincodeLogger.Debugf("in proc %v", args)
	var chaincodename string
	for _, v := range env {
		if strings.Index(v, "CORE_CHAINCODE_ID_NAME=") == 0 {
			p := strings.SplitAfter(v, "CORE_CHAINCODE_ID_NAME=")
			chaincodename = p[1]
			break
		}
	}
	if chaincodename == "" {
		return fmt.Errorf("Error chaincode id not provided")
	}
	stream := newInProcStream(recv, send)
	chaincodeLogger.Debugf("starting chat with peer using name=%s", chaincodename)
	err := chatWithPeer(chaincodename, stream, cc)
	return err
}
func getPeerAddress() string {
	if peerAddress != "" {
		return peerAddress
	}
	if peerAddress = viper.GetString("peer.address"); peerAddress == "" {
		chaincodeLogger.Fatalf("peer.address not configured, can't connect to peer")
	}
	return peerAddress
}
func newPeerClientConnection() (*grpc.ClientConn, error) {
	var peerAddress = getPeerAddress()
	if comm.TLSEnabled() {
		return comm.NewClientConnectionWithAddress(peerAddress, true, true, comm.InitTLSForPeer())
	}
	return comm.NewClientConnectionWithAddress(peerAddress, true, false, nil)
}
func chatWithPeer(chaincodename string, stream PeerChaincodeStream, cc Chaincode) error {
	handler := newChaincodeHandler(stream, cc)
	defer stream.CloseSend()
	chaincodeID := &pb.ChaincodeID{Name: chaincodename}
	payload, err := proto.Marshal(chaincodeID)
	if err != nil {
		return fmt.Errorf("Error marshalling chaincodeID during chaincode registration: %s", err)
	}
	chaincodeLogger.Debugf("Registering.. sending %s", pb.ChaincodeMessage_REGISTER)
	if err = handler.serialSend(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTER, Payload: payload}); err != nil {
		return fmt.Errorf("Error sending chaincode REGISTER: %s", err)
	}
	waitc := make(chan struct{})
	errc := make(chan error)
	go func() {
		defer close(waitc)
		msgAvail := make(chan *pb.ChaincodeMessage)
		var nsInfo *nextStateInfo
		var in *pb.ChaincodeMessage
		recv := true
		for {
			in = nil
			err = nil
			nsInfo = nil
			if recv {
				recv = false
				go func() {
					var in2 *pb.ChaincodeMessage
					in2, err = stream.Recv()
					msgAvail <- in2
				}()
			}
			select {
			case sendErr := <-errc:
				if sendErr == nil {
					continue
				}
				err = fmt.Errorf("Error sending %s: %s", in.Type.String(), sendErr)
				return
			case in = <-msgAvail:
				if err == io.EOF {
					chaincodeLogger.Debugf("Received EOF, ending chaincode stream, %s", err)
					return
				} else if err != nil {
					chaincodeLogger.Errorf("Received error from server: %s, ending chaincode stream", err)
					return
				} else if in == nil {
					err = fmt.Errorf("Received nil message, ending chaincode stream")
					chaincodeLogger.Debug("Received nil message, ending chaincode stream")
					return
				}
				chaincodeLogger.Debugf("[%s]Received message %s from shim", shorttxid(in.Txid), in.Type.String())
				recv = true
			case nsInfo = <-handler.nextState:
				in = nsInfo.msg
				if in == nil {
					panic("nil msg")
				}
				chaincodeLogger.Debugf("[%s]Move state message %s", shorttxid(in.Txid), in.Type.String())
			}
			err = handler.handleMessage(in)
			if err != nil {
				err = fmt.Errorf("Error handling message: %s", err)
				return
			}
			if in.Type == pb.ChaincodeMessage_KEEPALIVE {
				chaincodeLogger.Debug("Sending KEEPALIVE response")
				handler.serialSendAsync(in, nil)
			} else if nsInfo != nil && nsInfo.sendToCC {
				chaincodeLogger.Debugf("[%s]send state message %s", shorttxid(in.Txid), in.Type.String())
				handler.serialSendAsync(in, errc)
			}
		}
	}()
	<-waitc
	return err
}
func (stub *ChaincodeStub) verifySigAndGetSender(proposal *pb.Proposal) (string, error) {
	cis, err := putils.GetChaincodeInvocationSpecFromSignedProposal(proposal)
	if err != nil {
		return "", fmt.Errorf("Failed extracting signedProposal from signed signedProposal. [%s]", err)
	}
	if cis.Sig == nil || cis.SenderSpec == nil {
		return "", nil
	}
	hash, err := wallet.GetInvokeHash(cis.ChaincodeSpec, cis.IdGenerationAlg, cis.SenderSpec)
	if err != nil {
		return "", fmt.Errorf("invalid signature1. [%s]", err)
	}
	sender, err := wallet.GetSenderFromSignature(hash, cis.Sig)
	senderStr := sender.ToString()
	if strings.Compare(senderStr, string(cis.SenderSpec.Sender[:])) != 0 {
		return "", fmt.Errorf("invalid signature2. [%s]", err.Error())
	}
	return senderStr, nil
}
func (stub *ChaincodeStub) verifySigAndGetSenderPubKey(proposal *pb.Proposal) (string, error) {
	cis, err := putils.GetChaincodeInvocationSpecFromSignedProposal(proposal)
	if err != nil {
		return "", fmt.Errorf("Failed extracting signedProposal from signed signedProposal. 1 [%s]", err)
	}
	if cis.Sig == nil || cis.SenderSpec == nil {
		return "", nil
	}
	hash, err := wallet.GetInvokeHash(cis.ChaincodeSpec, cis.IdGenerationAlg, cis.SenderSpec)
	if err != nil {
		return "", fmt.Errorf("invalid signature1. [%s]", err)
	}
	senderPubKey, err := wallet.GetSenderPubKeyFromSignature(hash, cis.Sig)
	return senderPubKey, nil
}
func (stub *ChaincodeStub) getSenderMsg(proposal *pb.Proposal) (string, error) {
	cis, err := putils.GetChaincodeInvocationSpecFromSignedProposal(proposal)
	if err != nil {
		return "", fmt.Errorf("Failed extracting signedProposal from signed signedProposal. [%s]", err)
	}
	if cis.Sig == nil || cis.SenderSpec == nil {
		return "", nil
	}
	return string(cis.SenderSpec.Msg), nil
}
func (stub *ChaincodeStub) init(handler *Handler, txid string, input *pb.ChaincodeInput, signedProposal *pb.SignedProposal) error {
	stub.TxID = txid
	stub.args = input.Args
	stub.handler = handler
	stub.signedProposal = signedProposal
	if signedProposal != nil {
		var err error
		stub.proposal, err = utils.GetProposal(signedProposal.ProposalBytes)
		if err != nil {
			return fmt.Errorf("Failed extracting signedProposal from signed signedProposal. [%s]", err)
		}
		stub.creator, stub.transient, err = utils.GetChaincodeProposalContext(stub.proposal)
		if err != nil {
			return fmt.Errorf("Failed extracting signedProposal fields. [%s]", err)
		}
		stub.binding, err = utils.ComputeProposalBinding(stub.proposal)
		if err != nil {
			return fmt.Errorf("Failed computing binding from signedProposal. [%s]", err)
		}
		sender, err := stub.verifySigAndGetSender(stub.proposal)
		bytes := make([]byte, len(sender))
		copy(bytes,sender)
		stub.Sender = string(bytes)
		senderPubKey, err := stub.verifySigAndGetSenderPubKey(stub.proposal)
		if err != nil {
			return fmt.Errorf("unable to get pub key. [%s]", err)
		}
		pubBytes := make([]byte, len(senderPubKey))
		copy(pubBytes,senderPubKey)
		stub.SenderPubKey = string(pubBytes)
	}
	return nil
}
func (stub *ChaincodeStub) GetTxID() string {
	return stub.TxID
}
func (stub *ChaincodeStub) InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response {
	if channel != "" {
		chaincodeName = chaincodeName + "/" + channel
	}
	return stub.handler.handleInvokeChaincode(chaincodeName, args, stub.TxID)
}
func (stub *ChaincodeStub) GetState(key string) ([]byte, error) {
	return stub.handler.handleGetState(key, stub.TxID)
}
func (stub *ChaincodeStub) PutState(key string, value []byte) error {
	if key == "" {
		return fmt.Errorf("key must not be an empty string")
	}
	return stub.handler.handlePutState(key, value, stub.TxID)
}
func (stub *ChaincodeStub) DelState(key string) error {
	return stub.handler.handleDelState(key, stub.TxID)
}
type CommonIterator struct {
	handler    *Handler
	uuid       string
	response   *pb.QueryResponse
	currentLoc int
}
type StateQueryIterator struct {
	*CommonIterator
}
type HistoryQueryIterator struct {
	*CommonIterator
}
type resultType uint8
const (
	STATE_QUERY_RESULT   resultType = iota + 1
	HISTORY_QUERY_RESULT
)
func (stub *ChaincodeStub) handleGetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error) {
	response, err := stub.handler.handleGetStateByRange(startKey, endKey, stub.TxID)
	if err != nil {
		return nil, err
	}
	return &StateQueryIterator{CommonIterator: &CommonIterator{stub.handler, stub.TxID, response, 0}}, nil
}
func (stub *ChaincodeStub) GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error) {
	if startKey == "" {
		startKey = emptyKeySubstitute
	}
	if err := validateSimpleKeys(startKey, endKey); err != nil {
		return nil, err
	}
	return stub.handleGetStateByRange(startKey, endKey)
}
func (stub *ChaincodeStub) GetQueryResult(query string) (StateQueryIteratorInterface, error) {
	response, err := stub.handler.handleGetQueryResult(query, stub.TxID)
	if err != nil {
		return nil, err
	}
	return &StateQueryIterator{CommonIterator: &CommonIterator{stub.handler, stub.TxID, response, 0}}, nil
}
func (stub *ChaincodeStub) GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error) {
	response, err := stub.handler.handleGetHistoryForKey(key, stub.TxID)
	if err != nil {
		return nil, err
	}
	return &HistoryQueryIterator{CommonIterator: &CommonIterator{stub.handler, stub.TxID, response, 0}}, nil
}
func (stub *ChaincodeStub) CreateCompositeKey(objectType string, attributes []string) (string, error) {
	return createCompositeKey(objectType, attributes)
}
func (stub *ChaincodeStub) SplitCompositeKey(compositeKey string) (string, []string, error) {
	return splitCompositeKey(compositeKey)
}
func createCompositeKey(objectType string, attributes []string) (string, error) {
	if err := validateCompositeKeyAttribute(objectType); err != nil {
		return "", err
	}
	ck := compositeKeyNamespace + objectType + string(minUnicodeRuneValue)
	for _, att := range attributes {
		if err := validateCompositeKeyAttribute(att); err != nil {
			return "", err
		}
		ck += att + string(minUnicodeRuneValue)
	}
	return ck, nil
}
func splitCompositeKey(compositeKey string) (string, []string, error) {
	componentIndex := 1
	components := []string{}
	for i := 1; i < len(compositeKey); i++ {
		if compositeKey[i] == minUnicodeRuneValue {
			components = append(components, compositeKey[componentIndex:i])
			componentIndex = i + 1
		}
	}
	return components[0], components[1:], nil
}
func validateCompositeKeyAttribute(str string) error {
	if !utf8.ValidString(str) {
		return fmt.Errorf("Not a valid utf8 string: [%x]", str)
	}
	for index, runeValue := range str {
		if runeValue == minUnicodeRuneValue || runeValue == maxUnicodeRuneValue {
			return fmt.Errorf(`Input contain unicode %#U starting at position [%d]. %#U and %#U are not allowed in the input attribute of a composite key`,
				runeValue, index, minUnicodeRuneValue, maxUnicodeRuneValue)
		}
	}
	return nil
}
func validateSimpleKeys(simpleKeys ...string) error {
	for _, key := range simpleKeys {
		if len(key) > 0 && key[0] == compositeKeyNamespace[0] {
			return fmt.Errorf(`First character of the key [%s] contains a null character which is not allowed`, key)
		}
	}
	return nil
}
func (stub *ChaincodeStub) GetStateByPartialCompositeKey(objectType string, attributes []string) (StateQueryIteratorInterface, error) {
	if partialCompositeKey, err := stub.CreateCompositeKey(objectType, attributes); err == nil {
		return stub.handleGetStateByRange(partialCompositeKey, partialCompositeKey+string(maxUnicodeRuneValue))
	} else {
		return nil, err
	}
}
func (iter *StateQueryIterator) Next() (*queryresult.KV, error) {
	if result, err := iter.nextResult(STATE_QUERY_RESULT); err == nil {
		return result.(*queryresult.KV), err
	} else {
		return nil, err
	}
}
func (iter *HistoryQueryIterator) Next() (*queryresult.KeyModification, error) {
	if result, err := iter.nextResult(HISTORY_QUERY_RESULT); err == nil {
		return result.(*queryresult.KeyModification), err
	} else {
		return nil, err
	}
}
func (iter *CommonIterator) HasNext() bool {
	if iter.currentLoc < len(iter.response.Results) || iter.response.HasMore {
		return true
	}
	return false
}
func (iter *CommonIterator) getResultFromBytes(queryResultBytes *pb.QueryResultBytes,
	rType resultType) (commonledger.QueryResult, error) {
	if rType == STATE_QUERY_RESULT {
		stateQueryResult := &queryresult.KV{}
		if err := proto.Unmarshal(queryResultBytes.ResultBytes, stateQueryResult); err != nil {
			return nil, err
		}
		return stateQueryResult, nil
	} else if rType == HISTORY_QUERY_RESULT {
		historyQueryResult := &queryresult.KeyModification{}
		if err := proto.Unmarshal(queryResultBytes.ResultBytes, historyQueryResult); err != nil {
			return nil, err
		}
		return historyQueryResult, nil
	}
	return nil, errors.New("Wrong result type")
}
func (iter *CommonIterator) fetchNextQueryResult() error {
	if response, err := iter.handler.handleQueryStateNext(iter.response.Id, iter.uuid); err == nil {
		iter.currentLoc = 0
		iter.response = response
		return nil
	} else {
		return err
	}
}
func (iter *CommonIterator) nextResult(rType resultType) (commonledger.QueryResult, error) {
	if iter.currentLoc < len(iter.response.Results) {
		queryResult, err := iter.getResultFromBytes(iter.response.Results[iter.currentLoc], rType)
		if err != nil {
			chaincodeLogger.Errorf("Failed to decode query results [%s]", err)
			return nil, err
		}
		iter.currentLoc++
		if iter.currentLoc == len(iter.response.Results) && iter.response.HasMore {
			if err = iter.fetchNextQueryResult(); err != nil {
				chaincodeLogger.Errorf("Failed to fetch next results [%s]", err)
				return nil, err
			}
		}
		return queryResult, err
	} else if !iter.response.HasMore {
		return nil, errors.New("No such key")
	}
	return nil, errors.New("Invalid iterator state")
}
func (iter *CommonIterator) Close() error {
	_, err := iter.handler.handleQueryStateClose(iter.response.Id, iter.uuid)
	return err
}
func (stub *ChaincodeStub) GetArgs() [][]byte {
	return stub.args
}
func (stub *ChaincodeStub) GetStringArgs() []string {
	args := stub.GetArgs()
	strargs := make([]string, 0, len(args))
	for _, barg := range args {
		strargs = append(strargs, string(barg))
	}
	return strargs
}
func (stub *ChaincodeStub) GetFunctionAndParameters() (function string, params []string) {
	allargs := stub.GetStringArgs()
	function = ""
	params = []string{}
	if len(allargs) >= 1 {
		function = allargs[0]
		params = allargs[1:]
	}
	return
}
func (stub *ChaincodeStub) GetCreator() ([]byte, error) {
	return stub.creator, nil
}
func (stub *ChaincodeStub) GetTransient() (map[string][]byte, error) {
	return stub.transient, nil
}
func (stub *ChaincodeStub) GetBinding() ([]byte, error) {
	return stub.binding, nil
}
func (stub *ChaincodeStub) GetSignedProposal() (*pb.SignedProposal, error) {
	return stub.signedProposal, nil
}
func (stub *ChaincodeStub) GetArgsSlice() ([]byte, error) {
	args := stub.GetArgs()
	res := []byte{}
	for _, barg := range args {
		res = append(res, barg...)
	}
	return res, nil
}
func (stub *ChaincodeStub) GetTxTimestamp() (*timestamp.Timestamp, error) {
	hdr, err := utils.GetHeader(stub.proposal.Header)
	if err != nil {
		return nil, err
	}
	chdr, err := utils.UnmarshalChannelHeader(hdr.ChannelHeader)
	if err != nil {
		return nil, err
	}
	return chdr.GetTimestamp(), nil
}
func (stub *ChaincodeStub) SetEvent(name string, payload []byte) error {
	if name == "" {
		return errors.New("Event name can not be nil string.")
	}
	stub.chaincodeEvent = &pb.ChaincodeEvent{EventName: name, Payload: payload}
	return nil
}
func (stub *ChaincodeStub) Transfer(to string, balanceType string, amount *big.Int) error {
	if to == "" || len(to) != wallet.AddressStringLength {
		return fmt.Errorf(".invalid address length.")
	}
	if amount.Cmp(big.NewInt(0)) < 0 {
		return fmt.Errorf(".transfer amount should be a half-positive number.")
	}
	to = strings.ToLower(to)
	addr := wallet.StringToAddress(to)
	if addr == nil {
		return fmt.Errorf("must be valid address")
	}
	tran := &kvtranset.KVTrans{}
	tran.To = to
	tran.BalanceType = balanceType
	tran.Amount = amount.Bytes()
	var tranSet []*kvtranset.KVTrans
	tranSet = append(tranSet, tran)
	kvTranSet := &kvtranset.KVTranSet{Trans: tranSet}
	return stub.handler.handleTransfer(kvTranSet, stub.TxID)
}
func (stub *ChaincodeStub) GetAccount(address string) (*wallet.Account, error) {
	if address == "" || len(address) != wallet.AddressStringLength {
		return nil, fmt.Errorf("invalid address length")
	}
	address = strings.ToLower(address)
	addr := wallet.StringToAddress(address)
	if addr == nil {
		return nil, fmt.Errorf("must be valid address")
	}
	return stub.handler.handleGetAccount(address, stub.TxID)
}
func (stub *ChaincodeStub) IssueToken(address string, balanceType string, amount *big.Int) error {
	if address == "" || len(address) != wallet.AddressStringLength {
		return fmt.Errorf("invalid address length")
	}
	address = strings.ToLower(address)
	addr := wallet.StringToAddress(address)
	if addr == nil {
		return fmt.Errorf("must be valid address")
	}
	return stub.handler.handleIssueToken(address, balanceType, amount, stub.TxID)
}
func (stub *ChaincodeStub) GetSender() (string, error) {
	return stub.Sender, nil
}
func (stub *ChaincodeStub) GetSenderPubKey() (string, error) {
	return stub.SenderPubKey, nil
}
func (stub *ChaincodeStub) CalcFeeByInvoke() (*big.Int, error) {
	msg, err := stub.getSenderMsg(stub.proposal)
	if err != nil {
		return nil, err
	}
	content := msg
	return stub.handler.handleCalcFee(content, stub.TxID)
}