func (s *RPCServer) SendTx(ctx context.Context, tx *RpcTx) (*RpcResponse, error) {
	hashOfEvent, txmsg, resp := checkRpcTx(tx, true)
	if resp != nil {
		return resp, nil
	}
	cid := txmsg.ChainID
	var acc *models.Account
	var exist bool
	cdata, err := s.dmanager.GetChainData(cid)
	if err == nil {
		acc, exist = cdata.GetAccount(txmsg.From)
	}
	if !exist && ((txmsg.Val != nil && txmsg.Val.Sign() > 0) || len(txmsg.Input) == 0) {
		return newResponse(InvalidFromAddressCode), nil
	}
	if acc == nil {
		acc = models.NewAccount(*txmsg.From, nil)
	}
	if acc.Nonce > tx.Nonce {
		return newResponse(InvalidParamsCode, "invalid nonce"), nil
	}
	if s.dmanager.IsDataNodeOf(txmsg.ChainID) || (s.dmanager.IsMemoNode() && *common.ForChain == txmsg.ChainID) {
		if config.IsLogOn(config.DataDebugLog) {
			s.logger.Debugf("[RPCServer] receive to queue: %s", txmsg)
		}
		if err := s.eventer.PostEvent(txmsg, tx.Pub, tx.Sig); err != nil {
			return newResponse(PostEventErrCode, err.Error()), nil
		}
	} else {
		if config.IsLogOn(config.DataDebugLog) {
			s.logger.Debugf("[RPCServer] not a local tx, ignored")
		}
	}
	hs := common.BytesToHash(hashOfEvent)
	return &RpcResponse{Code: SuccessCode, Data: hs.Hex()}, nil
}
SendTx return resp.data as returned information
package rpcserver
import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"github.com/ThinkiumGroup/go-cipher"
	"github.com/ThinkiumGroup/go-common"
	"github.com/ThinkiumGroup/go-common/hexutil"
	"github.com/ThinkiumGroup/go-common/log"
	"github.com/ThinkiumGroup/go-common/math"
	"github.com/ThinkiumGroup/go-thinkium/config"
	"github.com/ThinkiumGroup/go-thinkium/consts"
	"github.com/ThinkiumGroup/go-thinkium/models"
	"github.com/sirupsen/logrus"
	"github.com/stephenfire/go-rtl"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)
type RPCServer struct {
	common.AbstractService
	local    common.Endpoint
	listener net.Listener
	nmanager models.NetworkManager
	dmanager models.DataManager
	engine   models.Engine
	eventer  models.Eventer
	logger   logrus.FieldLogger
}
func NewRPCServer(local common.Endpoint, nmanager models.NetworkManager, dmanager models.DataManager, engine models.Engine,
	eventer models.Eventer) (*RPCServer, error) {
	server := &RPCServer{
		local:    local,
		nmanager: nmanager,
		dmanager: dmanager,
		engine:   engine,
		eventer:  eventer,
		logger:   log.WithField("L", "RPCServer"),
	}
	server.SetChanger(server)
	return server, nil
}
func (s *RPCServer) String() string {
	return "RPC@" + s.local.String()
}
func (s *RPCServer) Initializer() error {
	if s.local.IsNil() {
		return errors.New("empty server endpoint setting for RPC Server")
	}
	s.logger.Debug("[RPCServer] initialized")
	return nil
}
func (s *RPCServer) Starter() error {
	l, err := net.Listen(s.local.NetType, s.local.Address)
	if err != nil {
		return err
	}
	s.listener = l
	srv := grpc.NewServer()
	RegisterNodeServer(srv, s)
	reflection.Register(srv)
	go func() {
		if err := srv.Serve(s.listener); err != nil {
			s.logger.Errorf("[RPCServer] failed to serve: %v", err)
		}
		s.logger.Debug("[RPCServer] serve stoped")
	}()
	s.logger.Debugf("[RPCServer] started @ %s", s.local)
	return nil
}
func (s *RPCServer) Closer() error {
	if err := s.listener.Close(); err != nil {
		s.logger.Errorf("[RPCServer] closing rpc server listener error: %v", err)
	}
	s.logger.Debug("[RPCServer] closed")
	return nil
}
func newResponse(code int32, msg ...string) *RpcResponse {
	if len(msg) == 0 || len(msg[0]) == 0 {
		return &RpcResponse{Code: code, Data: RpcErrMsgMap[code]}
	} else {
		return &RpcResponse{Code: code, Data: msg[0]}
	}
}
func (s *RPCServer) Ping(ctx context.Context, req *RpcRequest) (*RpcResponse, error) {
	if req == nil {
		return newResponse(InvalidParamsCode, "nil request"), nil
	}
	ni := NodeInfo{
		NodeId:        common.SystemNodeID,
		Version:       consts.Version,
		IsDataNode:    s.dmanager.IsDataNode(),
		DataNodeOf:    s.dmanager.DataNodeOf(),
		LastMsgTime:   common.LastMsgTime,
		LastEventTime: common.LastEventTime,
		LastBlockTime: common.LastBlockTime,
		LastBlocks:    common.LastBlocks.CopyMap(),
		Overflow:      common.Overflow,
		OpTypes:       s.eventer.GetNodeOpTypes(),
	}
	if jsons, err := json.Marshal(ni); err != nil {
		s.logger.Error("[RPCServer] Marshal NodeInfo error,", err.Error())
		return newResponse(MarshalErrCode, err.Error()), nil
	} else {
		return &RpcResponse{Code: SuccessCode, Data: string(jsons)}, nil
	}
}
func (s *RPCServer) GetAccount(ctx context.Context, addr *RpcAddress) (*RpcResponse, error) {
	if addr == nil {
		return newResponse(InvalidParamsCode, "nil request"), nil
	}
	if len(addr.Address) != common.AddressLength {
		return newResponse(InvalidParamsCode, "invalid address"), nil
	}
	chainId := common.ChainID(addr.Chainid)
	comaddr := common.BytesToAddress(addr.Address)
	cdata, err := s.dmanager.GetChainData(chainId)
	if err != nil {
		return newResponse(GetChainDataErrCode, err.Error()), nil
	}
	var code []byte
	acc, _ := cdata.GetAccount(&comaddr)
	if acc == nil {
		acc = models.NewAccount(comaddr, nil)
	} else {
		if acc.IsUserContract() {
			code = cdata.GetCodeByHash(common.BytesToHash(acc.CodeHash))
		}
	}
	ach := &AccountWithCode{
		Addr:            acc.Addr,
		Nonce:           acc.Nonce,
		Balance:         acc.Balance,
		LocalCurrency:   acc.LocalCurrency,
		StorageRoot:     acc.StorageRoot,
		CodeHash:        acc.CodeHash,
		LongStorageRoot: acc.LongStorageRoot,
		Code:            code,
	}
	if jsons, err := json.Marshal(ach); err != nil {
		return newResponse(MarshalErrCode, err.Error()), nil
	} else {
		return &RpcResponse{Code: SuccessCode, Data: string(jsons)}, nil
	}
}
func (s *RPCServer) GetAccountWithChainHeight(ctx context.Context, addr *RpcAddress) (*RpcResponse, error) {
	if addr == nil {
		return newResponse(InvalidParamsCode, "nil request"), nil
	}
	if len(addr.Address) != common.AddressLength {
		return newResponse(InvalidParamsCode, "invalid address"), nil
	}
	chainId := common.ChainID(addr.Chainid)
	comaddr := common.BytesToAddress(addr.Address)
	cdata, err := s.dmanager.GetChainData(chainId)
	if err != nil {
		return newResponse(GetChainDataErrCode, err.Error()), nil
	}
	var code []byte
	acc, _ := cdata.GetAccount(&comaddr)
	if acc == nil {
		acc = models.NewAccount(comaddr, nil)
	} else {
		if acc.IsUserContract() {
			code = cdata.GetCodeByHash(common.BytesToHash(acc.CodeHash))
		}
	}
	ach := &AccountHeight{
		Height:          cdata.GetCurrentHeight(),
		Addr:            acc.Addr,
		Nonce:           acc.Nonce,
		Balance:         acc.Balance,
		LocalCurrency:   acc.LocalCurrency,
		StorageRoot:     acc.StorageRoot,
		CodeHash:        acc.CodeHash,
		LongStorageRoot: acc.LongStorageRoot,
		Code:            code,
	}
	if jsons, err := json.Marshal(ach); err != nil {
		return newResponse(MarshalErrCode, err.Error()), nil
	} else {
		return &RpcResponse{Code: SuccessCode, Data: string(jsons)}, nil
	}
}
func deltaFromToAccountChange(header *models.BlockHeader, key models.DeltaFromKey, delta *models.AccountDelta) *AccountChange {
	if delta == nil {
		return nil
	}
	return &AccountChange{
		ChainID:   key.ShardID,
		Height:    key.Height,
		From:      nil,
		To:        &delta.Addr,
		Nonce:     0,
		Val:       delta.Delta,
		TimeStamp: header.TimeStamp,
	}
}
func txToAccountChange(header *models.BlockHeader, height common.Height, tx *models.Transaction) *AccountChange {
	if tx == nil {
		return nil
	}
	return &AccountChange{
		ChainID:   tx.ChainID,
		Height:    height,
		From:      tx.From,
		To:        tx.To,
		Nonce:     tx.Nonce,
		Val:       tx.Val,
		Input:     tx.Input,
		UseLocal:  tx.UseLocal,
		Extra:     tx.Extra,
		TimeStamp: header.TimeStamp,
	}
}
func checkRpcTx(tx *RpcTx, verifySig bool) (hoe []byte, txmsg *models.Transaction, resp *RpcResponse) {
	if tx == nil {
		return nil, nil, newResponse(InvalidParamsCode, "nil tx")
	}
	if tx.From == nil || len(tx.From.Address) != common.AddressLength {
		return nil, nil, newResponse(InvalidParamsCode, "illegal from address")
	}
	if len(tx.Multipubs) != len(tx.Multisigs) {
		return nil, nil, newResponse(InvalidParamsCode, "multipubs and multisigs not match")
	}
	if tx.Chainid == uint32(common.MainChainID) {
		if tx.To == nil || len(tx.To.Address) == 0 || !common.BytesToAddress(tx.To.Address).IsSystemContract() {
			return nil, nil, newResponse(InvalidBCCode)
		}
	}
	if verifySig {
		address, err := common.AddressFromPubSlice(tx.Pub)
		if err != nil {
			return nil, nil, newResponse(InvalidPublicKey, err.Error())
		}
		if !bytes.Equal(tx.From.Address[:], address.Bytes()) {
			return nil, nil, newResponse(InvalidPublicKey)
		}
		hoe, err = common.HashObject(tx)
		if err != nil {
			return nil, nil, newResponse(HashObjectErrCode, err.Error())
		}
		if v := common.VerifyHash(hoe, tx.Pub, tx.Sig); !v {
			return nil, nil, newResponse(InvalidSignatureCode)
		}
	}
	from := common.Address{}
	copy(from[:], tx.From.Address)
	if from.IsReserved() {
		return nil, nil, newResponse(ReservedFromAddrErrCode)
	}
	var pto *common.Address = nil
	if tx.To != nil && len(tx.To.Address) > 0 {
		to := common.Address{}
		copy(to[:], tx.To.Address)
		pto = &to
	}
	val, ok := math.ParseBig256(tx.Val)
	if !ok || (len(tx.Input) == 0 && val.Sign() == 0) {
		return nil, nil, newResponse(InvalidParamsCode, "invalid value")
	}
	var msigs models.PubAndSigs
	if len(tx.Multisigs) > 0 {
		msigs = make(models.PubAndSigs, len(tx.Multisigs))
		for i := 0; i < len(tx.Multisigs); i++ {
			if len(tx.Multisigs[i]) == 0 || len(tx.Multipubs[i]) == 0 {
				return nil, nil, newResponse(InvalidMultiSigsCode)
			}
			if !common.VerifyHash(hoe, tx.Multipubs[i], tx.Multisigs[i]) {
				return nil, nil, newResponse(InvalidMultiSigsCode)
			}
			msigs[i] = &models.PubAndSig{PublicKey: tx.Multipubs[i], Signature: tx.Multisigs[i]}
		}
	}
	txmsg = &models.Transaction{
		ChainID:   common.ChainID(tx.Chainid),
		From:      &from,
		To:        pto,
		Nonce:     tx.Nonce,
		Val:       val,
		Input:     tx.Input,
		UseLocal:  tx.Uselocal,
		Extra:     tx.Extra,
		MultiSigs: msigs,
		Version:   models.TxVersion,
	}
	return hoe, txmsg, nil
}
func (s *RPCServer) CallTransaction(ctx context.Context, tx *RpcTx) (*RpcResponse, error) {
	chainData, err := s.dmanager.GetChainData(common.ChainID(tx.Chainid))
	if err != nil {
		return newResponse(GetChainDataErrCode, err.Error()), nil
	}
	_, txmsg, resp := checkRpcTx(tx, false)
	if resp != nil {
		return resp, nil
	}
	if txmsg.To == nil {
		return newResponse(InvalidParamsCode, "illegal to address"), nil
	}
	if len(txmsg.Input) == 0 {
		return newResponse(InvalidParamsCode, "no input found"), nil
	}
	bc := chainData.GetBlockChain()
	if bc == nil {
		return newResponse(InvalidBCCode), nil
	}
	if bc.CurrentBlock() == nil {
		return newResponse(NilBlockCode), nil
	}
	rec, err := chainData.CallProcessTx(txmsg, &models.PubAndSig{PublicKey: tx.Pub, Signature: tx.Sig}, bc.CurrentBlock().BlockHeader)
	if err != nil {
		return newResponse(CallProcessTxErrCode, err.Error()), nil
	}
	receipt := rec.(*models.Receipt)
	result := new(TransactionReceipt).PartReceipt(txmsg, receipt)
	if jsons, err := json.Marshal(result); err != nil {
		return newResponse(MarshalErrCode, err.Error()), nil
	} else {
		return &RpcResponse{Code: SuccessCode, Data: string(jsons)}, nil
	}
}
func (s *RPCServer) GetTransactionByHash(ctx context.Context, txs *RpcTXHash) (*RpcResponse, error) {
	if txs == nil {
		return newResponse(InvalidParamsCode, "nil request"), nil
	}
	chainData, err := s.dmanager.GetChainData(common.ChainID(txs.Chainid))
	if err != nil {
		return newResponse(GetChainDataErrCode, err.Error()), nil
	}
	hash := common.Hash{}
	hash.SetBytes(txs.Hash)
	bc := chainData.GetBlockChain()
	if bc == nil {
		return newResponse(InvalidBCCode), nil
	}
	txI, err := bc.GetBlockTxIndexs(hash[:])
	if err != nil || txI == nil {
		return newResponse(NilTransactionCode), nil
	}
	block, err := bc.GetBlockByHash(txI.BlockHash[:])
	if err != nil {
		return newResponse(NilBlockCode, err.Error()), nil
	}
	if block == nil {
		return newResponse(NilBlockCode), nil
	}
	if block.BlockHeader == nil || block.BlockBody == nil {
		return newResponse(NilBlockCode), nil
	}
	if int(txI.Index) < 0 || int(txI.Index) >= len(block.BlockBody.Txs) {
		return newResponse(NilTransactionCode), nil
	}
	transaction := block.BlockBody.Txs[txI.Index]
	var receipt *models.Receipt
	if block.BlockHeader.ReceiptRoot != nil && !block.BlockHeader.ReceiptRoot.SliceEqual(common.NilHashSlice) {
		receiptHash := *(block.BlockHeader.ReceiptRoot)
		receipts := models.ReadReceipts(chainData.GetDb(), receiptHash)
		receipt, err = models.ReadReceipt(receipts, (int)(txI.Index))
		if err != nil {
			s.logger.Error("[RPCServer] GetTransactionByHash ReadReceipt error:", err.Error())
			return newResponse(ReadReceiptErrCode, err.Error()), nil
		}
	}
	if receipt == nil {
		return newResponse(ReadReceiptErrCode), nil
	}
	result := new(TransactionReceipt).FullReceipt(transaction, block.GetHeight(), receipt)
	if jsons, err := json.Marshal(result); err != nil {
		return newResponse(MarshalErrCode, err.Error()), nil
	} else {
		return &RpcResponse{Code: SuccessCode, Data: string(jsons)}, nil
	}
}
func (s *RPCServer) GetTransactions(ctx context.Context, txs *RpcTxList) (*RpcResponse, error) {
	if txs == nil {
		return newResponse(InvalidParamsCode, "nil request"), nil
	}
	chainData, err := s.dmanager.GetChainData(common.ChainID(txs.Chainid))
	if err != nil {
		return newResponse(GetChainDataErrCode, err.Error()), nil
	}
	changes := make([]*AccountChange, 0)
	targetAddr := common.BytesToAddress(txs.Address.Address)
	for h := txs.StartHeight; h < txs.EndHeight; h++ {
		height := common.Height(h)
		block, err := chainData.GetBlock(common.Height(h))
		if err != nil || block == nil || block.BlockBody == nil {
			if err != nil {
				s.logger.Error("[RPCServer] get block(chainid=%d, height=%d) error: %v", txs.Chainid, h, err)
				return newResponse(NilBlockCode, err.Error()), nil
			} else {
				s.logger.Warnf("[RPCServer] get block(chainid=%d, height=%d) body nil", txs.Chainid, h)
				break
			}
		} else {
			if config.IsLogOn(config.DataDebugLog) {
				s.logger.Debugf("[RPCServer] get block (chainid=%d,height=%d) DeltaFroms(%d) txs(%d)", block.BlockHeader.ChainID,
					block.BlockHeader.Height, len(block.BlockBody.DeltaFroms), len(block.BlockBody.Txs))
			}
			for i := 0; i < len(block.BlockBody.DeltaFroms); i++ {
				for j := 0; j < len(block.BlockBody.DeltaFroms[i].Deltas); j++ {
					if block.BlockBody.DeltaFroms[i].Deltas[j] == nil {
						continue
					}
					if block.BlockBody.DeltaFroms[i].Deltas[j].Addr == targetAddr {
						change := deltaFromToAccountChange(block.BlockHeader, block.BlockBody.DeltaFroms[i].Key,
							block.BlockBody.DeltaFroms[i].Deltas[j])
						if change != nil {
							changes = append(changes, change)
						}
					}
				}
			}
			for i := 0; i < len(block.BlockBody.Txs); i++ {
				if block.BlockBody.Txs[i] == nil {
					continue
				}
				if *(block.BlockBody.Txs[i].From) == targetAddr ||
					(block.BlockBody.Txs[i].To != nil && *(block.BlockBody.Txs[i].To) == targetAddr) {
					change := txToAccountChange(block.BlockHeader, height, block.BlockBody.Txs[i])
					if change != nil {
						changes = append(changes, change)
					}
				}
			}
		}
	}
	if jsons, err := json.Marshal(changes); err != nil {
		return newResponse(MarshalErrCode, err.Error()), nil
	} else {
		return &RpcResponse{Code: SuccessCode, Data: string(jsons)}, nil
	}
}