github.com/turingchain2020/turingchain@v1.1.21/wallet/wallet_proc.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 wallet
     6  
     7  import (
     8  	"encoding/hex"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"os"
    12  	"strings"
    13  	"sync/atomic"
    14  	"time"
    15  	"unicode"
    16  
    17  	"github.com/turingchain2020/turingchain/account"
    18  	"github.com/turingchain2020/turingchain/common"
    19  	"github.com/turingchain2020/turingchain/common/address"
    20  	"github.com/turingchain2020/turingchain/common/crypto"
    21  	dbm "github.com/turingchain2020/turingchain/common/db"
    22  	cty "github.com/turingchain2020/turingchain/system/dapp/coins/types"
    23  	"github.com/turingchain2020/turingchain/types"
    24  	"github.com/turingchain2020/turingchain/wallet/bipwallet"
    25  	wcom "github.com/turingchain2020/turingchain/wallet/common"
    26  	"github.com/golang/protobuf/proto"
    27  )
    28  
    29  // ProcSignRawTx 用钱包对交易进行签名
    30  //input:
    31  //type ReqSignRawTx struct {
    32  //	Addr    string
    33  //	Privkey string
    34  //	TxHex   string
    35  //	Expire  string
    36  //}
    37  //output:
    38  //string
    39  //签名交易
    40  func (wallet *Wallet) ProcSignRawTx(unsigned *types.ReqSignRawTx) (string, error) {
    41  	wallet.mtx.Lock()
    42  	defer wallet.mtx.Unlock()
    43  	index := unsigned.Index
    44  
    45  	//Privacy交易功能,需要在隐私plugin里面检查,而不是所有交易签名都检查,在隐私启动scan时候会导致其他交易签名失败,同时这里在scaning时候,
    46  	//需要返回一个错误,而不是nil
    47  	//if ok, err := wallet.IsRescanUtxosFlagScaning(); ok || err != nil {
    48  	//	return "", err types.ErrNotSupport
    49  	//}
    50  
    51  	var key crypto.PrivKey
    52  	if unsigned.GetAddr() != "" {
    53  		ok, err := wallet.checkWalletStatus()
    54  		if !ok {
    55  			return "", err
    56  		}
    57  		key, err = wallet.getPrivKeyByAddr(unsigned.GetAddr())
    58  		if err != nil {
    59  			return "", err
    60  		}
    61  	} else if unsigned.GetPrivkey() != "" {
    62  		keyByte, err := common.FromHex(unsigned.GetPrivkey())
    63  		if err != nil {
    64  			return "", err
    65  		}
    66  		if len(keyByte) == 0 {
    67  			return "", types.ErrPrivateKeyLen
    68  		}
    69  		cr, err := crypto.New(types.GetSignName("", wallet.SignType))
    70  		if err != nil {
    71  			return "", err
    72  		}
    73  		key, err = cr.PrivKeyFromBytes(keyByte)
    74  		if err != nil {
    75  			return "", err
    76  		}
    77  	} else {
    78  		return "", types.ErrNoPrivKeyOrAddr
    79  	}
    80  
    81  	txByteData, err := common.FromHex(unsigned.GetTxHex())
    82  	if err != nil {
    83  		return "", err
    84  	}
    85  	var tx types.Transaction
    86  	err = types.Decode(txByteData, &tx)
    87  	if err != nil {
    88  		return "", err
    89  	}
    90  
    91  	if unsigned.NewToAddr != "" {
    92  		tx.To = unsigned.NewToAddr
    93  	}
    94  	if unsigned.Fee != 0 {
    95  		tx.Fee = unsigned.Fee
    96  	} else {
    97  		//get proper fee if not set
    98  		proper, err := wallet.api.GetProperFee(nil)
    99  		if err != nil {
   100  			return "", err
   101  		}
   102  		fee, err := tx.GetRealFee(proper.ProperFee)
   103  		if err != nil {
   104  			return "", err
   105  		}
   106  		tx.Fee = fee
   107  	}
   108  
   109  	expire, err := types.ParseExpire(unsigned.GetExpire())
   110  	if err != nil {
   111  		return "", err
   112  	}
   113  	types.AssertConfig(wallet.client)
   114  	cfg := wallet.client.GetConfig()
   115  	tx.SetExpire(cfg, time.Duration(expire))
   116  	if policy, ok := wcom.PolicyContainer[string(cfg.GetParaExec(tx.Execer))]; ok {
   117  		// 尝试让策略自己去完成签名
   118  		needSysSign, signtx, err := policy.SignTransaction(key, unsigned)
   119  		if !needSysSign {
   120  			return signtx, err
   121  		}
   122  	}
   123  
   124  	group, err := tx.GetTxGroup()
   125  	if err != nil {
   126  		return "", err
   127  	}
   128  	if group == nil {
   129  		tx.Sign(int32(wallet.SignType), key)
   130  		txHex := types.Encode(&tx)
   131  		signedTx := hex.EncodeToString(txHex)
   132  		return signedTx, nil
   133  	}
   134  	if int(index) > len(group.GetTxs()) {
   135  		return "", types.ErrIndex
   136  	}
   137  	if index <= 0 {
   138  		//设置过期需要重构
   139  		group.SetExpire(cfg, 0, time.Duration(expire))
   140  		group.RebuiltGroup()
   141  		for i := range group.Txs {
   142  			err := group.SignN(i, int32(wallet.SignType), key)
   143  			if err != nil {
   144  				return "", err
   145  			}
   146  		}
   147  		grouptx := group.Tx()
   148  		txHex := types.Encode(grouptx)
   149  		signedTx := hex.EncodeToString(txHex)
   150  		return signedTx, nil
   151  	}
   152  	index--
   153  	err = group.SignN(int(index), int32(wallet.SignType), key)
   154  	if err != nil {
   155  		return "", err
   156  	}
   157  	grouptx := group.Tx()
   158  	txHex := types.Encode(grouptx)
   159  	signedTx := hex.EncodeToString(txHex)
   160  	return signedTx, nil
   161  }
   162  
   163  // ProcGetAccount 通过地址标签获取账户地址
   164  func (wallet *Wallet) ProcGetAccount(req *types.ReqGetAccount) (*types.WalletAccount, error) {
   165  	wallet.mtx.Lock()
   166  	defer wallet.mtx.Unlock()
   167  	accStore, err := wallet.walletStore.GetAccountByLabel(req.GetLabel())
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  
   172  	accs, err := wallet.accountdb.LoadAccounts(wallet.api, []string{accStore.GetAddr()})
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	return &types.WalletAccount{Label: accStore.GetLabel(), Acc: accs[0]}, nil
   177  
   178  }
   179  
   180  // ProcGetAccountList 获取钱包账号列表
   181  //output:
   182  //type WalletAccounts struct {
   183  //	Wallets []*WalletAccount
   184  //type WalletAccount struct {
   185  //	Acc   *Account
   186  //	Label string
   187  //获取钱包的地址列表
   188  func (wallet *Wallet) ProcGetAccountList(req *types.ReqAccountList) (*types.WalletAccounts, error) {
   189  	wallet.mtx.Lock()
   190  	defer wallet.mtx.Unlock()
   191  
   192  	//通过Account前缀查找获取钱包中的所有账户信息
   193  	WalletAccStores, err := wallet.walletStore.GetAccountByPrefix("Account")
   194  	if err != nil || len(WalletAccStores) == 0 {
   195  		walletlog.Info("ProcGetAccountList", "GetAccountByPrefix:err", err)
   196  		return nil, err
   197  	}
   198  	if req.WithoutBalance {
   199  		return makeAccountWithoutBalance(WalletAccStores)
   200  	}
   201  
   202  	addrs := make([]string, len(WalletAccStores))
   203  	for index, AccStore := range WalletAccStores {
   204  		if len(AccStore.Addr) != 0 {
   205  			addrs[index] = AccStore.Addr
   206  		}
   207  	}
   208  	//获取所有地址对应的账户详细信息从account模块
   209  	accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs)
   210  	if err != nil || len(accounts) == 0 {
   211  		walletlog.Error("ProcGetAccountList", "LoadAccounts:err", err)
   212  		return nil, err
   213  	}
   214  
   215  	//异常打印信息
   216  	if len(WalletAccStores) != len(accounts) {
   217  		walletlog.Error("ProcGetAccountList err!", "AccStores)", len(WalletAccStores), "accounts", len(accounts))
   218  	}
   219  
   220  	var WalletAccounts types.WalletAccounts
   221  	WalletAccounts.Wallets = make([]*types.WalletAccount, len(WalletAccStores))
   222  
   223  	for index, Account := range accounts {
   224  		var WalletAccount types.WalletAccount
   225  		//此账户还没有参与交易所在account模块没有记录
   226  		if len(Account.Addr) == 0 {
   227  			Account.Addr = addrs[index]
   228  		}
   229  		WalletAccount.Acc = Account
   230  		WalletAccount.Label = WalletAccStores[index].GetLabel()
   231  		WalletAccounts.Wallets[index] = &WalletAccount
   232  	}
   233  	return &WalletAccounts, nil
   234  }
   235  
   236  func makeAccountWithoutBalance(accountStores []*types.WalletAccountStore) (*types.WalletAccounts, error) {
   237  	var WalletAccounts types.WalletAccounts
   238  	WalletAccounts.Wallets = make([]*types.WalletAccount, len(accountStores))
   239  
   240  	for index, account := range accountStores {
   241  		var WalletAccount types.WalletAccount
   242  		//此账户还没有参与交易所在account模块没有记录
   243  		if len(account.Addr) == 0 {
   244  			continue
   245  		}
   246  		WalletAccount.Acc = &types.Account{Addr: account.Addr}
   247  		WalletAccount.Label = account.GetLabel()
   248  		WalletAccounts.Wallets[index] = &WalletAccount
   249  	}
   250  	return &WalletAccounts, nil
   251  }
   252  
   253  // ProcCreateNewAccount 处理创建新账号
   254  //input:
   255  //type ReqNewAccount struct {
   256  //	Label string
   257  //output:
   258  //type WalletAccount struct {
   259  //	Acc   *Account
   260  //	Label string
   261  //type Account struct {
   262  //	Currency int32
   263  //	Balance  int64
   264  //	Frozen   int64
   265  //	Addr     string
   266  //创建一个新的账户
   267  func (wallet *Wallet) ProcCreateNewAccount(Label *types.ReqNewAccount) (*types.WalletAccount, error) {
   268  	wallet.mtx.Lock()
   269  	defer wallet.mtx.Unlock()
   270  
   271  	ok, err := wallet.checkWalletStatus()
   272  	if !ok {
   273  		return nil, err
   274  	}
   275  
   276  	if Label == nil || len(Label.GetLabel()) == 0 {
   277  		walletlog.Error("ProcCreateNewAccount Label is nil")
   278  		return nil, types.ErrInvalidParam
   279  	}
   280  
   281  	//首先校验label是否已被使用
   282  	WalletAccStores, err := wallet.walletStore.GetAccountByLabel(Label.GetLabel())
   283  	if WalletAccStores != nil && err == nil {
   284  		walletlog.Error("ProcCreateNewAccount Label is exist in wallet!")
   285  		return nil, types.ErrLabelHasUsed
   286  	}
   287  
   288  	var Account types.Account
   289  	var walletAccount types.WalletAccount
   290  	var WalletAccStore types.WalletAccountStore
   291  	var addr string
   292  	var privkeybyte []byte
   293  
   294  	cointype := wallet.GetCoinType()
   295  	//通过seed获取私钥, 首先通过钱包密码解锁seed然后通过seed生成私钥
   296  	seed, err := wallet.getSeed(wallet.Password)
   297  	if err != nil {
   298  		walletlog.Error("ProcCreateNewAccount", "getSeed err", err)
   299  		return nil, err
   300  	}
   301  
   302  	for {
   303  		privkeyhex, err := GetPrivkeyBySeed(wallet.walletStore.GetDB(), seed, 0, wallet.SignType, wallet.CoinType)
   304  		if err != nil {
   305  			walletlog.Error("ProcCreateNewAccount", "GetPrivkeyBySeed err", err)
   306  			return nil, err
   307  		}
   308  		privkeybyte, err = common.FromHex(privkeyhex)
   309  		if err != nil || len(privkeybyte) == 0 {
   310  			walletlog.Error("ProcCreateNewAccount", "FromHex err", err)
   311  			return nil, err
   312  		}
   313  
   314  		pub, err := bipwallet.PrivkeyToPub(cointype, uint32(wallet.SignType), privkeybyte)
   315  		if err != nil {
   316  			seedlog.Error("ProcCreateNewAccount PrivkeyToPub", "err", err)
   317  			return nil, types.ErrPrivkeyToPub
   318  		}
   319  		addr, err = bipwallet.PubToAddress(pub)
   320  		if err != nil {
   321  			seedlog.Error("ProcCreateNewAccount PubToAddress", "err", err)
   322  			return nil, types.ErrPrivkeyToPub
   323  		}
   324  		//通过新生成的账户地址查询钱包数据库,如果查询返回的账户信息是空,
   325  		//说明新生成的账户没有被使用,否则继续使用下一个index生成私钥对
   326  		account, err := wallet.walletStore.GetAccountByAddr(addr)
   327  		if account == nil || err != nil {
   328  			break
   329  		}
   330  	}
   331  
   332  	Account.Addr = addr
   333  	Account.Currency = 0
   334  	Account.Balance = 0
   335  	Account.Frozen = 0
   336  
   337  	walletAccount.Acc = &Account
   338  	walletAccount.Label = Label.GetLabel()
   339  
   340  	//使用钱包的password对私钥加密 aes cbc
   341  	Encrypted := wcom.CBCEncrypterPrivkey([]byte(wallet.Password), privkeybyte)
   342  	WalletAccStore.Privkey = common.ToHex(Encrypted)
   343  	WalletAccStore.Label = Label.GetLabel()
   344  	WalletAccStore.Addr = addr
   345  
   346  	//存储账户信息到wallet数据库中
   347  	err = wallet.walletStore.SetWalletAccount(false, Account.Addr, &WalletAccStore)
   348  	if err != nil {
   349  		return nil, err
   350  	}
   351  
   352  	//获取地址对应的账户信息从account模块
   353  	addrs := make([]string, 1)
   354  	addrs[0] = addr
   355  	accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs)
   356  	if err != nil {
   357  		walletlog.Error("ProcCreateNewAccount", "LoadAccounts err", err)
   358  		return nil, err
   359  	}
   360  	// 本账户是首次创建
   361  	if len(accounts[0].Addr) == 0 {
   362  		accounts[0].Addr = addr
   363  	}
   364  	walletAccount.Acc = accounts[0]
   365  
   366  	//从blockchain模块同步Account.Addr对应的所有交易详细信息
   367  	for _, policy := range wcom.PolicyContainer {
   368  		policy.OnCreateNewAccount(walletAccount.Acc)
   369  	}
   370  
   371  	return &walletAccount, nil
   372  }
   373  
   374  // ProcWalletTxList 处理获取钱包交易列表
   375  //input:
   376  //type ReqWalletTransactionList struct {
   377  //	FromTx []byte
   378  //	Count  int32
   379  //output:
   380  //type WalletTxDetails struct {
   381  //	TxDetails []*WalletTxDetail
   382  //type WalletTxDetail struct {
   383  //	Tx      *Transaction
   384  //	Receipt *ReceiptData
   385  //	Height  int64
   386  //	Index   int64
   387  //获取所有钱包的交易记录
   388  func (wallet *Wallet) ProcWalletTxList(TxList *types.ReqWalletTransactionList) (*types.WalletTxDetails, error) {
   389  	wallet.mtx.Lock()
   390  	defer wallet.mtx.Unlock()
   391  
   392  	if TxList == nil {
   393  		walletlog.Error("ProcWalletTxList TxList is nil!")
   394  		return nil, types.ErrInvalidParam
   395  	}
   396  	if TxList.GetDirection() != 0 && TxList.GetDirection() != 1 {
   397  		walletlog.Error("ProcWalletTxList Direction err!")
   398  		return nil, types.ErrInvalidParam
   399  	}
   400  	//默认取10笔交易数据
   401  	if TxList.Count == 0 {
   402  		TxList.Count = 10
   403  	}
   404  	if int64(TxList.Count) > types.MaxBlockCountPerTime {
   405  		return nil, types.ErrMaxCountPerTime
   406  	}
   407  
   408  	WalletTxDetails, err := wallet.walletStore.GetTxDetailByIter(TxList)
   409  	if err != nil {
   410  		walletlog.Error("ProcWalletTxList", "GetTxDetailByIter err", err)
   411  		return nil, err
   412  	}
   413  	return WalletTxDetails, nil
   414  }
   415  
   416  // ProcImportPrivKey 处理导入私钥
   417  //input:
   418  //type ReqWalletImportPrivKey struct {
   419  //	Privkey string
   420  //	Label   string
   421  //output:
   422  //type WalletAccount struct {
   423  //	Acc   *Account
   424  //	Label string
   425  //导入私钥,并且同时会导入交易
   426  func (wallet *Wallet) ProcImportPrivKey(PrivKey *types.ReqWalletImportPrivkey) (*types.WalletAccount, error) {
   427  	wallet.mtx.Lock()
   428  	defer wallet.mtx.Unlock()
   429  	walletaccount, err := wallet.procImportPrivKey(PrivKey)
   430  	return walletaccount, err
   431  }
   432  
   433  func (wallet *Wallet) procImportPrivKey(PrivKey *types.ReqWalletImportPrivkey) (*types.WalletAccount, error) {
   434  	ok, err := wallet.checkWalletStatus()
   435  	if !ok {
   436  		return nil, err
   437  	}
   438  
   439  	if PrivKey == nil || len(PrivKey.GetLabel()) == 0 || len(PrivKey.GetPrivkey()) == 0 {
   440  		walletlog.Error("ProcImportPrivKey input parameter is nil!")
   441  		return nil, types.ErrInvalidParam
   442  	}
   443  
   444  	//校验label是否已经被使用
   445  	Account, err := wallet.walletStore.GetAccountByLabel(PrivKey.GetLabel())
   446  	if Account != nil && err == nil {
   447  		walletlog.Error("ProcImportPrivKey Label is exist in wallet!")
   448  		return nil, types.ErrLabelHasUsed
   449  	}
   450  
   451  	cointype := wallet.GetCoinType()
   452  
   453  	privkeybyte, err := common.FromHex(PrivKey.Privkey)
   454  	if err != nil || len(privkeybyte) == 0 {
   455  		walletlog.Error("ProcImportPrivKey", "FromHex err", err)
   456  		return nil, types.ErrFromHex
   457  	}
   458  
   459  	pub, err := bipwallet.PrivkeyToPub(cointype, uint32(wallet.SignType), privkeybyte)
   460  	if err != nil {
   461  		seedlog.Error("ProcImportPrivKey PrivkeyToPub", "err", err)
   462  		return nil, types.ErrPrivkeyToPub
   463  	}
   464  
   465  	addr, err := bipwallet.PubToAddress(pub)
   466  	if err != nil {
   467  		seedlog.Error("ProcImportPrivKey PrivkeyToPub", "err", err)
   468  		return nil, types.ErrPrivkeyToPub
   469  	}
   470  
   471  	//对私钥加密
   472  	Encryptered := wcom.CBCEncrypterPrivkey([]byte(wallet.Password), privkeybyte)
   473  	Encrypteredstr := common.ToHex(Encryptered)
   474  	//校验PrivKey对应的addr是否已经存在钱包中
   475  	Account, err = wallet.walletStore.GetAccountByAddr(addr)
   476  	if Account != nil && err == nil {
   477  		if Account.Privkey == Encrypteredstr {
   478  			walletlog.Error("ProcImportPrivKey Privkey is exist in wallet!")
   479  			return nil, types.ErrPrivkeyExist
   480  		}
   481  		walletlog.Error("ProcImportPrivKey!", "Account.Privkey", Account.Privkey, "input Privkey", PrivKey.Privkey)
   482  		return nil, types.ErrPrivkey
   483  	}
   484  
   485  	var walletaccount types.WalletAccount
   486  	var WalletAccStore types.WalletAccountStore
   487  	WalletAccStore.Privkey = Encrypteredstr //存储加密后的私钥
   488  	WalletAccStore.Label = PrivKey.GetLabel()
   489  	WalletAccStore.Addr = addr
   490  	//存储Addr:label+privkey+addr到数据库
   491  	err = wallet.walletStore.SetWalletAccount(false, addr, &WalletAccStore)
   492  	if err != nil {
   493  		walletlog.Error("ProcImportPrivKey", "SetWalletAccount err", err)
   494  		return nil, err
   495  	}
   496  
   497  	//获取地址对应的账户信息从account模块
   498  	addrs := make([]string, 1)
   499  	addrs[0] = addr
   500  	accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs)
   501  	if err != nil {
   502  		walletlog.Error("ProcImportPrivKey", "LoadAccounts err", err)
   503  		return nil, err
   504  	}
   505  	// 本账户是首次创建
   506  	if len(accounts[0].Addr) == 0 {
   507  		accounts[0].Addr = addr
   508  	}
   509  	walletaccount.Acc = accounts[0]
   510  	walletaccount.Label = PrivKey.Label
   511  
   512  	for _, policy := range wcom.PolicyContainer {
   513  		policy.OnImportPrivateKey(accounts[0])
   514  	}
   515  	return &walletaccount, nil
   516  }
   517  
   518  // ProcSendToAddress 响应发送到地址
   519  //input:
   520  //type ReqWalletSendToAddress struct {
   521  //	From   string
   522  //	To     string
   523  //	Amount int64
   524  //	Note   string
   525  //output:
   526  //type ReplyHash struct {
   527  //	Hashe []byte
   528  //发送一笔交易给对方地址,返回交易hash
   529  func (wallet *Wallet) ProcSendToAddress(SendToAddress *types.ReqWalletSendToAddress) (*types.ReplyHash, error) {
   530  	wallet.mtx.Lock()
   531  	defer wallet.mtx.Unlock()
   532  
   533  	if SendToAddress == nil {
   534  		walletlog.Error("ProcSendToAddress input para is nil")
   535  		return nil, types.ErrInvalidParam
   536  	}
   537  	if len(SendToAddress.From) == 0 || len(SendToAddress.To) == 0 {
   538  		walletlog.Error("ProcSendToAddress input para From or To is nil!")
   539  		return nil, types.ErrInvalidParam
   540  	}
   541  
   542  	ok, err := wallet.isTransfer(SendToAddress.GetTo())
   543  	if !ok {
   544  		return nil, err
   545  	}
   546  
   547  	//获取from账户的余额从account模块,校验余额是否充足
   548  	addrs := make([]string, 1)
   549  	addrs[0] = SendToAddress.GetFrom()
   550  	var accounts []*types.Account
   551  	var tokenAccounts []*types.Account
   552  	accounts, err = wallet.accountdb.LoadAccounts(wallet.api, addrs)
   553  	if err != nil || len(accounts) == 0 {
   554  		walletlog.Error("ProcSendToAddress", "LoadAccounts err", err)
   555  		return nil, err
   556  	}
   557  	Balance := accounts[0].Balance
   558  	amount := SendToAddress.GetAmount()
   559  	//amount必须大于等于0
   560  	if amount < 0 {
   561  		return nil, types.ErrAmount
   562  	}
   563  	if !SendToAddress.IsToken {
   564  		if Balance-amount < wallet.FeeAmount {
   565  			return nil, types.ErrInsufficientBalance
   566  		}
   567  	} else {
   568  		//如果是token转账,一方面需要保证coin的余额满足fee,另一方面则需要保证token的余额满足转账操作
   569  		if Balance < wallet.FeeAmount {
   570  			return nil, types.ErrInsufficientBalance
   571  		}
   572  		if nil == wallet.accTokenMap[SendToAddress.TokenSymbol] {
   573  			tokenAccDB, err := account.NewAccountDB(wallet.api.GetConfig(), "token", SendToAddress.TokenSymbol, nil)
   574  			if err != nil {
   575  				return nil, err
   576  			}
   577  			wallet.accTokenMap[SendToAddress.TokenSymbol] = tokenAccDB
   578  		}
   579  		tokenAccDB := wallet.accTokenMap[SendToAddress.TokenSymbol]
   580  		tokenAccounts, err = tokenAccDB.LoadAccounts(wallet.api, addrs)
   581  		if err != nil || len(tokenAccounts) == 0 {
   582  			walletlog.Error("ProcSendToAddress", "Load Token Accounts err", err)
   583  			return nil, err
   584  		}
   585  		tokenBalance := tokenAccounts[0].Balance
   586  		if tokenBalance < amount {
   587  			return nil, types.ErrInsufficientTokenBal
   588  		}
   589  	}
   590  	addrto := SendToAddress.GetTo()
   591  	note := SendToAddress.GetNote()
   592  	priv, err := wallet.getPrivKeyByAddr(addrs[0])
   593  	if err != nil {
   594  		return nil, err
   595  	}
   596  	return wallet.sendToAddress(priv, addrto, amount, note, SendToAddress.IsToken, SendToAddress.TokenSymbol)
   597  }
   598  
   599  // ProcWalletSetFee 处理设置手续费
   600  //type ReqWalletSetFee struct {
   601  //	Amount int64
   602  //设置钱包默认的手续费
   603  func (wallet *Wallet) ProcWalletSetFee(WalletSetFee *types.ReqWalletSetFee) error {
   604  	if WalletSetFee.Amount < wallet.minFee {
   605  		walletlog.Error("ProcWalletSetFee err!", "Amount", WalletSetFee.Amount, "MinFee", wallet.minFee)
   606  		return types.ErrInvalidParam
   607  	}
   608  	err := wallet.walletStore.SetFeeAmount(WalletSetFee.Amount)
   609  	if err == nil {
   610  		walletlog.Debug("ProcWalletSetFee success!")
   611  		wallet.mtx.Lock()
   612  		wallet.FeeAmount = WalletSetFee.Amount
   613  		wallet.mtx.Unlock()
   614  	}
   615  	return err
   616  }
   617  
   618  // ProcWalletSetLabel 处理设置账号标签
   619  //input:
   620  //type ReqWalletSetLabel struct {
   621  //	Addr  string
   622  //	Label string
   623  //output:
   624  //type WalletAccount struct {
   625  //	Acc   *Account
   626  //	Label string
   627  //设置某个账户的标签
   628  func (wallet *Wallet) ProcWalletSetLabel(SetLabel *types.ReqWalletSetLabel) (*types.WalletAccount, error) {
   629  	wallet.mtx.Lock()
   630  	defer wallet.mtx.Unlock()
   631  
   632  	if SetLabel == nil || len(SetLabel.Addr) == 0 || len(SetLabel.Label) == 0 {
   633  		walletlog.Error("ProcWalletSetLabel input parameter is nil!")
   634  		return nil, types.ErrInvalidParam
   635  	}
   636  	//校验label是否已经被使用
   637  	Account, err := wallet.walletStore.GetAccountByLabel(SetLabel.GetLabel())
   638  	if Account != nil && err == nil {
   639  		walletlog.Error("ProcWalletSetLabel Label is exist in wallet!")
   640  		return nil, types.ErrLabelHasUsed
   641  	}
   642  	//获取地址对应的账户信息从钱包中,然后修改label
   643  	Account, err = wallet.walletStore.GetAccountByAddr(SetLabel.Addr)
   644  	if err == nil && Account != nil {
   645  		oldLabel := Account.Label
   646  		Account.Label = SetLabel.GetLabel()
   647  		err := wallet.walletStore.SetWalletAccount(true, SetLabel.Addr, Account)
   648  		if err == nil {
   649  			//新的label设置成功之后需要删除旧的label在db的数据
   650  			wallet.walletStore.DelAccountByLabel(oldLabel)
   651  
   652  			//获取地址对应的账户详细信息从account模块
   653  			addrs := make([]string, 1)
   654  			addrs[0] = SetLabel.Addr
   655  			accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs)
   656  			if err != nil || len(accounts) == 0 {
   657  				walletlog.Error("ProcWalletSetLabel", "LoadAccounts err", err)
   658  				return nil, err
   659  			}
   660  			var walletAccount types.WalletAccount
   661  			walletAccount.Acc = accounts[0]
   662  			walletAccount.Label = SetLabel.GetLabel()
   663  			return &walletAccount, err
   664  		}
   665  	}
   666  	return nil, err
   667  }
   668  
   669  // ProcMergeBalance 处理
   670  //input:
   671  //type ReqWalletMergeBalance struct {
   672  //	To string
   673  //output:
   674  //type ReplyHashes struct {
   675  //	Hashes [][]byte
   676  //合并所有的balance 到一个地址
   677  func (wallet *Wallet) ProcMergeBalance(MergeBalance *types.ReqWalletMergeBalance) (*types.ReplyHashes, error) {
   678  	wallet.mtx.Lock()
   679  	defer wallet.mtx.Unlock()
   680  
   681  	ok, err := wallet.checkWalletStatus()
   682  	if !ok {
   683  		return nil, err
   684  	}
   685  
   686  	if len(MergeBalance.GetTo()) == 0 {
   687  		walletlog.Error("ProcMergeBalance input para is nil!")
   688  		return nil, types.ErrInvalidParam
   689  	}
   690  
   691  	//获取钱包上的所有账户信息
   692  	WalletAccStores, err := wallet.walletStore.GetAccountByPrefix("Account")
   693  	if err != nil || len(WalletAccStores) == 0 {
   694  		walletlog.Error("ProcMergeBalance", "GetAccountByPrefix err", err)
   695  		return nil, err
   696  	}
   697  
   698  	addrs := make([]string, len(WalletAccStores))
   699  	for index, AccStore := range WalletAccStores {
   700  		if len(AccStore.Addr) != 0 {
   701  			addrs[index] = AccStore.Addr
   702  		}
   703  	}
   704  	//获取所有地址对应的账户信息从account模块
   705  	accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs)
   706  	if err != nil || len(accounts) == 0 {
   707  		walletlog.Error("ProcMergeBalance", "LoadAccounts err", err)
   708  		return nil, err
   709  	}
   710  
   711  	//异常信息记录
   712  	if len(WalletAccStores) != len(accounts) {
   713  		walletlog.Error("ProcMergeBalance", "AccStores", len(WalletAccStores), "accounts", len(accounts))
   714  	}
   715  	//通过privkey生成一个pubkey然后换算成对应的addr
   716  	cr, err := crypto.New(types.GetSignName("", wallet.SignType))
   717  	if err != nil {
   718  		walletlog.Error("ProcMergeBalance", "err", err)
   719  		return nil, err
   720  	}
   721  
   722  	addrto := MergeBalance.GetTo()
   723  	note := "MergeBalance"
   724  
   725  	var ReplyHashes types.ReplyHashes
   726  
   727  	types.AssertConfig(wallet.client)
   728  	cfg := wallet.client.GetConfig()
   729  	for index, Account := range accounts {
   730  		Privkey := WalletAccStores[index].Privkey
   731  		//解密存储的私钥
   732  		prikeybyte, err := common.FromHex(Privkey)
   733  		if err != nil || len(prikeybyte) == 0 {
   734  			walletlog.Error("ProcMergeBalance", "FromHex err", err, "index", index)
   735  			continue
   736  		}
   737  
   738  		privkey := wcom.CBCDecrypterPrivkey([]byte(wallet.Password), prikeybyte)
   739  		priv, err := cr.PrivKeyFromBytes(privkey)
   740  		if err != nil {
   741  			walletlog.Error("ProcMergeBalance", "PrivKeyFromBytes err", err, "index", index)
   742  			continue
   743  		}
   744  		//过滤掉to地址
   745  		if Account.Addr == addrto {
   746  			continue
   747  		}
   748  		//获取账户的余额,过滤掉余额不足的地址
   749  		amount := Account.GetBalance()
   750  		if amount < wallet.FeeAmount {
   751  			continue
   752  		}
   753  		amount = amount - wallet.FeeAmount
   754  		v := &cty.CoinsAction_Transfer{
   755  			Transfer: &types.AssetsTransfer{Amount: amount, Note: []byte(note)},
   756  		}
   757  		if cfg.IsPara() {
   758  			v.Transfer.To = MergeBalance.GetTo()
   759  		}
   760  		transfer := &cty.CoinsAction{Value: v, Ty: cty.CoinsActionTransfer}
   761  		//初始化随机数
   762  		exec := []byte("coins")
   763  		toAddr := addrto
   764  		if cfg.IsPara() {
   765  			exec = []byte(cfg.GetTitle() + "coins")
   766  			toAddr = address.ExecAddress(string(exec))
   767  		}
   768  		tx := &types.Transaction{Execer: exec, Payload: types.Encode(transfer), Fee: wallet.FeeAmount, To: toAddr, Nonce: wallet.random.Int63()}
   769  		tx.ChainID = cfg.GetChainID()
   770  
   771  		tx.SetExpire(cfg, time.Second*120)
   772  		tx.Sign(int32(wallet.SignType), priv)
   773  		//walletlog.Info("ProcMergeBalance", "tx.Nonce", tx.Nonce, "tx", tx, "index", index)
   774  
   775  		//发送交易信息给mempool模块
   776  		msg := wallet.client.NewMessage("mempool", types.EventTx, tx)
   777  		err = wallet.client.Send(msg, true)
   778  		if err != nil {
   779  			walletlog.Error("ProcMergeBalance", "Send tx err", err, "index", index)
   780  			continue
   781  		}
   782  		resp, err := wallet.client.Wait(msg)
   783  		if err != nil {
   784  			walletlog.Error("ProcMergeBalance", "Send tx err", err, "index", index)
   785  			continue
   786  		}
   787  		//如果交易在mempool校验失败,不记录此交易
   788  		reply := resp.GetData().(*types.Reply)
   789  		if !reply.GetIsOk() {
   790  			walletlog.Error("ProcMergeBalance", "Send tx err", string(reply.GetMsg()), "index", index)
   791  			continue
   792  		}
   793  		ReplyHashes.Hashes = append(ReplyHashes.Hashes, tx.Hash())
   794  	}
   795  	return &ReplyHashes, nil
   796  }
   797  
   798  // ProcWalletSetPasswd 处理钱包的保存密码
   799  //input:
   800  //type ReqWalletSetPasswd struct {
   801  //	Oldpass string
   802  //	Newpass string
   803  //设置或者修改密码
   804  func (wallet *Wallet) ProcWalletSetPasswd(Passwd *types.ReqWalletSetPasswd) error {
   805  	wallet.mtx.Lock()
   806  	defer wallet.mtx.Unlock()
   807  
   808  	isok, err := wallet.checkWalletStatus()
   809  	if !isok && err == types.ErrSaveSeedFirst {
   810  		return err
   811  	}
   812  	// 新密码合法性校验
   813  	if !isValidPassWord(Passwd.NewPass) {
   814  		return types.ErrInvalidPassWord
   815  	}
   816  	//保存钱包的锁状态,需要暂时的解锁,函数退出时再恢复回去
   817  	tempislock := atomic.LoadInt32(&wallet.isWalletLocked)
   818  	//wallet.isWalletLocked = false
   819  	atomic.CompareAndSwapInt32(&wallet.isWalletLocked, 1, 0)
   820  
   821  	defer func() {
   822  		//wallet.isWalletLocked = tempislock
   823  		atomic.CompareAndSwapInt32(&wallet.isWalletLocked, 0, tempislock)
   824  	}()
   825  
   826  	// 钱包已经加密需要验证oldpass的正确性
   827  	if len(wallet.Password) == 0 && wallet.EncryptFlag == 1 {
   828  		isok := wallet.walletStore.VerifyPasswordHash(Passwd.OldPass)
   829  		if !isok {
   830  			walletlog.Error("ProcWalletSetPasswd Verify Oldpasswd fail!")
   831  			return types.ErrVerifyOldpasswdFail
   832  		}
   833  	}
   834  
   835  	if len(wallet.Password) != 0 && Passwd.OldPass != wallet.Password {
   836  		walletlog.Error("ProcWalletSetPasswd Oldpass err!")
   837  		return types.ErrVerifyOldpasswdFail
   838  	}
   839  
   840  	//使用新的密码生成passwdhash用于下次密码的验证
   841  	newBatch := wallet.walletStore.NewBatch(true)
   842  	err = wallet.walletStore.SetPasswordHash(Passwd.NewPass, newBatch)
   843  	if err != nil {
   844  		walletlog.Error("ProcWalletSetPasswd", "SetPasswordHash err", err)
   845  		return err
   846  	}
   847  	//设置钱包加密标志位
   848  	err = wallet.walletStore.SetEncryptionFlag(newBatch)
   849  	if err != nil {
   850  		walletlog.Error("ProcWalletSetPasswd", "SetEncryptionFlag err", err)
   851  		return err
   852  	}
   853  	//使用old密码解密seed然后用新的钱包密码重新加密seed
   854  	seed, err := wallet.getSeed(Passwd.OldPass)
   855  	if err != nil {
   856  		walletlog.Error("ProcWalletSetPasswd", "getSeed err", err)
   857  		return err
   858  	}
   859  	ok, err := SaveSeedInBatch(wallet.walletStore.GetDB(), seed, Passwd.NewPass, newBatch)
   860  	if !ok {
   861  		walletlog.Error("ProcWalletSetPasswd", "SaveSeed err", err)
   862  		return err
   863  	}
   864  
   865  	//对所有存储的私钥重新使用新的密码加密,通过Account前缀查找获取钱包中的所有账户信息
   866  	WalletAccStores, err := wallet.walletStore.GetAccountByPrefix("Account")
   867  	if err != nil || len(WalletAccStores) == 0 {
   868  		walletlog.Error("ProcWalletSetPasswd", "GetAccountByPrefix:err", err)
   869  	}
   870  
   871  	for _, AccStore := range WalletAccStores {
   872  		//使用old Password解密存储的私钥
   873  		storekey, err := common.FromHex(AccStore.GetPrivkey())
   874  		if err != nil || len(storekey) == 0 {
   875  			walletlog.Info("ProcWalletSetPasswd", "addr", AccStore.Addr, "FromHex err", err)
   876  			continue
   877  		}
   878  		Decrypter := wcom.CBCDecrypterPrivkey([]byte(Passwd.OldPass), storekey)
   879  
   880  		//使用新的密码重新加密私钥
   881  		Encrypter := wcom.CBCEncrypterPrivkey([]byte(Passwd.NewPass), Decrypter)
   882  		AccStore.Privkey = common.ToHex(Encrypter)
   883  		err = wallet.walletStore.SetWalletAccountInBatch(true, AccStore.Addr, AccStore, newBatch)
   884  		if err != nil {
   885  			walletlog.Info("ProcWalletSetPasswd", "addr", AccStore.Addr, "SetWalletAccount err", err)
   886  		}
   887  	}
   888  
   889  	err = newBatch.Write()
   890  	if err != nil {
   891  		walletlog.Error("ProcWalletSetPasswd newBatch.Write", "err", err)
   892  		return err
   893  	}
   894  	wallet.Password = Passwd.NewPass
   895  	wallet.EncryptFlag = 1
   896  	return nil
   897  }
   898  
   899  //ProcWalletLock 锁定钱包
   900  func (wallet *Wallet) ProcWalletLock() error {
   901  	//判断钱包是否已保存seed
   902  	has, err := wallet.walletStore.HasSeed()
   903  	if !has || err != nil {
   904  		return types.ErrSaveSeedFirst
   905  	}
   906  
   907  	atomic.CompareAndSwapInt32(&wallet.isWalletLocked, 0, 1)
   908  	for _, policy := range wcom.PolicyContainer {
   909  		policy.OnWalletLocked()
   910  	}
   911  	return nil
   912  }
   913  
   914  // ProcWalletUnLock 处理钱包解锁
   915  //input:
   916  //type WalletUnLock struct {
   917  //	Passwd  string
   918  //	Timeout int64
   919  //解锁钱包Timeout时间,超时后继续锁住
   920  func (wallet *Wallet) ProcWalletUnLock(WalletUnLock *types.WalletUnLock) error {
   921  	wallet.mtx.Lock()
   922  	defer wallet.mtx.Unlock()
   923  
   924  	//判断钱包是否已保存seed
   925  	has, err := wallet.walletStore.HasSeed()
   926  	if !has || err != nil {
   927  		return types.ErrSaveSeedFirst
   928  	}
   929  	// 钱包已经加密需要验证passwd的正确性
   930  	if len(wallet.Password) == 0 && wallet.EncryptFlag == 1 {
   931  		isok := wallet.walletStore.VerifyPasswordHash(WalletUnLock.Passwd)
   932  		if !isok {
   933  			walletlog.Error("ProcWalletUnLock Verify Oldpasswd fail!")
   934  			return types.ErrVerifyOldpasswdFail
   935  		}
   936  	}
   937  	//内存中已经记录password时的校验
   938  	if len(wallet.Password) != 0 && WalletUnLock.Passwd != wallet.Password {
   939  		return types.ErrInputPassword
   940  	}
   941  	//本钱包没有设置密码加密过,只需要解锁不需要记录解锁密码
   942  	wallet.Password = WalletUnLock.Passwd
   943  	//只解锁挖矿转账
   944  	if !WalletUnLock.WalletOrTicket {
   945  		//wallet.isTicketLocked = false
   946  		atomic.CompareAndSwapInt32(&wallet.isWalletLocked, 1, 0)
   947  		if WalletUnLock.Timeout != 0 {
   948  			wallet.resetTimeout(WalletUnLock.Timeout)
   949  		}
   950  	}
   951  	for _, policy := range wcom.PolicyContainer {
   952  		policy.OnWalletUnlocked(WalletUnLock)
   953  	}
   954  	return nil
   955  
   956  }
   957  
   958  //解锁超时处理,需要区分整个钱包的解锁或者只挖矿的解锁
   959  func (wallet *Wallet) resetTimeout(Timeout int64) {
   960  	if wallet.timeout == nil {
   961  		wallet.timeout = time.AfterFunc(time.Second*time.Duration(Timeout), func() {
   962  			//wallet.isWalletLocked = true
   963  			atomic.CompareAndSwapInt32(&wallet.isWalletLocked, 0, 1)
   964  		})
   965  	} else {
   966  		wallet.timeout.Reset(time.Second * time.Duration(Timeout))
   967  	}
   968  }
   969  
   970  //ProcWalletAddBlock wallet模块收到blockchain广播的addblock消息,需要解析钱包相关的tx并存储到db中
   971  func (wallet *Wallet) ProcWalletAddBlock(block *types.BlockDetail) {
   972  	if block == nil {
   973  		walletlog.Error("ProcWalletAddBlock input para is nil!")
   974  		return
   975  	}
   976  	//walletlog.Error("ProcWalletAddBlock", "height", block.GetBlock().GetHeight())
   977  	types.AssertConfig(wallet.client)
   978  	cfg := wallet.client.GetConfig()
   979  	txlen := len(block.Block.GetTxs())
   980  	newbatch := wallet.walletStore.GetBlockBatch(true)
   981  	defer wallet.walletStore.FreeBlockBatch()
   982  	for index := 0; index < txlen; index++ {
   983  		tx := block.Block.Txs[index]
   984  		execer := string(cfg.GetParaExec(tx.Execer))
   985  		// 执行钱包业务逻辑策略
   986  		if policy, ok := wcom.PolicyContainer[execer]; ok {
   987  			wtxdetail := policy.OnAddBlockTx(block, tx, int32(index), newbatch)
   988  			if wtxdetail == nil {
   989  				continue
   990  			}
   991  			if len(wtxdetail.Fromaddr) > 0 {
   992  				txdetailbyte, err := proto.Marshal(wtxdetail)
   993  				if err != nil {
   994  					walletlog.Error("ProcWalletAddBlock", "Marshal txdetail error", err, "Height", block.Block.Height, "index", index)
   995  					continue
   996  				}
   997  				blockheight := block.Block.Height*maxTxNumPerBlock + int64(index)
   998  				heightstr := fmt.Sprintf("%018d", blockheight)
   999  				key := wcom.CalcTxKey(heightstr)
  1000  				newbatch.Set(key, txdetailbyte)
  1001  			}
  1002  
  1003  		} else { // 默认的执行器类型处理
  1004  			// TODO: 钱包基础功能模块,将会重新建立一个处理策略,将钱包变成一个容器
  1005  			//获取from地址
  1006  			pubkey := block.Block.Txs[index].Signature.GetPubkey()
  1007  			addr := address.PubKeyToAddress(pubkey)
  1008  			param := &buildStoreWalletTxDetailParam{
  1009  				tokenname:  "",
  1010  				block:      block,
  1011  				tx:         tx,
  1012  				index:      index,
  1013  				newbatch:   newbatch,
  1014  				isprivacy:  false,
  1015  				addDelType: AddTx,
  1016  				//utxos:      nil,
  1017  			}
  1018  			//from addr
  1019  			fromaddress := addr.String()
  1020  			param.senderRecver = fromaddress
  1021  			if len(fromaddress) != 0 && wallet.AddrInWallet(fromaddress) {
  1022  				param.sendRecvFlag = sendTx
  1023  				wallet.buildAndStoreWalletTxDetail(param)
  1024  				walletlog.Debug("ProcWalletAddBlock", "fromaddress", fromaddress)
  1025  				continue
  1026  			}
  1027  			//toaddr获取交易中真实的接收地址,主要是针对para
  1028  			toaddr := tx.GetRealToAddr()
  1029  			if len(toaddr) != 0 && wallet.AddrInWallet(toaddr) {
  1030  				param.sendRecvFlag = recvTx
  1031  				wallet.buildAndStoreWalletTxDetail(param)
  1032  				walletlog.Debug("ProcWalletAddBlock", "toaddr", toaddr)
  1033  				continue
  1034  			}
  1035  		}
  1036  	}
  1037  	err := newbatch.Write()
  1038  	if err != nil {
  1039  		walletlog.Error("ProcWalletAddBlock newbatch.Write", "err", err)
  1040  		atomic.CompareAndSwapInt32(&wallet.fatalFailureFlag, 0, 1)
  1041  	}
  1042  
  1043  	for _, policy := range wcom.PolicyContainer {
  1044  		policy.OnAddBlockFinish(block)
  1045  	}
  1046  }
  1047  
  1048  //
  1049  type buildStoreWalletTxDetailParam struct {
  1050  	tokenname    string
  1051  	block        *types.BlockDetail
  1052  	tx           *types.Transaction
  1053  	index        int
  1054  	newbatch     dbm.Batch
  1055  	senderRecver string
  1056  	isprivacy    bool
  1057  	addDelType   int32
  1058  	sendRecvFlag int32
  1059  	//utxos        []*types.UTXO
  1060  }
  1061  
  1062  func (wallet *Wallet) buildAndStoreWalletTxDetail(param *buildStoreWalletTxDetailParam) {
  1063  	blockheight := param.block.Block.Height*maxTxNumPerBlock + int64(param.index)
  1064  	heightstr := fmt.Sprintf("%018d", blockheight)
  1065  	walletlog.Debug("buildAndStoreWalletTxDetail", "heightstr", heightstr, "addDelType", param.addDelType)
  1066  	if AddTx == param.addDelType {
  1067  		var txdetail types.WalletTxDetail
  1068  		var Err error
  1069  		key := wcom.CalcTxKey(heightstr)
  1070  		txdetail.Tx = param.tx
  1071  		txdetail.Height = param.block.Block.Height
  1072  		txdetail.Index = int64(param.index)
  1073  		txdetail.Receipt = param.block.Receipts[param.index]
  1074  		txdetail.Blocktime = param.block.Block.BlockTime
  1075  		txdetail.Txhash = param.tx.Hash()
  1076  		txdetail.ActionName = txdetail.Tx.ActionName()
  1077  		txdetail.Amount, Err = param.tx.Amount()
  1078  		if Err != nil {
  1079  			walletlog.Error("buildAndStoreWalletTxDetail Amount err", "Height", param.block.Block.Height, "index", param.index)
  1080  		}
  1081  		txdetail.Fromaddr = param.senderRecver
  1082  		//txdetail.Spendrecv = param.utxos
  1083  
  1084  		txdetailbyte, err := proto.Marshal(&txdetail)
  1085  		if err != nil {
  1086  			walletlog.Error("buildAndStoreWalletTxDetail Marshal txdetail err", "Height", param.block.Block.Height, "index", param.index)
  1087  			return
  1088  		}
  1089  		param.newbatch.Set(key, txdetailbyte)
  1090  	} else {
  1091  		param.newbatch.Delete(wcom.CalcTxKey(heightstr))
  1092  	}
  1093  }
  1094  
  1095  //ProcWalletDelBlock wallet模块收到blockchain广播的delblock消息,需要解析钱包相关的tx并存db中删除
  1096  func (wallet *Wallet) ProcWalletDelBlock(block *types.BlockDetail) {
  1097  	if block == nil {
  1098  		walletlog.Error("ProcWalletDelBlock input para is nil!")
  1099  		return
  1100  	}
  1101  	//walletlog.Error("ProcWalletDelBlock", "height", block.GetBlock().GetHeight())
  1102  	types.AssertConfig(wallet.client)
  1103  	cfg := wallet.client.GetConfig()
  1104  	txlen := len(block.Block.GetTxs())
  1105  	newbatch := wallet.walletStore.GetBlockBatch(true)
  1106  	defer wallet.walletStore.FreeBlockBatch()
  1107  	for index := txlen - 1; index >= 0; index-- {
  1108  		blockheight := block.Block.Height*maxTxNumPerBlock + int64(index)
  1109  		heightstr := fmt.Sprintf("%018d", blockheight)
  1110  		tx := block.Block.Txs[index]
  1111  
  1112  		execer := string(cfg.GetParaExec(tx.Execer))
  1113  		// 执行钱包业务逻辑策略
  1114  		if policy, ok := wcom.PolicyContainer[execer]; ok {
  1115  			wtxdetail := policy.OnDeleteBlockTx(block, tx, int32(index), newbatch)
  1116  			if wtxdetail == nil {
  1117  				continue
  1118  			}
  1119  			if len(wtxdetail.Fromaddr) > 0 {
  1120  				newbatch.Delete(wcom.CalcTxKey(heightstr))
  1121  			}
  1122  
  1123  		} else { // 默认的合约处理流程
  1124  			// TODO:将钱包基础功能移动到专属钱包基础业务的模块中,将钱包模块变成容器
  1125  			//获取from地址
  1126  			pubkey := tx.Signature.GetPubkey()
  1127  			addr := address.PubKeyToAddress(pubkey)
  1128  			fromaddress := addr.String()
  1129  			if len(fromaddress) != 0 && wallet.AddrInWallet(fromaddress) {
  1130  				newbatch.Delete(wcom.CalcTxKey(heightstr))
  1131  				continue
  1132  			}
  1133  			//toaddr
  1134  			toaddr := tx.GetRealToAddr()
  1135  			if len(toaddr) != 0 && wallet.AddrInWallet(toaddr) {
  1136  				newbatch.Delete(wcom.CalcTxKey(heightstr))
  1137  			}
  1138  		}
  1139  	}
  1140  	err := newbatch.Write()
  1141  	if err != nil {
  1142  		walletlog.Error("ProcWalletDelBlock newbatch.Write", "err", err)
  1143  	}
  1144  	for _, policy := range wcom.PolicyContainer {
  1145  		policy.OnDeleteBlockFinish(block)
  1146  	}
  1147  }
  1148  
  1149  // GetTxDetailByHashs 根据交易哈希获取对应的交易详情
  1150  func (wallet *Wallet) GetTxDetailByHashs(ReqHashes *types.ReqHashes) {
  1151  	//通过txhashs获取对应的txdetail
  1152  	msg := wallet.client.NewMessage("blockchain", types.EventGetTransactionByHash, ReqHashes)
  1153  	err := wallet.client.Send(msg, true)
  1154  	if err != nil {
  1155  		walletlog.Error("GetTxDetailByHashs Send EventGetTransactionByHash", "err", err)
  1156  		return
  1157  	}
  1158  	resp, err := wallet.client.Wait(msg)
  1159  	if err != nil {
  1160  		walletlog.Error("GetTxDetailByHashs EventGetTransactionByHash", "err", err)
  1161  		return
  1162  	}
  1163  	TxDetails := resp.GetData().(*types.TransactionDetails)
  1164  	if TxDetails == nil {
  1165  		walletlog.Info("GetTxDetailByHashs TransactionDetails is nil")
  1166  		return
  1167  	}
  1168  
  1169  	//批量存储地址对应的所有交易的详细信息到wallet db中
  1170  	newbatch := wallet.walletStore.NewBatch(true)
  1171  	for _, txdetal := range TxDetails.Txs {
  1172  		height := txdetal.GetHeight()
  1173  		txindex := txdetal.GetIndex()
  1174  
  1175  		blockheight := height*maxTxNumPerBlock + txindex
  1176  		heightstr := fmt.Sprintf("%018d", blockheight)
  1177  		var txdetail types.WalletTxDetail
  1178  		txdetail.Tx = txdetal.GetTx()
  1179  		txdetail.Height = txdetal.GetHeight()
  1180  		txdetail.Index = txdetal.GetIndex()
  1181  		txdetail.Receipt = txdetal.GetReceipt()
  1182  		txdetail.Blocktime = txdetal.GetBlocktime()
  1183  		txdetail.Amount = txdetal.GetAmount()
  1184  		txdetail.Fromaddr = txdetal.GetFromaddr()
  1185  		txdetail.ActionName = txdetal.GetTx().ActionName()
  1186  
  1187  		txdetailbyte, err := proto.Marshal(&txdetail)
  1188  		if err != nil {
  1189  			walletlog.Error("GetTxDetailByHashs Marshal txdetail err", "Height", height, "index", txindex)
  1190  			return
  1191  		}
  1192  		newbatch.Set(wcom.CalcTxKey(heightstr), txdetailbyte)
  1193  	}
  1194  	err = newbatch.Write()
  1195  	if err != nil {
  1196  		walletlog.Error("GetTxDetailByHashs newbatch.Write", "err", err)
  1197  	}
  1198  }
  1199  
  1200  //生成一个随机的seed种子, 目前支持英文单词和简体中文
  1201  func (wallet *Wallet) genSeed(lang int32) (*types.ReplySeed, error) {
  1202  	seed, err := CreateSeed("", lang)
  1203  	if err != nil {
  1204  		walletlog.Error("genSeed", "CreateSeed err", err)
  1205  		return nil, err
  1206  	}
  1207  	var ReplySeed types.ReplySeed
  1208  	ReplySeed.Seed = seed
  1209  	return &ReplySeed, nil
  1210  }
  1211  
  1212  // GenSeed 获取随机种子
  1213  func (wallet *Wallet) GenSeed(lang int32) (*types.ReplySeed, error) {
  1214  	return wallet.genSeed(lang)
  1215  }
  1216  
  1217  //GetSeed 获取seed种子, 通过钱包密码
  1218  func (wallet *Wallet) GetSeed(password string) (string, error) {
  1219  	wallet.mtx.Lock()
  1220  	defer wallet.mtx.Unlock()
  1221  
  1222  	return wallet.getSeed(password)
  1223  }
  1224  
  1225  //获取seed种子, 通过钱包密码
  1226  func (wallet *Wallet) getSeed(password string) (string, error) {
  1227  	ok, err := wallet.checkWalletStatus()
  1228  	if !ok {
  1229  		return "", err
  1230  	}
  1231  
  1232  	seed, err := GetSeed(wallet.walletStore.GetDB(), password)
  1233  	if err != nil {
  1234  		walletlog.Error("getSeed", "GetSeed err", err)
  1235  		return "", err
  1236  	}
  1237  	return seed, nil
  1238  }
  1239  
  1240  // SaveSeed 保存种子
  1241  func (wallet *Wallet) SaveSeed(password string, seed string) (bool, error) {
  1242  	return wallet.saveSeed(password, seed)
  1243  }
  1244  
  1245  //保存seed种子到数据库中, 并通过钱包密码加密, 钱包起来首先要设置seed
  1246  func (wallet *Wallet) saveSeed(password string, seed string) (bool, error) {
  1247  	wallet.mtx.Lock()
  1248  	defer wallet.mtx.Unlock()
  1249  
  1250  	//首先需要判断钱包是否已经设置seed,如果已经设置提示不需要再设置,一个钱包只能保存一个seed
  1251  	exit, err := wallet.walletStore.HasSeed()
  1252  	if exit && err == nil {
  1253  		return false, types.ErrSeedExist
  1254  	}
  1255  	//入参数校验,seed必须是大于等于12个单词或者汉字
  1256  	if len(password) == 0 || len(seed) == 0 {
  1257  		return false, types.ErrInvalidParam
  1258  	}
  1259  
  1260  	// 密码合法性校验
  1261  	if !isValidPassWord(password) {
  1262  		return false, types.ErrInvalidPassWord
  1263  	}
  1264  
  1265  	seedarry := strings.Fields(seed)
  1266  	curseedlen := len(seedarry)
  1267  	if curseedlen < SaveSeedLong {
  1268  		walletlog.Error("saveSeed VeriySeedwordnum", "curseedlen", curseedlen, "SaveSeedLong", SaveSeedLong)
  1269  		return false, types.ErrSeedWordNum
  1270  	}
  1271  
  1272  	var newseed string
  1273  	for index, seedstr := range seedarry {
  1274  		if index != curseedlen-1 {
  1275  			newseed += seedstr + " "
  1276  		} else {
  1277  			newseed += seedstr
  1278  		}
  1279  	}
  1280  
  1281  	//校验seed是否能生成钱包结构类型,从而来校验seed的正确性
  1282  	have, err := VerifySeed(newseed, wallet.SignType, wallet.CoinType)
  1283  	if !have {
  1284  		walletlog.Error("saveSeed VerifySeed", "err", err)
  1285  		return false, types.ErrSeedWord
  1286  	}
  1287  	//批量处理seed和password的存储
  1288  	newBatch := wallet.walletStore.NewBatch(true)
  1289  	err = wallet.walletStore.SetPasswordHash(password, newBatch)
  1290  	if err != nil {
  1291  		walletlog.Error("saveSeed", "SetPasswordHash err", err)
  1292  		return false, err
  1293  	}
  1294  	//设置钱包加密标志位
  1295  	err = wallet.walletStore.SetEncryptionFlag(newBatch)
  1296  	if err != nil {
  1297  		walletlog.Error("saveSeed", "SetEncryptionFlag err", err)
  1298  		return false, err
  1299  	}
  1300  
  1301  	ok, err := SaveSeedInBatch(wallet.walletStore.GetDB(), newseed, password, newBatch)
  1302  	if !ok {
  1303  		walletlog.Error("saveSeed", "SaveSeed err", err)
  1304  		return false, err
  1305  	}
  1306  
  1307  	err = newBatch.Write()
  1308  	if err != nil {
  1309  		walletlog.Error("saveSeed newBatch.Write", "err", err)
  1310  		return false, err
  1311  	}
  1312  	wallet.Password = password
  1313  	wallet.EncryptFlag = 1
  1314  	return true, nil
  1315  }
  1316  
  1317  //ProcDumpPrivkey 获取地址对应的私钥
  1318  func (wallet *Wallet) ProcDumpPrivkey(addr string) (string, error) {
  1319  	wallet.mtx.Lock()
  1320  	defer wallet.mtx.Unlock()
  1321  
  1322  	ok, err := wallet.checkWalletStatus()
  1323  	if !ok {
  1324  		return "", err
  1325  	}
  1326  	if len(addr) == 0 {
  1327  		walletlog.Error("ProcDumpPrivkey input para is nil!")
  1328  		return "", types.ErrInvalidParam
  1329  	}
  1330  
  1331  	priv, err := wallet.getPrivKeyByAddr(addr)
  1332  	if err != nil {
  1333  		return "", err
  1334  	}
  1335  	return common.ToHex(priv.Bytes()), nil
  1336  	//return strings.ToUpper(common.ToHex(priv.Bytes())), nil
  1337  }
  1338  
  1339  //收到其他模块上报的系统有致命性故障,需要通知前端
  1340  func (wallet *Wallet) setFatalFailure(reportErrEvent *types.ReportErrEvent) {
  1341  
  1342  	walletlog.Error("setFatalFailure", "reportErrEvent", reportErrEvent.String())
  1343  	if reportErrEvent.Error == "ErrDataBaseDamage" {
  1344  		atomic.StoreInt32(&wallet.fatalFailureFlag, 1)
  1345  	}
  1346  }
  1347  
  1348  func (wallet *Wallet) getFatalFailure() int32 {
  1349  	return atomic.LoadInt32(&wallet.fatalFailureFlag)
  1350  }
  1351  
  1352  //密码合法性校验,密码长度在8-30位之间。必须是数字+字母的组合
  1353  func isValidPassWord(password string) bool {
  1354  	pwLen := len(password)
  1355  	if pwLen < 8 || pwLen > 30 {
  1356  		return false
  1357  	}
  1358  
  1359  	var char bool
  1360  	var digit bool
  1361  	for _, s := range password {
  1362  		if unicode.IsLetter(s) {
  1363  			char = true
  1364  		} else if unicode.IsDigit(s) {
  1365  			digit = true
  1366  		} else {
  1367  			return false
  1368  		}
  1369  	}
  1370  	return char && digit
  1371  }
  1372  
  1373  // CreateNewAccountByIndex 指定index创建公私钥对,主要用于空投地址。目前暂定一千万
  1374  func (wallet *Wallet) createNewAccountByIndex(index uint32) (string, error) {
  1375  	wallet.mtx.Lock()
  1376  	defer wallet.mtx.Unlock()
  1377  
  1378  	ok, err := wallet.checkWalletStatus()
  1379  	if !ok {
  1380  		return "", err
  1381  	}
  1382  
  1383  	if !isValidIndex(index) {
  1384  		walletlog.Error("createNewAccountByIndex index err", "index", index)
  1385  		return "", types.ErrInvalidParam
  1386  	}
  1387  
  1388  	//空投地址是否已经存在,存在就直接返回存储的值即可
  1389  	airDropAddr, err := wallet.walletStore.GetAirDropIndex()
  1390  	if airDropAddr != "" && err == nil {
  1391  		priv, err := wallet.getPrivKeyByAddr(airDropAddr)
  1392  		if err != nil {
  1393  			return "", err
  1394  		}
  1395  		return common.ToHex(priv.Bytes()), nil
  1396  	}
  1397  
  1398  	var addr string
  1399  	var privkeybyte []byte
  1400  	var HexPubkey string
  1401  	var isUsed bool
  1402  
  1403  	cointype := wallet.GetCoinType()
  1404  
  1405  	//通过seed获取私钥, 首先通过钱包密码解锁seed然后通过seed生成私钥
  1406  	seed, err := wallet.getSeed(wallet.Password)
  1407  	if err != nil {
  1408  		walletlog.Error("createNewAccountByIndex", "getSeed err", err)
  1409  		return "", err
  1410  	}
  1411  
  1412  	// 通过指定index生成公私钥对,并存入数据库中,如果账户已经存在就直接返回账户信息即可
  1413  	privkeyhex, err := GetPrivkeyBySeed(wallet.walletStore.GetDB(), seed, index, wallet.SignType, wallet.CoinType)
  1414  	if err != nil {
  1415  		walletlog.Error("createNewAccountByIndex", "GetPrivkeyBySeed err", err)
  1416  		return "", err
  1417  	}
  1418  	privkeybyte, err = common.FromHex(privkeyhex)
  1419  	if err != nil || len(privkeybyte) == 0 {
  1420  		walletlog.Error("createNewAccountByIndex", "FromHex err", err)
  1421  		return "", err
  1422  	}
  1423  
  1424  	pub, err := bipwallet.PrivkeyToPub(cointype, uint32(wallet.SignType), privkeybyte)
  1425  	if err != nil {
  1426  		seedlog.Error("createNewAccountByIndex PrivkeyToPub", "err", err)
  1427  		return "", types.ErrPrivkeyToPub
  1428  	}
  1429  
  1430  	HexPubkey = hex.EncodeToString(pub)
  1431  
  1432  	addr, err = bipwallet.PubToAddress(pub)
  1433  	if err != nil {
  1434  		seedlog.Error("createNewAccountByIndex PubToAddress", "err", err)
  1435  		return "", types.ErrPrivkeyToPub
  1436  	}
  1437  	//通过新生成的账户地址查询钱包数据库,如果查询返回的账户信息不为空,
  1438  	//说明此账户已经被使用,不需要再次存储账户信息
  1439  	account, err := wallet.walletStore.GetAccountByAddr(addr)
  1440  	if account != nil && err == nil {
  1441  		isUsed = true
  1442  	}
  1443  
  1444  	//第一次创建此账户
  1445  	if !isUsed {
  1446  		Account := types.Account{
  1447  			Addr:     addr,
  1448  			Currency: 0,
  1449  			Balance:  0,
  1450  			Frozen:   0,
  1451  		}
  1452  		//首先校验label是否已被使用
  1453  		Label := "airdropaddr"
  1454  		for {
  1455  			i := 0
  1456  			WalletAccStores, err := wallet.walletStore.GetAccountByLabel(Label)
  1457  			if WalletAccStores != nil && err == nil {
  1458  				walletlog.Debug("createNewAccountByIndex Label is exist in wallet!", "WalletAccStores", WalletAccStores)
  1459  				i++
  1460  				Label = Label + fmt.Sprintf("%d", i)
  1461  			} else {
  1462  				break
  1463  			}
  1464  		}
  1465  
  1466  		walletAccount := types.WalletAccount{
  1467  			Acc:   &Account,
  1468  			Label: Label,
  1469  		}
  1470  
  1471  		//使用钱包的password对私钥加密 aes cbc
  1472  		Encrypted := wcom.CBCEncrypterPrivkey([]byte(wallet.Password), privkeybyte)
  1473  
  1474  		var WalletAccStore types.WalletAccountStore
  1475  		WalletAccStore.Privkey = common.ToHex(Encrypted)
  1476  		WalletAccStore.Label = Label
  1477  		WalletAccStore.Addr = addr
  1478  
  1479  		//存储账户信息到wallet数据库中
  1480  		err = wallet.walletStore.SetWalletAccount(false, Account.Addr, &WalletAccStore)
  1481  		if err != nil {
  1482  			return "", err
  1483  		}
  1484  
  1485  		//获取地址对应的账户信息从account模块
  1486  		addrs := make([]string, 1)
  1487  		addrs[0] = addr
  1488  		accounts, err := wallet.accountdb.LoadAccounts(wallet.api, addrs)
  1489  		if err != nil {
  1490  			walletlog.Error("createNewAccountByIndex", "LoadAccounts err", err)
  1491  			return "", err
  1492  		}
  1493  		// 本账户是首次创建
  1494  		if len(accounts[0].Addr) == 0 {
  1495  			accounts[0].Addr = addr
  1496  		}
  1497  		walletAccount.Acc = accounts[0]
  1498  
  1499  		//从blockchain模块同步Account.Addr对应的所有交易详细信息
  1500  		for _, policy := range wcom.PolicyContainer {
  1501  			policy.OnCreateNewAccount(walletAccount.Acc)
  1502  		}
  1503  	}
  1504  	//存贮空投地址的信息
  1505  	airfrop := &wcom.AddrInfo{
  1506  		Index:  index,
  1507  		Addr:   addr,
  1508  		Pubkey: HexPubkey,
  1509  	}
  1510  	err = wallet.walletStore.SetAirDropIndex(airfrop)
  1511  	if err != nil {
  1512  		walletlog.Error("createNewAccountByIndex", "SetAirDropIndex err", err)
  1513  	}
  1514  	return privkeyhex, nil
  1515  }
  1516  
  1517  //isValidIndex校验index的合法性
  1518  func isValidIndex(index uint32) bool {
  1519  	if types.AirDropMinIndex <= index && index <= types.AirDropMaxIndex {
  1520  		return true
  1521  	}
  1522  	return false
  1523  }
  1524  
  1525  //ProcDumpPrivkeysFile 获取全部私钥保存到文件
  1526  func (wallet *Wallet) ProcDumpPrivkeysFile(fileName, passwd string) error {
  1527  	_, err := os.Stat(fileName)
  1528  	if err == nil {
  1529  		walletlog.Error("ProcDumpPrivkeysFile file already exists!", "fileName", fileName)
  1530  		return types.ErrFileExists
  1531  	}
  1532  
  1533  	wallet.mtx.Lock()
  1534  	defer wallet.mtx.Unlock()
  1535  
  1536  	ok, err := wallet.checkWalletStatus()
  1537  	if !ok {
  1538  		return err
  1539  	}
  1540  
  1541  	f, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
  1542  	if err != nil {
  1543  		walletlog.Error("ProcDumpPrivkeysFile create file error!", "fileName", fileName, "err", err)
  1544  		return err
  1545  	}
  1546  	defer f.Close()
  1547  
  1548  	accounts, err := wallet.walletStore.GetAccountByPrefix("Account")
  1549  	if err != nil || len(accounts) == 0 {
  1550  		walletlog.Info("ProcDumpPrivkeysFile GetWalletAccounts", "GetAccountByPrefix:err", err)
  1551  		return err
  1552  	}
  1553  
  1554  	for i, acc := range accounts {
  1555  		priv, err := wallet.getPrivKeyByAddr(acc.Addr)
  1556  		if err != nil {
  1557  			walletlog.Info("getPrivKeyByAddr", acc.Addr, err)
  1558  			continue
  1559  		}
  1560  
  1561  		privkey := common.ToHex(priv.Bytes())
  1562  		content := privkey + "& *.prickey.+.label.* &" + acc.Label
  1563  
  1564  		Encrypter, err := AesgcmEncrypter([]byte(passwd), []byte(content))
  1565  		if err != nil {
  1566  			walletlog.Error("ProcDumpPrivkeysFile AesgcmEncrypter fileContent error!", "fileName", fileName, "err", err)
  1567  			continue
  1568  		}
  1569  
  1570  		f.WriteString(string(Encrypter))
  1571  
  1572  		if i < len(accounts)-1 {
  1573  			f.WriteString("&ffzm.&**&")
  1574  		}
  1575  	}
  1576  
  1577  	return nil
  1578  }
  1579  
  1580  // ProcImportPrivkeysFile 处理导入私钥
  1581  //input:
  1582  //type  struct {
  1583  //	fileName string
  1584  //  passwd   string
  1585  //导入私钥,并且同时会导入交易
  1586  func (wallet *Wallet) ProcImportPrivkeysFile(fileName, passwd string) error {
  1587  	if _, err := os.Stat(fileName); os.IsNotExist(err) {
  1588  		walletlog.Error("ProcImportPrivkeysFile file is not exist!", "fileName", fileName)
  1589  		return err
  1590  	}
  1591  
  1592  	wallet.mtx.Lock()
  1593  	defer wallet.mtx.Unlock()
  1594  
  1595  	ok, err := wallet.checkWalletStatus()
  1596  	if !ok {
  1597  		return err
  1598  	}
  1599  
  1600  	f, err := os.Open(fileName)
  1601  	if err != nil {
  1602  		walletlog.Error("ProcImportPrivkeysFile Open file error", "fileName", fileName, "err", err)
  1603  		return err
  1604  	}
  1605  	defer f.Close()
  1606  
  1607  	fileContent, err := ioutil.ReadAll(f)
  1608  	if err != nil {
  1609  		walletlog.Error("ProcImportPrivkeysFile read file error", "fileName", fileName, "err", err)
  1610  		return err
  1611  	}
  1612  	accounts := strings.Split(string(fileContent), "&ffzm.&**&")
  1613  	for _, value := range accounts {
  1614  		Decrypter, err := AesgcmDecrypter([]byte(passwd), []byte(value))
  1615  		if err != nil {
  1616  			walletlog.Error("ProcImportPrivkeysFile AesgcmDecrypter fileContent error", "fileName", fileName, "err", err)
  1617  			return types.ErrVerifyOldpasswdFail
  1618  		}
  1619  
  1620  		acc := strings.Split(string(Decrypter), "& *.prickey.+.label.* &")
  1621  		if len(acc) != 2 {
  1622  			walletlog.Error("ProcImportPrivkeysFile len(acc) != 2, File format error.", "Decrypter", string(Decrypter), "len", len(acc))
  1623  			continue
  1624  		}
  1625  		privKey := acc[0]
  1626  		label := acc[1]
  1627  
  1628  		//校验label是否已经被使用
  1629  		Account, err := wallet.walletStore.GetAccountByLabel(label)
  1630  		if Account != nil && err == nil {
  1631  			walletlog.Info("ProcImportPrivKey Label is exist in wallet, label = label + _2!")
  1632  			label = label + "_2"
  1633  		}
  1634  
  1635  		PrivKey := &types.ReqWalletImportPrivkey{
  1636  			Privkey: privKey,
  1637  			Label:   label,
  1638  		}
  1639  
  1640  		_, err = wallet.procImportPrivKey(PrivKey)
  1641  		if err == types.ErrPrivkeyExist {
  1642  			// 修改标签名称 是否需要?
  1643  			// wallet.ProcWalletSetLabel()
  1644  		} else if err != nil {
  1645  			walletlog.Info("ProcImportPrivKey procImportPrivKey error")
  1646  			return err
  1647  		}
  1648  	}
  1649  
  1650  	return nil
  1651  }