github.com/turingchain2020/turingchain@v1.1.21/rpc/client.go (about)

     1  // Copyright Turing Corp. 2018 All Rights Reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package rpc turingchain RPC模块包含JSONRpc以及grpc
     6  package rpc
     7  
     8  import (
     9  	"encoding/hex"
    10  	"time"
    11  
    12  	"github.com/turingchain2020/turingchain/account"
    13  	"github.com/turingchain2020/turingchain/client"
    14  	"github.com/turingchain2020/turingchain/common"
    15  	"github.com/turingchain2020/turingchain/common/address"
    16  	"github.com/turingchain2020/turingchain/common/log/log15"
    17  	"github.com/turingchain2020/turingchain/queue"
    18  	ety "github.com/turingchain2020/turingchain/system/dapp/coins/types"
    19  	"github.com/turingchain2020/turingchain/types"
    20  )
    21  
    22  var log = log15.New("module", "rpc")
    23  
    24  type channelClient struct {
    25  	client.QueueProtocolAPI
    26  	accountdb *account.DB
    27  }
    28  
    29  // Init channel client
    30  func (c *channelClient) Init(q queue.Client, api client.QueueProtocolAPI) {
    31  	if api == nil {
    32  		var err error
    33  		api, err = client.New(q, nil)
    34  		if err != nil {
    35  			panic(err)
    36  		}
    37  	}
    38  	c.QueueProtocolAPI = api
    39  	c.accountdb = account.NewCoinsAccount(q.GetConfig())
    40  }
    41  
    42  // CreateRawTransaction create rawtransaction
    43  func (c *channelClient) CreateRawTransaction(param *types.CreateTx) ([]byte, error) {
    44  	if param == nil {
    45  		log.Error("CreateRawTransaction", "Error", types.ErrInvalidParam)
    46  		return nil, types.ErrInvalidParam
    47  	}
    48  	//构建交易时to地址不为空时需要检测地址的合法性
    49  	if param.GetTo() != "" {
    50  		if err := address.CheckAddress(param.GetTo()); err != nil {
    51  			return nil, types.ErrInvalidAddress
    52  		}
    53  	}
    54  	//因为历史原因,这里还是有部分token 的字段,但是没有依赖token dapp
    55  	//未来这个调用可能会被废弃
    56  	types.AssertConfig(c.QueueProtocolAPI)
    57  	cfg := c.QueueProtocolAPI.GetConfig()
    58  	execer := cfg.ExecName(ety.CoinsX)
    59  	if param.IsToken {
    60  		execer = cfg.ExecName("token")
    61  	}
    62  	if param.Execer != "" {
    63  		execer = param.Execer
    64  	}
    65  	reply, err := types.CallCreateTx(cfg, execer, "", param)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	//add tx fee setting
    71  	tx := &types.Transaction{}
    72  	err = types.Decode(reply, tx)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	tx.Fee = param.Fee
    77  	//set proper fee if zero fee
    78  	if tx.Fee <= 0 {
    79  		proper, err := c.GetProperFee(nil)
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  		fee, err := tx.GetRealFee(proper.GetProperFee())
    84  		if err != nil {
    85  			return nil, err
    86  		}
    87  		tx.Fee = fee
    88  	}
    89  
    90  	return types.Encode(tx), nil
    91  }
    92  
    93  func (c *channelClient) ReWriteRawTx(param *types.ReWriteRawTx) ([]byte, error) {
    94  	types.AssertConfig(c.QueueProtocolAPI)
    95  	cfg := c.QueueProtocolAPI.GetConfig()
    96  	if param == nil || param.Tx == "" {
    97  		log.Error("ReWriteRawTx", "Error", types.ErrInvalidParam)
    98  		return nil, types.ErrInvalidParam
    99  	}
   100  
   101  	tx, err := decodeTx(param.Tx)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	if param.To != "" {
   106  		tx.To = param.To
   107  	}
   108  	if param.Fee != 0 && param.Fee > tx.Fee {
   109  		tx.Fee = param.Fee
   110  	}
   111  	var expire int64
   112  	if param.Expire != "" {
   113  		expire, err = types.ParseExpire(param.Expire)
   114  		if err != nil {
   115  			return nil, err
   116  		}
   117  		tx.SetExpire(cfg, time.Duration(expire))
   118  	}
   119  	group, err := tx.GetTxGroup()
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  
   124  	//单笔交易直接返回
   125  	if group == nil {
   126  		txHex := types.Encode(tx)
   127  		return txHex, nil
   128  	}
   129  
   130  	//交易组的处理
   131  	index := param.Index
   132  	if int(index) > len(group.GetTxs()) {
   133  		return nil, types.ErrIndex
   134  	}
   135  
   136  	//修改交易组中所有成员交易
   137  	if index <= 0 {
   138  		if param.Fee != 0 && param.Fee > group.Txs[0].Fee {
   139  			group.Txs[0].Fee = param.Fee
   140  		}
   141  		if param.Expire != "" {
   142  			for i := 0; i < len(group.Txs); i++ {
   143  				group.SetExpire(cfg, i, time.Duration(expire))
   144  			}
   145  		}
   146  		group.RebuiltGroup()
   147  		grouptx := group.Tx()
   148  		txHex := types.Encode(grouptx)
   149  		return txHex, nil
   150  	}
   151  	//修改交易组中指定成员交易
   152  	index--
   153  	if param.Fee != 0 && index == 0 && param.Fee > group.Txs[0].Fee {
   154  		group.Txs[0].Fee = param.Fee
   155  	}
   156  	if param.Expire != "" {
   157  		group.SetExpire(cfg, int(index), time.Duration(expire))
   158  	}
   159  	group.RebuiltGroup()
   160  	grouptx := group.Tx()
   161  	txHex := types.Encode(grouptx)
   162  	return txHex, nil
   163  }
   164  
   165  // CreateRawTxGroup create rawtransaction for group
   166  func (c *channelClient) CreateRawTxGroup(param *types.CreateTransactionGroup) ([]byte, error) {
   167  	types.AssertConfig(c.QueueProtocolAPI)
   168  	cfg := c.QueueProtocolAPI.GetConfig()
   169  	if param == nil || len(param.Txs) <= 1 {
   170  		return nil, types.ErrTxGroupCountLessThanTwo
   171  	}
   172  	var transactions []*types.Transaction
   173  	for _, t := range param.Txs {
   174  		txByte, err := common.FromHex(t)
   175  		if err != nil {
   176  			return nil, err
   177  		}
   178  		var transaction types.Transaction
   179  		err = types.Decode(txByte, &transaction)
   180  		if err != nil {
   181  			return nil, err
   182  		}
   183  		transactions = append(transactions, &transaction)
   184  	}
   185  	feeRate := cfg.GetMinTxFeeRate()
   186  	//get proper fee rate
   187  	proper, err := c.GetProperFee(nil)
   188  	if err != nil {
   189  		log.Error("CreateNoBalance", "GetProperFeeErr", err)
   190  		return nil, err
   191  	}
   192  	if proper.GetProperFee() > feeRate {
   193  		feeRate = proper.ProperFee
   194  	}
   195  	group, err := types.CreateTxGroup(transactions, feeRate)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	txGroup := group.Tx()
   201  	txHex := types.Encode(txGroup)
   202  	return txHex, nil
   203  }
   204  
   205  // CreateNoBalanceTxs create the multiple transaction with no balance
   206  // 实际使用的时候要注意,一般情况下,不要传递 private key 到服务器端,除非是本地localhost 的服务。
   207  func (c *channelClient) CreateNoBalanceTxs(in *types.NoBalanceTxs) (*types.Transaction, error) {
   208  	types.AssertConfig(c.QueueProtocolAPI)
   209  	cfg := c.QueueProtocolAPI.GetConfig()
   210  	txNone := &types.Transaction{Execer: []byte(cfg.ExecName(types.NoneX)), Payload: []byte("no-fee-transaction")}
   211  	txNone.To = address.ExecAddress(string(txNone.Execer))
   212  	txNone, err := types.FormatTx(cfg, cfg.ExecName(types.NoneX), txNone)
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  	//不设置时默认为永不超时
   217  	if in.Expire == "" {
   218  		in.Expire = "0"
   219  	}
   220  	expire, err := types.ParseExpire(in.Expire)
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  	//交易组只需要设置单笔交易超时
   225  	txNone.SetExpire(cfg, time.Duration(expire))
   226  	isParaTx := false
   227  	transactions := []*types.Transaction{txNone}
   228  	for _, txhex := range in.TxHexs {
   229  		tx, err := decodeTx(txhex)
   230  		if err != nil {
   231  			return nil, err
   232  		}
   233  		if types.IsParaExecName(string(tx.GetExecer())) {
   234  			isParaTx = true
   235  		}
   236  		transactions = append(transactions, tx)
   237  	}
   238  
   239  	//平行链下不允许设置高度作为过期判定, issue#706
   240  	if expire > 0 && expire <= types.ExpireBound && isParaTx {
   241  		return nil, types.ErrInvalidExpire
   242  	}
   243  
   244  	feeRate := cfg.GetMinTxFeeRate()
   245  	//get proper fee rate
   246  	proper, err := c.GetProperFee(nil)
   247  	if err != nil {
   248  		log.Error("CreateNoBalance", "GetProperFeeErr", err)
   249  		return nil, err
   250  	}
   251  	if proper.GetProperFee() > feeRate {
   252  		feeRate = proper.ProperFee
   253  	}
   254  	group, err := types.CreateTxGroup(transactions, feeRate)
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  	err = group.Check(cfg, 0, cfg.GetMinTxFeeRate(), cfg.GetMaxTxFee())
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  
   263  	newtx := group.Tx()
   264  	//如果可能要做签名
   265  	if in.PayAddr != "" || in.Privkey != "" {
   266  		rawTx := hex.EncodeToString(types.Encode(newtx))
   267  		req := &types.ReqSignRawTx{Addr: in.PayAddr, Privkey: in.Privkey, Expire: in.Expire, TxHex: rawTx, Index: 1}
   268  		signedTx, err := c.ExecWalletFunc("wallet", "SignRawTx", req)
   269  		if err != nil {
   270  			return nil, err
   271  		}
   272  		return decodeTx(signedTx.(*types.ReplySignRawTx).TxHex)
   273  	}
   274  	return newtx, nil
   275  }
   276  
   277  func decodeTx(hexstr string) (*types.Transaction, error) {
   278  	var tx types.Transaction
   279  	data, err := common.FromHex(hexstr)
   280  	if err != nil {
   281  		return nil, err
   282  	}
   283  	err = types.Decode(data, &tx)
   284  	if err != nil {
   285  		return nil, err
   286  	}
   287  	return &tx, nil
   288  }
   289  
   290  // GetAddrOverview get overview of address
   291  func (c *channelClient) GetAddrOverview(parm *types.ReqAddr) (*types.AddrOverview, error) {
   292  	err := address.CheckAddress(parm.Addr)
   293  	if err != nil {
   294  		return nil, types.ErrInvalidAddress
   295  	}
   296  	reply, err := c.QueueProtocolAPI.GetAddrOverview(parm)
   297  	if err != nil {
   298  		log.Error("GetAddrOverview", "Error", err.Error())
   299  		return nil, err
   300  	}
   301  	//获取地址账户的余额通过account模块
   302  	addrs := make([]string, 1)
   303  	addrs[0] = parm.Addr
   304  	accounts, err := c.accountdb.LoadAccounts(c.QueueProtocolAPI, addrs)
   305  	if err != nil {
   306  		log.Error("GetAddrOverview", "Error", err.Error())
   307  		return nil, err
   308  	}
   309  	if len(accounts) != 0 {
   310  		reply.Balance = accounts[0].Balance
   311  	}
   312  	return reply, nil
   313  }
   314  
   315  // GetBalance get balance
   316  func (c *channelClient) GetBalance(in *types.ReqBalance) ([]*types.Account, error) {
   317  	// in.AssetExec & in.AssetSymbol 新增参数,
   318  	// 不填时兼容原来的调用
   319  	if in.AssetExec == "" || in.AssetSymbol == "" {
   320  		in.AssetSymbol = "trc"
   321  		in.AssetExec = "coins"
   322  		return c.accountdb.GetBalance(c.QueueProtocolAPI, in)
   323  	}
   324  
   325  	acc, err := account.NewAccountDB(c.QueueProtocolAPI.GetConfig(), in.AssetExec, in.AssetSymbol, nil)
   326  	if err != nil {
   327  		log.Error("GetBalance", "Error", err.Error())
   328  		return nil, err
   329  	}
   330  	return acc.GetBalance(c.QueueProtocolAPI, in)
   331  }
   332  
   333  // GetAllExecBalance get balance of exec
   334  func (c *channelClient) GetAllExecBalance(in *types.ReqAllExecBalance) (*types.AllExecBalance, error) {
   335  	types.AssertConfig(c.QueueProtocolAPI)
   336  	cfg := c.QueueProtocolAPI.GetConfig()
   337  	addr := in.Addr
   338  	err := address.CheckAddress(addr)
   339  	if err != nil {
   340  		if err = address.CheckMultiSignAddress(addr); err != nil {
   341  			return nil, types.ErrInvalidAddress
   342  		}
   343  	}
   344  	var addrs []string
   345  	addrs = append(addrs, addr)
   346  	allBalance := &types.AllExecBalance{Addr: addr}
   347  	for _, exec := range types.AllowUserExec {
   348  		execer := cfg.ExecName(string(exec))
   349  		params := &types.ReqBalance{
   350  			Addresses:   addrs,
   351  			Execer:      execer,
   352  			StateHash:   in.StateHash,
   353  			AssetExec:   in.AssetExec,
   354  			AssetSymbol: in.AssetSymbol,
   355  		}
   356  		res, err := c.GetBalance(params)
   357  		if err != nil {
   358  			continue
   359  		}
   360  		if len(res) < 1 {
   361  			continue
   362  		}
   363  		acc := res[0]
   364  		if acc.Balance == 0 && acc.Frozen == 0 {
   365  			continue
   366  		}
   367  		execAcc := &types.ExecAccount{Execer: execer, Account: acc}
   368  		allBalance.ExecAccount = append(allBalance.ExecAccount, execAcc)
   369  	}
   370  	return allBalance, nil
   371  }
   372  
   373  // GetTotalCoins get total of coins
   374  func (c *channelClient) GetTotalCoins(in *types.ReqGetTotalCoins) (*types.ReplyGetTotalCoins, error) {
   375  	//获取地址账户的余额通过account模块
   376  	resp, err := c.accountdb.GetTotalCoins(c.QueueProtocolAPI, in)
   377  	if err != nil {
   378  		return nil, err
   379  	}
   380  	return resp, nil
   381  }
   382  
   383  // DecodeRawTransaction decode rawtransaction
   384  func (c *channelClient) DecodeRawTransaction(param *types.ReqDecodeRawTransaction) (*types.Transaction, error) {
   385  	var tx types.Transaction
   386  	bytes, err := common.FromHex(param.TxHex)
   387  	if err != nil {
   388  		return nil, err
   389  	}
   390  	err = types.Decode(bytes, &tx)
   391  	if err != nil {
   392  		return nil, err
   393  	}
   394  	return &tx, nil
   395  }
   396  
   397  // GetTimeStatus get status of time
   398  func (c *channelClient) GetTimeStatus() (*types.TimeStatus, error) {
   399  	ntpTime := common.GetRealTimeRetry(c.GetConfig().GetModuleConfig().NtpHosts, 2)
   400  	local := time.Now()
   401  	if ntpTime.IsZero() {
   402  		return &types.TimeStatus{NtpTime: "", LocalTime: local.Format("2006-01-02 15:04:05"), Diff: 0}, nil
   403  	}
   404  	diff := local.Sub(ntpTime) / time.Second
   405  	return &types.TimeStatus{NtpTime: ntpTime.Format("2006-01-02 15:04:05"), LocalTime: local.Format("2006-01-02 15:04:05"), Diff: int64(diff)}, nil
   406  }
   407  
   408  // GetExecBalance get balance with exec by channelclient
   409  func (c *channelClient) GetExecBalance(in *types.ReqGetExecBalance) (*types.ReplyGetExecBalance, error) {
   410  	//通过account模块获取地址账户在合约中的余额
   411  	resp, err := c.accountdb.GetExecBalance(c.QueueProtocolAPI, in)
   412  	if err != nil {
   413  		return nil, err
   414  	}
   415  	return resp, nil
   416  }