github.com/turingchain2020/turingchain@v1.1.21/wallet/common/store.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 common
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/sha256"
    10  	"encoding/json"
    11  	"fmt"
    12  	"sync"
    13  
    14  	"github.com/turingchain2020/turingchain/common/crypto"
    15  	"github.com/turingchain2020/turingchain/common/db"
    16  	"github.com/turingchain2020/turingchain/common/log/log15"
    17  	"github.com/turingchain2020/turingchain/common/version"
    18  	"github.com/turingchain2020/turingchain/types"
    19  	"github.com/golang/protobuf/proto"
    20  )
    21  
    22  var (
    23  	storelog = log15.New("wallet", "store")
    24  )
    25  
    26  //AddrInfo 通过seed指定index创建的账户信息,目前主要用于空投地址
    27  type AddrInfo struct {
    28  	Index  uint32 `json:"index,omitempty"`
    29  	Addr   string `json:"addr,omitempty"`
    30  	Pubkey string `json:"pubkey,omitempty"`
    31  }
    32  
    33  // NewStore 新建存储对象
    34  func NewStore(db db.DB) *Store {
    35  	return &Store{db: db, blkBatch: db.NewBatch(true)}
    36  }
    37  
    38  // Store 钱包通用数据库存储类,实现对钱包账户数据库操作的基本实现
    39  type Store struct {
    40  	db        db.DB
    41  	blkBatch  db.Batch
    42  	batchLock sync.Mutex
    43  }
    44  
    45  // Close 关闭数据库
    46  func (store *Store) Close() {
    47  	store.db.Close()
    48  }
    49  
    50  // GetDB 获取数据库操作接口
    51  func (store *Store) GetDB() db.DB {
    52  	return store.db
    53  }
    54  
    55  // NewBatch 新建批处理操作对象接口
    56  func (store *Store) NewBatch(sync bool) db.Batch {
    57  	return store.db.NewBatch(sync)
    58  }
    59  
    60  // GetBlockBatch 新建批处理操作对象接口
    61  func (store *Store) GetBlockBatch(sync bool) db.Batch {
    62  	store.batchLock.Lock()
    63  	store.blkBatch.Reset()
    64  	store.blkBatch.UpdateWriteSync(sync)
    65  	return store.blkBatch
    66  }
    67  
    68  //FreeBlockBatch free
    69  func (store *Store) FreeBlockBatch() {
    70  	store.batchLock.Unlock()
    71  }
    72  
    73  // Get 取值
    74  func (store *Store) Get(key []byte) ([]byte, error) {
    75  	return store.db.Get(key)
    76  }
    77  
    78  // Set 设置值
    79  func (store *Store) Set(key []byte, value []byte) (err error) {
    80  	return store.db.Set(key, value)
    81  }
    82  
    83  // NewListHelper 新建列表复制操作对象
    84  func (store *Store) NewListHelper() *db.ListHelper {
    85  	return db.NewListHelper(store.db)
    86  }
    87  
    88  // GetAccountByte 获取账号byte类型
    89  func (store *Store) GetAccountByte(update bool, addr string, account *types.WalletAccountStore) ([]byte, error) {
    90  	if len(addr) == 0 {
    91  		storelog.Error("GetAccountByte addr is nil")
    92  		return nil, types.ErrInvalidParam
    93  	}
    94  	if account == nil {
    95  		storelog.Error("GetAccountByte account is nil")
    96  		return nil, types.ErrInvalidParam
    97  	}
    98  
    99  	timestamp := fmt.Sprintf("%018d", types.Now().Unix())
   100  	//更新时需要使用原来的Accountkey
   101  	if update {
   102  		timestamp = account.TimeStamp
   103  	}
   104  	account.TimeStamp = timestamp
   105  
   106  	accountbyte, err := proto.Marshal(account)
   107  	if err != nil {
   108  		storelog.Error("GetAccountByte", " proto.Marshal error", err)
   109  		return nil, types.ErrMarshal
   110  	}
   111  	return accountbyte, nil
   112  }
   113  
   114  // SetWalletAccount 保存钱包账户信息
   115  func (store *Store) SetWalletAccount(update bool, addr string, account *types.WalletAccountStore) error {
   116  	accountbyte, err := store.GetAccountByte(update, addr, account)
   117  	if err != nil {
   118  		storelog.Error("SetWalletAccount", "GetAccountByte error", err)
   119  		return err
   120  	}
   121  	//需要同时修改三个表,Account,Addr,Label,批量处理
   122  	newbatch := store.NewBatch(true)
   123  	newbatch.Set(CalcAccountKey(account.TimeStamp, addr), accountbyte)
   124  	newbatch.Set(CalcAddrKey(addr), accountbyte)
   125  	newbatch.Set(CalcLabelKey(account.GetLabel()), accountbyte)
   126  	return newbatch.Write()
   127  }
   128  
   129  // SetWalletAccountInBatch 保存钱包账号信息
   130  func (store *Store) SetWalletAccountInBatch(update bool, addr string, account *types.WalletAccountStore, newbatch db.Batch) error {
   131  	accountbyte, err := store.GetAccountByte(update, addr, account)
   132  	if err != nil {
   133  		storelog.Error("SetWalletAccount", "GetAccountByte error", err)
   134  		return err
   135  	}
   136  	//需要同时修改三个表,Account,Addr,Label,批量处理
   137  	newbatch.Set(CalcAccountKey(account.TimeStamp, addr), accountbyte)
   138  	newbatch.Set(CalcAddrKey(addr), accountbyte)
   139  	newbatch.Set(CalcLabelKey(account.GetLabel()), accountbyte)
   140  	return nil
   141  }
   142  
   143  // GetAccountByAddr 根据地址获取账号信息
   144  func (store *Store) GetAccountByAddr(addr string) (*types.WalletAccountStore, error) {
   145  	var account types.WalletAccountStore
   146  	if len(addr) == 0 {
   147  		storelog.Error("GetAccountByAddr addr is empty")
   148  		return nil, types.ErrInvalidParam
   149  	}
   150  	data, err := store.Get(CalcAddrKey(addr))
   151  	if data == nil || err != nil {
   152  		if err != db.ErrNotFoundInDb {
   153  			storelog.Debug("GetAccountByAddr addr", "err", err)
   154  		}
   155  		return nil, types.ErrAddrNotExist
   156  	}
   157  	err = proto.Unmarshal(data, &account)
   158  	if err != nil {
   159  		storelog.Error("GetAccountByAddr", "proto.Unmarshal err:", err)
   160  		return nil, types.ErrUnmarshal
   161  	}
   162  	return &account, nil
   163  }
   164  
   165  // GetAccountByLabel 根据标签获取账号信息
   166  func (store *Store) GetAccountByLabel(label string) (*types.WalletAccountStore, error) {
   167  	var account types.WalletAccountStore
   168  	if len(label) == 0 {
   169  		storelog.Error("GetAccountByLabel label is empty")
   170  		return nil, types.ErrInvalidParam
   171  	}
   172  	data, err := store.Get(CalcLabelKey(label))
   173  	if data == nil || err != nil {
   174  		if err != db.ErrNotFoundInDb {
   175  			storelog.Error("GetAccountByLabel label", "err", err)
   176  		}
   177  		return nil, types.ErrLabelNotExist
   178  	}
   179  	err = proto.Unmarshal(data, &account)
   180  	if err != nil {
   181  		storelog.Error("GetAccountByAddr", "proto.Unmarshal err:", err)
   182  		return nil, types.ErrUnmarshal
   183  	}
   184  	return &account, nil
   185  }
   186  
   187  // GetAccountByPrefix 根据前缀获取账号信息列表
   188  func (store *Store) GetAccountByPrefix(addr string) ([]*types.WalletAccountStore, error) {
   189  	if len(addr) == 0 {
   190  		storelog.Error("GetAccountByPrefix addr is nil")
   191  		return nil, types.ErrInvalidParam
   192  	}
   193  	list := store.NewListHelper()
   194  	accbytes := list.PrefixScan([]byte(addr))
   195  	if len(accbytes) == 0 {
   196  		storelog.Debug("GetAccountByPrefix addr not exist")
   197  		return nil, types.ErrAccountNotExist
   198  	}
   199  	WalletAccountStores := make([]*types.WalletAccountStore, len(accbytes))
   200  	for index, accbyte := range accbytes {
   201  		var walletaccount types.WalletAccountStore
   202  		err := proto.Unmarshal(accbyte, &walletaccount)
   203  		if err != nil {
   204  			storelog.Error("GetAccountByAddr", "proto.Unmarshal err:", err)
   205  			return nil, types.ErrUnmarshal
   206  		}
   207  		WalletAccountStores[index] = &walletaccount
   208  	}
   209  	return WalletAccountStores, nil
   210  }
   211  
   212  //GetTxDetailByIter 迭代获取从指定key:height*100000+index 开始向前或者向后查找指定count的交易
   213  func (store *Store) GetTxDetailByIter(TxList *types.ReqWalletTransactionList) (*types.WalletTxDetails, error) {
   214  	var txDetails types.WalletTxDetails
   215  	if TxList == nil {
   216  		storelog.Error("GetTxDetailByIter TxList is nil")
   217  		return nil, types.ErrInvalidParam
   218  	}
   219  
   220  	var txbytes [][]byte
   221  	//FromTx是空字符串时,
   222  	//Direction == 0从最新的交易开始倒序取count个
   223  	//Direction == 1从最早的交易开始正序取count个
   224  	if len(TxList.FromTx) == 0 {
   225  		list := store.NewListHelper()
   226  		if TxList.Direction == 0 {
   227  			txbytes = list.IteratorScanFromLast(CalcTxKey(""), TxList.Count, db.ListDESC)
   228  		} else {
   229  			txbytes = list.IteratorScanFromFirst(CalcTxKey(""), TxList.Count, db.ListASC)
   230  		}
   231  		if len(txbytes) == 0 {
   232  			storelog.Error("GetTxDetailByIter IteratorScanFromLast does not exist tx!")
   233  			return nil, types.ErrTxNotExist
   234  		}
   235  	} else {
   236  		list := store.NewListHelper()
   237  		txbytes = list.IteratorScan(CalcTxKey(""), CalcTxKey(string(TxList.FromTx)), TxList.Count, TxList.Direction)
   238  		if len(txbytes) == 0 {
   239  			storelog.Error("GetTxDetailByIter IteratorScan does not exist tx!")
   240  			return nil, types.ErrTxNotExist
   241  		}
   242  	}
   243  
   244  	txDetails.TxDetails = make([]*types.WalletTxDetail, len(txbytes))
   245  	for index, txdetailbyte := range txbytes {
   246  		var txdetail types.WalletTxDetail
   247  		err := proto.Unmarshal(txdetailbyte, &txdetail)
   248  		if err != nil {
   249  			storelog.Error("GetTxDetailByIter", "proto.Unmarshal err:", err)
   250  			return nil, types.ErrUnmarshal
   251  		}
   252  		txdetail.Txhash = txdetail.GetTx().Hash()
   253  		txDetails.TxDetails[index] = &txdetail
   254  	}
   255  	return &txDetails, nil
   256  }
   257  
   258  // SetEncryptionFlag 设置加密方式标志
   259  func (store *Store) SetEncryptionFlag(batch db.Batch) error {
   260  	var flag int64 = 1
   261  	data, err := json.Marshal(flag)
   262  	if err != nil {
   263  		storelog.Error("SetEncryptionFlag marshal flag", "err", err)
   264  		return types.ErrMarshal
   265  	}
   266  
   267  	batch.Set(CalcEncryptionFlag(), data)
   268  	return nil
   269  }
   270  
   271  // GetEncryptionFlag 获取加密方式
   272  func (store *Store) GetEncryptionFlag() int64 {
   273  	var flag int64
   274  	data, err := store.Get(CalcEncryptionFlag())
   275  	if data == nil || err != nil {
   276  		data, err = store.Get(CalckeyEncryptionCompFlag())
   277  		if data == nil || err != nil {
   278  			return 0
   279  		}
   280  	}
   281  	err = json.Unmarshal(data, &flag)
   282  	if err != nil {
   283  		storelog.Error("GetEncryptionFlag unmarshal", "err", err)
   284  		return 0
   285  	}
   286  	return flag
   287  }
   288  
   289  // SetPasswordHash 保存密码哈希
   290  func (store *Store) SetPasswordHash(password string, batch db.Batch) error {
   291  	var WalletPwHash types.WalletPwHash
   292  	//获取一个随机字符串
   293  	randstr := fmt.Sprintf("fuzamei:$@%s", crypto.CRandHex(16))
   294  	WalletPwHash.Randstr = randstr
   295  
   296  	//通过password和随机字符串生成一个hash值
   297  	pwhashstr := fmt.Sprintf("%s:%s", password, WalletPwHash.Randstr)
   298  	pwhash := sha256.Sum256([]byte(pwhashstr))
   299  	WalletPwHash.PwHash = pwhash[:]
   300  
   301  	pwhashbytes, err := json.Marshal(WalletPwHash)
   302  	if err != nil {
   303  		storelog.Error("SetEncryptionFlag marshal flag", "err", err)
   304  		return types.ErrMarshal
   305  	}
   306  	batch.Set(CalcPasswordHash(), pwhashbytes)
   307  	return nil
   308  }
   309  
   310  // VerifyPasswordHash 检查密码有效性
   311  func (store *Store) VerifyPasswordHash(password string) bool {
   312  	var WalletPwHash types.WalletPwHash
   313  	pwhashbytes, err := store.Get(CalcPasswordHash())
   314  	if pwhashbytes == nil || err != nil {
   315  		return false
   316  	}
   317  	err = json.Unmarshal(pwhashbytes, &WalletPwHash)
   318  	if err != nil {
   319  		storelog.Error("VerifyPasswordHash unmarshal", "err", err)
   320  		return false
   321  	}
   322  	pwhashstr := fmt.Sprintf("%s:%s", password, WalletPwHash.Randstr)
   323  	pwhash := sha256.Sum256([]byte(pwhashstr))
   324  	Pwhash := pwhash[:]
   325  	//通过新的密码计算pwhash最对比
   326  	return bytes.Equal(WalletPwHash.GetPwHash(), Pwhash)
   327  }
   328  
   329  // DelAccountByLabel 根据标签名称,删除对应的账号信息
   330  func (store *Store) DelAccountByLabel(label string) {
   331  	err := store.GetDB().DeleteSync(CalcLabelKey(label))
   332  	if err != nil {
   333  		storelog.Error("DelAccountByLabel", "err", err)
   334  	}
   335  }
   336  
   337  //SetWalletVersion 升级数据库的版本号
   338  func (store *Store) SetWalletVersion(ver int64) error {
   339  	data, err := json.Marshal(ver)
   340  	if err != nil {
   341  		storelog.Error("SetWalletVerKey marshal version", "err", err)
   342  		return types.ErrMarshal
   343  	}
   344  	return store.GetDB().SetSync(version.WalletVerKey, data)
   345  }
   346  
   347  // GetWalletVersion 获取wallet数据库的版本号
   348  func (store *Store) GetWalletVersion() int64 {
   349  	var ver int64
   350  	data, err := store.Get(version.WalletVerKey)
   351  	if data == nil || err != nil {
   352  		return 0
   353  	}
   354  	err = json.Unmarshal(data, &ver)
   355  	if err != nil {
   356  		storelog.Error("GetWalletVersion unmarshal", "err", err)
   357  		return 0
   358  	}
   359  	return ver
   360  }
   361  
   362  //HasSeed 判断钱包是否已经保存seed
   363  func (store *Store) HasSeed() (bool, error) {
   364  	seed, err := store.Get(CalcWalletSeed())
   365  	if len(seed) == 0 || err != nil {
   366  		return false, types.ErrSeedExist
   367  	}
   368  	return true, nil
   369  }
   370  
   371  // GetAirDropIndex 获取指定index的空投地址
   372  func (store *Store) GetAirDropIndex() (string, error) {
   373  	var airDrop AddrInfo
   374  	data, err := store.Get(CalcAirDropIndex())
   375  	if data == nil || err != nil {
   376  		if err != db.ErrNotFoundInDb {
   377  			storelog.Debug("GetAirDropIndex", "err", err)
   378  		}
   379  		return "", types.ErrAddrNotExist
   380  	}
   381  	err = json.Unmarshal(data, &airDrop)
   382  	if err != nil {
   383  		storelog.Error("GetWalletVersion unmarshal", "err", err)
   384  		return "", err
   385  	}
   386  	storelog.Debug("GetAirDropIndex ", "airDrop", airDrop)
   387  	return airDrop.Addr, nil
   388  }
   389  
   390  // SetAirDropIndex 存储指定index的空投地址信息
   391  func (store *Store) SetAirDropIndex(airDropIndex *AddrInfo) error {
   392  	data, err := json.Marshal(airDropIndex)
   393  	if err != nil {
   394  		storelog.Error("SetAirDropIndex marshal", "err", err)
   395  		return err
   396  	}
   397  
   398  	storelog.Debug("SetAirDropIndex ", "airDropIndex", airDropIndex)
   399  	return store.GetDB().SetSync(CalcAirDropIndex(), data)
   400  }