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 }