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