github.com/turingchain2020/turingchain@v1.1.21/wallet/wallet.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 wallet turingchain钱包功能实现
     6  package wallet
     7  
     8  import (
     9  	"errors"
    10  	"math/rand"
    11  	"reflect"
    12  	"sync"
    13  	"sync/atomic"
    14  	"time"
    15  
    16  	"github.com/turingchain2020/turingchain/account"
    17  	"github.com/turingchain2020/turingchain/client"
    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  	clog "github.com/turingchain2020/turingchain/common/log"
    23  	log "github.com/turingchain2020/turingchain/common/log/log15"
    24  	"github.com/turingchain2020/turingchain/queue"
    25  	"github.com/turingchain2020/turingchain/types"
    26  	"github.com/turingchain2020/turingchain/wallet/bipwallet"
    27  	wcom "github.com/turingchain2020/turingchain/wallet/common"
    28  )
    29  
    30  var (
    31  	//minFee           int64
    32  	maxTxNumPerBlock int64 = types.MaxTxsPerBlock
    33  	// MaxTxHashsPerTime 每次处理的最大交易哈希数量
    34  	MaxTxHashsPerTime int64 = 100
    35  	walletlog               = log.New("module", "wallet")
    36  	//accountdb         *account.DB
    37  	//accTokenMap = make(map[string]*account.DB)
    38  )
    39  
    40  func init() {
    41  	wcom.QueryData.Register("wallet", &Wallet{})
    42  }
    43  
    44  const (
    45  	// AddTx 添加交易操作
    46  	AddTx int32 = 20001
    47  	// DelTx 删除交易操作
    48  	DelTx int32 = 20002
    49  	// 交易收发方向
    50  	sendTx int32 = 30001
    51  	recvTx int32 = 30002
    52  )
    53  
    54  // Wallet 钱包功能的实现类
    55  type Wallet struct {
    56  	client queue.Client
    57  	// 模块间通信的操作接口,建议用api代替client调用
    58  	api                client.QueueProtocolAPI
    59  	mtx                sync.Mutex
    60  	timeout            *time.Timer
    61  	mineStatusReporter wcom.MineStatusReport
    62  	isclosed           int32
    63  	isWalletLocked     int32
    64  	fatalFailureFlag   int32
    65  	Password           string
    66  	FeeAmount          int64
    67  	EncryptFlag        int64
    68  	wg                 *sync.WaitGroup
    69  	walletStore        *walletStore
    70  	random             *rand.Rand
    71  	cfg                *types.Wallet
    72  	done               chan struct{}
    73  	rescanwg           *sync.WaitGroup
    74  	lastHeader         *types.Header
    75  	initFlag           uint32 // 钱包模块是否初始化完毕的标记,默认为0,表示未初始化
    76  	SignType           int    // SignType 签名类型 1;secp256k1,2:ed25519,3:sm2
    77  	CoinType           uint32 // CoinType 币种类型 trc:0x80003333,ycc:0x80003334
    78  
    79  	minFee      int64
    80  	accountdb   *account.DB
    81  	accTokenMap map[string]*account.DB
    82  }
    83  
    84  // SetLogLevel 设置日志登记
    85  func SetLogLevel(level string) {
    86  	clog.SetLogLevel(level)
    87  }
    88  
    89  // DisableLog 禁用日志
    90  func DisableLog() {
    91  	walletlog.SetHandler(log.DiscardHandler())
    92  	storelog.SetHandler(log.DiscardHandler())
    93  }
    94  
    95  // New 创建一个钱包对象
    96  func New(cfg *types.TuringchainConfig) *Wallet {
    97  	mcfg := cfg.GetModuleConfig().Wallet
    98  	//walletStore
    99  	//accountdb = account.NewCoinsAccount()
   100  	walletStoreDB := dbm.NewDB("wallet", mcfg.Driver, mcfg.DbPath, mcfg.DbCache)
   101  	//walletStore := NewStore(walletStoreDB)
   102  	walletStore := newStore(walletStoreDB)
   103  	//minFee = cfg.MinFee
   104  	signType := types.GetSignType("", mcfg.SignType)
   105  	if signType <= 0 {
   106  		signType = types.SECP256K1
   107  	}
   108  
   109  	wallet := &Wallet{
   110  		walletStore:      walletStore,
   111  		isWalletLocked:   1,
   112  		fatalFailureFlag: 0,
   113  		wg:               &sync.WaitGroup{},
   114  		FeeAmount:        walletStore.GetFeeAmount(mcfg.MinFee),
   115  		EncryptFlag:      walletStore.GetEncryptionFlag(),
   116  		done:             make(chan struct{}),
   117  		cfg:              mcfg,
   118  		rescanwg:         &sync.WaitGroup{},
   119  		initFlag:         0,
   120  		SignType:         signType,
   121  		CoinType:         bipwallet.GetSLIP0044CoinType(mcfg.CoinType),
   122  		minFee:           mcfg.MinFee,
   123  		accountdb:        account.NewCoinsAccount(cfg),
   124  		accTokenMap:      make(map[string]*account.DB),
   125  	}
   126  	wallet.random = rand.New(rand.NewSource(types.Now().UnixNano()))
   127  	wcom.QueryData.SetThis("wallet", reflect.ValueOf(wallet))
   128  	return wallet
   129  }
   130  
   131  //Wait for wallet ready
   132  func (wallet *Wallet) Wait() {}
   133  
   134  // RegisterMineStatusReporter 向钱包注册状态回报
   135  func (wallet *Wallet) RegisterMineStatusReporter(reporter wcom.MineStatusReport) error {
   136  	if reporter == nil {
   137  		return types.ErrInvalidParam
   138  	}
   139  	if wallet.mineStatusReporter != nil {
   140  		return errors.New("ReporterIsExisted")
   141  	}
   142  	consensus := wallet.client.GetConfig().GetModuleConfig().Consensus.Name
   143  
   144  	if !isConflict(consensus, reporter.PolicyName()) {
   145  		wallet.mineStatusReporter = reporter
   146  	}
   147  	return nil
   148  }
   149  
   150  //检测当policy和Consensus有冲突时,不挂接对应的reporter
   151  func isConflict(curConsensus string, policy string) bool {
   152  	walletlog.Info("isConflict", "curConsensus", curConsensus, "policy", policy)
   153  
   154  	return curConsensus != policy
   155  }
   156  
   157  // GetConfig 获取钱包配置
   158  func (wallet *Wallet) GetConfig() *types.Wallet {
   159  	return wallet.cfg
   160  }
   161  
   162  // GetAPI 获取操作API
   163  func (wallet *Wallet) GetAPI() client.QueueProtocolAPI {
   164  	return wallet.api
   165  }
   166  
   167  // GetDBStore 获取数据库存储对象操作接口
   168  func (wallet *Wallet) GetDBStore() dbm.DB {
   169  	return wallet.walletStore.GetDB()
   170  }
   171  
   172  // GetSignType 获取签名类型
   173  func (wallet *Wallet) GetSignType() int {
   174  	return wallet.SignType
   175  }
   176  
   177  // GetCoinType 获取币种类型
   178  func (wallet *Wallet) GetCoinType() uint32 {
   179  	return wallet.CoinType
   180  }
   181  
   182  // GetPassword 获取密码
   183  func (wallet *Wallet) GetPassword() string {
   184  	wallet.mtx.Lock()
   185  	defer wallet.mtx.Unlock()
   186  
   187  	return wallet.Password
   188  }
   189  
   190  // Nonce 获取随机值
   191  func (wallet *Wallet) Nonce() int64 {
   192  	return wallet.random.Int63()
   193  }
   194  
   195  // AddWaitGroup 添加一个分组等待事件
   196  func (wallet *Wallet) AddWaitGroup(delta int) {
   197  	wallet.wg.Add(delta)
   198  }
   199  
   200  // WaitGroupDone 完成分组事件
   201  func (wallet *Wallet) WaitGroupDone() {
   202  	wallet.wg.Done()
   203  }
   204  
   205  // GetBlockHeight 获取区块高度
   206  func (wallet *Wallet) GetBlockHeight() int64 {
   207  	return wallet.GetHeight()
   208  }
   209  
   210  // GetRandom 获取随机值
   211  func (wallet *Wallet) GetRandom() *rand.Rand {
   212  	return wallet.random
   213  }
   214  
   215  // GetWalletDone 是否结束的通道
   216  func (wallet *Wallet) GetWalletDone() chan struct{} {
   217  	return wallet.done
   218  }
   219  
   220  // GetLastHeader 获取最新高度信息
   221  func (wallet *Wallet) GetLastHeader() *types.Header {
   222  	wallet.mtx.Lock()
   223  	defer wallet.mtx.Unlock()
   224  	return wallet.lastHeader
   225  }
   226  
   227  // GetWaitGroup 获取等待互斥量
   228  func (wallet *Wallet) GetWaitGroup() *sync.WaitGroup {
   229  	return wallet.wg
   230  }
   231  
   232  // GetAccountByLabel 根据标签获取账号
   233  func (wallet *Wallet) GetAccountByLabel(label string) (*types.WalletAccountStore, error) {
   234  	return wallet.walletStore.GetAccountByLabel(label)
   235  }
   236  
   237  // IsRescanUtxosFlagScaning 是否处于扫描UTXO状态
   238  func (wallet *Wallet) IsRescanUtxosFlagScaning() (bool, error) {
   239  	in := &types.ReqNil{}
   240  	flag := false
   241  	for _, policy := range wcom.PolicyContainer {
   242  		out, err := policy.Call("GetUTXOScaningFlag", in)
   243  		if err != nil {
   244  			if err.Error() == types.ErrNotSupport.Error() {
   245  				continue
   246  			}
   247  			return flag, err
   248  		}
   249  		reply, ok := out.(*types.Reply)
   250  		if !ok {
   251  			err = types.ErrTypeAsset
   252  			return flag, err
   253  		}
   254  		flag = reply.IsOk
   255  		return flag, err
   256  	}
   257  
   258  	return flag, nil
   259  }
   260  
   261  // Close 关闭钱包
   262  func (wallet *Wallet) Close() {
   263  	//等待所有的子线程退出
   264  	//set close flag to isclosed == 1
   265  	atomic.StoreInt32(&wallet.isclosed, 1)
   266  	for _, policy := range wcom.PolicyContainer {
   267  		policy.OnClose()
   268  	}
   269  	close(wallet.done)
   270  	wallet.client.Close()
   271  	wallet.wg.Wait()
   272  	//关闭数据库
   273  	wallet.walletStore.Close()
   274  	walletlog.Info("wallet module closed")
   275  }
   276  
   277  // IsClose 检查是否处于关闭状态
   278  func (wallet *Wallet) IsClose() bool {
   279  	return atomic.LoadInt32(&wallet.isclosed) == 1
   280  }
   281  
   282  // IsWalletLocked 返回钱包锁的状态
   283  func (wallet *Wallet) IsWalletLocked() bool {
   284  	return atomic.LoadInt32(&wallet.isWalletLocked) != 0
   285  }
   286  
   287  // SetQueueClient 初始化客户端消息队列
   288  func (wallet *Wallet) SetQueueClient(cli queue.Client) {
   289  	var err error
   290  	wallet.client = cli
   291  	wallet.client.Sub("wallet")
   292  	wallet.api, err = client.New(cli, nil)
   293  	if err != nil {
   294  		panic("SetQueueClient client.New err")
   295  	}
   296  	sub := cli.GetConfig().GetSubConfig().Wallet
   297  	// 置完client之后才做Init
   298  	wcom.Init(wallet, sub)
   299  	wallet.wg.Add(1)
   300  	go wallet.ProcRecvMsg()
   301  	for _, policy := range wcom.PolicyContainer {
   302  		policy.OnSetQueueClient()
   303  	}
   304  	wallet.setInited(true)
   305  }
   306  
   307  // GetAccountByAddr 根据地址获取账户
   308  func (wallet *Wallet) GetAccountByAddr(addr string) (*types.WalletAccountStore, error) {
   309  	return wallet.walletStore.GetAccountByAddr(addr)
   310  }
   311  
   312  // SetWalletAccount 设置钱包账户
   313  func (wallet *Wallet) SetWalletAccount(update bool, addr string, account *types.WalletAccountStore) error {
   314  	return wallet.walletStore.SetWalletAccount(update, addr, account)
   315  }
   316  
   317  // GetPrivKeyByAddr 根据地址获取私钥
   318  func (wallet *Wallet) GetPrivKeyByAddr(addr string) (crypto.PrivKey, error) {
   319  	if !wallet.isInited() {
   320  		return nil, types.ErrNotInited
   321  	}
   322  	wallet.mtx.Lock()
   323  	defer wallet.mtx.Unlock()
   324  
   325  	return wallet.getPrivKeyByAddr(addr)
   326  }
   327  
   328  func (wallet *Wallet) getPrivKeyByAddr(addr string) (crypto.PrivKey, error) {
   329  	//获取指定地址在钱包里的账户信息
   330  	Accountstor, err := wallet.walletStore.GetAccountByAddr(addr)
   331  	if err != nil {
   332  		walletlog.Error("getPrivKeyByAddr", "GetAccountByAddr err:", err)
   333  		return nil, err
   334  	}
   335  
   336  	//通过password解密存储的私钥
   337  	prikeybyte, err := common.FromHex(Accountstor.GetPrivkey())
   338  	if err != nil || len(prikeybyte) == 0 {
   339  		walletlog.Error("getPrivKeyByAddr", "FromHex err", err)
   340  		return nil, err
   341  	}
   342  
   343  	privkey := wcom.CBCDecrypterPrivkey([]byte(wallet.Password), prikeybyte)
   344  	//通过privkey生成一个pubkey然后换算成对应的addr
   345  	cr, err := crypto.New(types.GetSignName("", wallet.SignType))
   346  	if err != nil {
   347  		walletlog.Error("getPrivKeyByAddr", "err", err)
   348  		return nil, err
   349  	}
   350  	priv, err := cr.PrivKeyFromBytes(privkey)
   351  	if err != nil {
   352  		walletlog.Error("getPrivKeyByAddr", "PrivKeyFromBytes err", err)
   353  		return nil, err
   354  	}
   355  	return priv, nil
   356  }
   357  
   358  // AddrInWallet 地址对应的账户是否属于本钱包
   359  func (wallet *Wallet) AddrInWallet(addr string) bool {
   360  	if !wallet.isInited() {
   361  		return false
   362  	}
   363  	if len(addr) == 0 {
   364  		return false
   365  	}
   366  	acc, err := wallet.walletStore.GetAccountByAddr(addr)
   367  	if err == nil && acc != nil {
   368  		return true
   369  	}
   370  	return false
   371  }
   372  
   373  //IsTransfer 检测钱包是否允许转账到指定地址,判断钱包锁和是否有seed以及挖矿锁
   374  func (wallet *Wallet) IsTransfer(addr string) (bool, error) {
   375  	wallet.mtx.Lock()
   376  	defer wallet.mtx.Unlock()
   377  
   378  	return wallet.isTransfer(addr)
   379  }
   380  
   381  //isTransfer 检测钱包是否允许转账到指定地址,判断钱包锁和是否有seed以及挖矿锁
   382  func (wallet *Wallet) isTransfer(addr string) (bool, error) {
   383  
   384  	ok, err := wallet.checkWalletStatus()
   385  	//钱包已经解锁或者错误是ErrSaveSeedFirst直接返回
   386  	if ok || err == types.ErrSaveSeedFirst {
   387  		return ok, err
   388  	}
   389  	//钱包已经锁定,挖矿锁已经解锁,需要判断addr是否是挖矿合约地址
   390  	//这里依赖了ticket 挖矿合约
   391  	if !wallet.isTicketLocked() {
   392  		consensus := wallet.client.GetConfig().GetModuleConfig().Consensus.Name
   393  
   394  		if addr == address.ExecAddress(consensus) {
   395  			return true, nil
   396  		}
   397  	}
   398  	return ok, err
   399  }
   400  
   401  //CheckWalletStatus 钱包状态检测函数,解锁状态,seed是否已保存
   402  func (wallet *Wallet) CheckWalletStatus() (bool, error) {
   403  	if !wallet.isInited() {
   404  		return false, types.ErrNotInited
   405  	}
   406  
   407  	wallet.mtx.Lock()
   408  	defer wallet.mtx.Unlock()
   409  
   410  	return wallet.checkWalletStatus()
   411  }
   412  
   413  //CheckWalletStatus 钱包状态检测函数,解锁状态,seed是否已保存
   414  func (wallet *Wallet) checkWalletStatus() (bool, error) {
   415  	// 钱包锁定,ticket已经解锁,返回只解锁了ticket的错误
   416  	if wallet.IsWalletLocked() && !wallet.isTicketLocked() {
   417  		return false, types.ErrOnlyTicketUnLocked
   418  	} else if wallet.IsWalletLocked() {
   419  		return false, types.ErrWalletIsLocked
   420  	}
   421  
   422  	//判断钱包是否已保存seed
   423  	has, err := wallet.walletStore.HasSeed()
   424  	if !has || err != nil {
   425  		return false, types.ErrSaveSeedFirst
   426  	}
   427  	return true, nil
   428  }
   429  
   430  func (wallet *Wallet) isTicketLocked() bool {
   431  	locked := true
   432  	if wallet.mineStatusReporter != nil {
   433  		locked = wallet.mineStatusReporter.IsTicketLocked()
   434  	}
   435  	return locked
   436  }
   437  
   438  func (wallet *Wallet) isAutoMinning() bool {
   439  	autoMining := false
   440  	if wallet.mineStatusReporter != nil {
   441  		autoMining = wallet.mineStatusReporter.IsAutoMining()
   442  	}
   443  	return autoMining
   444  }
   445  
   446  // GetWalletStatus 获取钱包状态
   447  func (wallet *Wallet) GetWalletStatus() *types.WalletStatus {
   448  	var err error
   449  	s := &types.WalletStatus{}
   450  	s.IsWalletLock = wallet.IsWalletLocked()
   451  	s.IsHasSeed, err = wallet.walletStore.HasSeed()
   452  	s.IsAutoMining = wallet.isAutoMinning()
   453  	s.IsTicketLock = wallet.isTicketLocked()
   454  	if err != nil {
   455  		walletlog.Debug("GetWalletStatus HasSeed ", "err", err)
   456  	}
   457  	walletlog.Debug("GetWalletStatus", "walletstatus", s)
   458  	return s
   459  }
   460  
   461  // GetWalletAccounts 获取账号列表
   462  //output:
   463  //type WalletAccountStore struct {
   464  //	Privkey   string  //加密后的私钥hex值
   465  //	Label     string
   466  //	Addr      string
   467  //	TimeStamp string
   468  //获取钱包的所有账户地址列表,
   469  func (wallet *Wallet) getWalletAccounts() ([]*types.WalletAccountStore, error) {
   470  	if !wallet.isInited() {
   471  		return nil, types.ErrNotInited
   472  	}
   473  
   474  	//通过Account前缀查找获取钱包中的所有账户信息
   475  	WalletAccStores, err := wallet.walletStore.GetAccountByPrefix("Account")
   476  	if err != nil || len(WalletAccStores) == 0 {
   477  		walletlog.Info("GetWalletAccounts", "GetAccountByPrefix:err", err)
   478  		return nil, err
   479  	}
   480  	return WalletAccStores, err
   481  }
   482  
   483  //GetWalletAccounts 获取账号列表
   484  func (wallet *Wallet) GetWalletAccounts() ([]*types.WalletAccountStore, error) {
   485  	if !wallet.isInited() {
   486  		return nil, types.ErrNotInited
   487  	}
   488  	wallet.mtx.Lock()
   489  	defer wallet.mtx.Unlock()
   490  
   491  	return wallet.getWalletAccounts()
   492  }
   493  
   494  func (wallet *Wallet) updateLastHeader(block *types.BlockDetail, mode int) error {
   495  	wallet.mtx.Lock()
   496  	defer wallet.mtx.Unlock()
   497  	header, err := wallet.api.GetLastHeader()
   498  	if err != nil {
   499  		return err
   500  	}
   501  	if block != nil {
   502  		if mode == 1 && block.Block.Height > header.Height {
   503  			wallet.lastHeader = &types.Header{
   504  				BlockTime: block.Block.BlockTime,
   505  				Height:    block.Block.Height,
   506  				StateHash: block.Block.StateHash,
   507  			}
   508  		} else if mode == -1 && wallet.lastHeader != nil && wallet.lastHeader.Height == block.Block.Height {
   509  			wallet.lastHeader = header
   510  		}
   511  	}
   512  	if block == nil || wallet.lastHeader == nil {
   513  		wallet.lastHeader = header
   514  	}
   515  	return nil
   516  }
   517  
   518  func (wallet *Wallet) setInited(flag bool) {
   519  	if flag && !wallet.isInited() {
   520  		atomic.StoreUint32(&wallet.initFlag, 1)
   521  	}
   522  }
   523  
   524  func (wallet *Wallet) isInited() bool {
   525  	return atomic.LoadUint32(&wallet.initFlag) != 0
   526  }