OSDN Git Service

update wallet_store.go
[bytom/vapor.git] / database / wallet_store.go
1 package database
2
3 import (
4         "encoding/binary"
5         "encoding/json"
6         "fmt"
7
8         "github.com/vapor/asset"
9         "github.com/vapor/blockchain/query"
10         "github.com/vapor/common"
11         dbm "github.com/vapor/database/leveldb"
12         "github.com/vapor/errors"
13         "github.com/vapor/protocol/bc"
14 )
15
16 var errAccntTxIDNotFound = errors.New("account TXID not found")
17
18 const (
19         UTXOPrefix          = "ACU:" //UTXOPrefix is StandardUTXOKey prefix
20         SUTXOPrefix         = "SCU:" //SUTXOPrefix is ContractUTXOKey prefix
21         contractPrefix      = "Contract:"
22         accountPrefix       = "Account:"
23         TxPrefix            = "TXS:"  //TxPrefix is wallet database transactions prefix
24         TxIndexPrefix       = "TID:"  //TxIndexPrefix is wallet database tx index prefix
25         UnconfirmedTxPrefix = "UTXS:" //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
26         GlobalTxIndexPrefix = "GTID:" //GlobalTxIndexPrefix is wallet database global tx index prefix
27         walletKey           = "walletInfo"
28 )
29
30 // WalletStorer interface contains wallet storage functions.
31 type WalletStorer interface {
32         InitBatch()
33         CommitBatch()
34         GetAssetDefinition(*bc.AssetID) []byte
35         SetAssetDefinition(*bc.AssetID, []byte)
36         GetRawProgram(common.Hash) []byte
37         GetAccountByAccountID(string) []byte
38         DeleteTransactions(uint64)
39         SetTransaction(uint64, uint32, string, []byte)
40         DeleteUnconfirmedTransaction(string)
41         SetGlobalTransactionIndex(string, *bc.Hash, uint64)
42         GetStandardUTXO(bc.Hash) []byte
43         GetTransaction(string) ([]byte, error)
44         GetGlobalTransaction(string) []byte
45         GetTransactions() ([]*query.AnnotatedTx, error)
46         GetUnconfirmedTransactions() ([]*query.AnnotatedTx, error)
47         GetUnconfirmedTransaction(string) []byte
48         SetUnconfirmedTransaction(string, []byte)
49         DeleteStardardUTXO(bc.Hash)
50         DeleteContractUTXO(bc.Hash)
51         SetStandardUTXO(bc.Hash, []byte)
52         SetContractUTXO(bc.Hash, []byte)
53         GetWalletInfo() []byte
54         SetWalletInfo([]byte)
55         DeleteWalletTransactions()
56         DeleteWalletUTXOs()
57         GetAccountUTXOs(key string) [][]byte
58         SetRecoveryStatus([]byte, []byte)
59         DeleteRecoveryStatus([]byte)
60         GetRecoveryStatus([]byte) []byte
61 }
62
63 // WalletStore store wallet using leveldb
64 type WalletStore struct {
65         DB    dbm.DB
66         batch dbm.Batch
67 }
68
69 // NewWalletStore create new WalletStore struct
70 func NewWalletStore(db dbm.DB) *WalletStore {
71         return &WalletStore{
72                 DB: db,
73         }
74 }
75
76 // InitBatch initial batch
77 func (store *WalletStore) InitBatch() {
78         store.batch = store.DB.NewBatch()
79 }
80
81 // CommitBatch commit batch
82 func (store *WalletStore) CommitBatch() {
83         if store.batch != nil {
84                 store.batch.Write()
85         }
86 }
87
88 // ContractKey account control promgram store prefix
89 func ContractKey(hash common.Hash) []byte {
90         return append([]byte(contractPrefix), hash[:]...)
91 }
92
93 // Key account store prefix
94 func Key(name string) []byte {
95         return append([]byte(accountPrefix), []byte(name)...)
96 }
97
98 // StandardUTXOKey makes an account unspent outputs key to store
99 func StandardUTXOKey(id bc.Hash) []byte {
100         name := id.String()
101         return []byte(UTXOPrefix + name)
102 }
103
104 // ContractUTXOKey makes a smart contract unspent outputs key to store
105 func ContractUTXOKey(id bc.Hash) []byte {
106         name := id.String()
107         return []byte(SUTXOPrefix + name)
108 }
109
110 func calcDeleteKey(blockHeight uint64) []byte {
111         return []byte(fmt.Sprintf("%s%016x", TxPrefix, blockHeight))
112 }
113
114 func calcTxIndexKey(txID string) []byte {
115         return []byte(TxIndexPrefix + txID)
116 }
117
118 func calcAnnotatedKey(formatKey string) []byte {
119         return []byte(TxPrefix + formatKey)
120 }
121
122 func calcUnconfirmedTxKey(formatKey string) []byte {
123         return []byte(UnconfirmedTxPrefix + formatKey)
124 }
125
126 func calcGlobalTxIndexKey(txID string) []byte {
127         return []byte(GlobalTxIndexPrefix + txID)
128 }
129
130 func CalcGlobalTxIndex(blockHash *bc.Hash, position uint64) []byte {
131         txIdx := make([]byte, 40)
132         copy(txIdx[:32], blockHash.Bytes())
133         binary.BigEndian.PutUint64(txIdx[32:], position)
134         return txIdx
135 }
136
137 func formatKey(blockHeight uint64, position uint32) string {
138         return fmt.Sprintf("%016x%08x", blockHeight, position)
139 }
140
141 // GetAssetDefinition get asset definition by assetiD
142 func (store *WalletStore) GetAssetDefinition(assetID *bc.AssetID) []byte {
143         return store.DB.Get(asset.ExtAssetKey(assetID))
144 }
145
146 // SetAssetDefinition set assetID and definition
147 func (store *WalletStore) SetAssetDefinition(assetID *bc.AssetID, definition []byte) {
148         if store.batch == nil {
149                 store.DB.Set(asset.ExtAssetKey(assetID), definition)
150         } else {
151                 store.batch.Set(asset.ExtAssetKey(assetID), definition)
152         }
153 }
154
155 // GetRawProgram get raw program by hash
156 func (store *WalletStore) GetRawProgram(hash common.Hash) []byte {
157         return store.DB.Get(ContractKey(hash))
158 }
159
160 // GetAccountByAccountID get account value by account ID
161 func (store *WalletStore) GetAccountByAccountID(accountID string) []byte {
162         return store.DB.Get(Key(accountID))
163 }
164
165 // DeleteTransactions delete transactions when orphan block rollback
166 func (store *WalletStore) DeleteTransactions(height uint64) {
167         tmpTx := query.AnnotatedTx{}
168         txIter := store.DB.IteratorPrefix(calcDeleteKey(height))
169         defer txIter.Release()
170
171         for txIter.Next() {
172                 if err := json.Unmarshal(txIter.Value(), &tmpTx); err == nil {
173                         store.batch.Delete(calcTxIndexKey(tmpTx.ID.String()))
174                 }
175                 store.batch.Delete(txIter.Key())
176         }
177 }
178
179 // SetTransaction set raw transaction by block height and tx position
180 func (store *WalletStore) SetTransaction(height uint64, position uint32, txID string, rawTx []byte) {
181         if store.batch == nil {
182                 store.DB.Set(calcAnnotatedKey(formatKey(height, position)), rawTx)
183                 store.DB.Set(calcTxIndexKey(txID), []byte(formatKey(height, position)))
184         } else {
185                 store.batch.Set(calcAnnotatedKey(formatKey(height, position)), rawTx)
186                 store.batch.Set(calcTxIndexKey(txID), []byte(formatKey(height, position)))
187         }
188 }
189
190 // DeleteUnconfirmedTransaction delete unconfirmed tx by txID
191 func (store *WalletStore) DeleteUnconfirmedTransaction(txID string) {
192         if store.batch == nil {
193                 store.DB.Delete(calcUnconfirmedTxKey(txID))
194         } else {
195                 store.batch.Delete(calcUnconfirmedTxKey(txID))
196         }
197 }
198
199 // SetGlobalTransactionIndex set global tx index by blockhash and position
200 func (store *WalletStore) SetGlobalTransactionIndex(globalTxID string, blockHash *bc.Hash, position uint64) {
201         if store.batch == nil {
202                 store.DB.Set(calcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
203         } else {
204                 store.batch.Set(calcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
205         }
206 }
207
208 // GetStandardUTXO get standard utxo by id
209 func (store *WalletStore) GetStandardUTXO(outid bc.Hash) []byte {
210         return store.DB.Get(StandardUTXOKey(outid))
211 }
212
213 // GetTransaction get tx by tx index
214 func (store *WalletStore) GetTransaction(txID string) ([]byte, error) {
215         formatKey := store.DB.Get(calcTxIndexKey(txID))
216         if formatKey == nil {
217                 return nil, errAccntTxIDNotFound
218         }
219         txInfo := store.DB.Get(calcAnnotatedKey(string(formatKey)))
220         return txInfo, nil
221 }
222
223 // GetGlobalTransaction get global tx by txID
224 func (store *WalletStore) GetGlobalTransaction(txID string) []byte {
225         return store.DB.Get(calcGlobalTxIndexKey(txID))
226 }
227
228 // GetTransactions get all walletDB transactions
229 func (store *WalletStore) GetTransactions() ([]*query.AnnotatedTx, error) {
230         annotatedTxs := []*query.AnnotatedTx{}
231
232         txIter := store.DB.IteratorPrefix([]byte(TxPrefix))
233         defer txIter.Release()
234         for txIter.Next() {
235                 annotatedTx := &query.AnnotatedTx{}
236                 if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
237                         return nil, err
238                 }
239                 annotatedTxs = append(annotatedTxs, annotatedTx)
240         }
241
242         return annotatedTxs, nil
243 }
244
245 // GetUnconfirmedTransactions get all unconfirmed txs
246 func (store *WalletStore) GetUnconfirmedTransactions() ([]*query.AnnotatedTx, error) {
247         annotatedTxs := []*query.AnnotatedTx{}
248         txIter := store.DB.IteratorPrefix([]byte(UnconfirmedTxPrefix))
249         defer txIter.Release()
250
251         for txIter.Next() {
252                 annotatedTx := &query.AnnotatedTx{}
253                 if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
254                         return nil, err
255                 }
256                 annotatedTxs = append(annotatedTxs, annotatedTx)
257         }
258         return annotatedTxs, nil
259 }
260
261 // GetUnconfirmedTransaction get unconfirmed tx by txID
262 func (store *WalletStore) GetUnconfirmedTransaction(txID string) []byte {
263         return store.DB.Get(calcUnconfirmedTxKey(txID))
264 }
265
266 // SetUnconfirmedTransaction set unconfirmed tx by txID
267 func (store *WalletStore) SetUnconfirmedTransaction(txID string, rawTx []byte) {
268         if store.batch == nil {
269                 store.DB.Set(calcUnconfirmedTxKey(txID), rawTx)
270         } else {
271                 store.batch.Set(calcUnconfirmedTxKey(txID), rawTx)
272         }
273 }
274
275 // DeleteStardardUTXO delete stardard utxo by outputID
276 func (store *WalletStore) DeleteStardardUTXO(outputID bc.Hash) {
277         if store.batch == nil {
278                 store.DB.Delete(StandardUTXOKey(outputID))
279         } else {
280                 store.batch.Delete(StandardUTXOKey(outputID))
281         }
282 }
283
284 // DeleteContractUTXO delete contract utxo by outputID
285 func (store *WalletStore) DeleteContractUTXO(outputID bc.Hash) {
286         if store.batch == nil {
287                 store.DB.Delete(ContractUTXOKey(outputID))
288         } else {
289                 store.batch.Delete(ContractUTXOKey(outputID))
290         }
291 }
292
293 // SetStandardUTXO set standard utxo
294 func (store *WalletStore) SetStandardUTXO(outputID bc.Hash, data []byte) {
295         if store.batch == nil {
296                 store.DB.Set(StandardUTXOKey(outputID), data)
297         } else {
298                 store.batch.Set(StandardUTXOKey(outputID), data)
299         }
300 }
301
302 // SetContractUTXO set standard utxo
303 func (store *WalletStore) SetContractUTXO(outputID bc.Hash, data []byte) {
304         if store.batch == nil {
305                 store.DB.Set(ContractUTXOKey(outputID), data)
306         } else {
307                 store.batch.Set(ContractUTXOKey(outputID), data)
308         }
309 }
310
311 // GetWalletInfo get wallet information
312 func (store *WalletStore) GetWalletInfo() []byte {
313         return store.DB.Get([]byte(walletKey))
314 }
315
316 // SetWalletInfo get wallet information
317 func (store *WalletStore) SetWalletInfo(rawWallet []byte) {
318         if store.batch == nil {
319                 store.DB.Set([]byte(walletKey), rawWallet)
320         } else {
321                 store.batch.Set([]byte(walletKey), rawWallet)
322         }
323 }
324
325 // DeleteWalletTransactions delete all txs in wallet
326 func (store *WalletStore) DeleteWalletTransactions() {
327         batch := store.DB.NewBatch()
328         txIter := store.DB.IteratorPrefix([]byte(TxPrefix))
329         defer txIter.Release()
330
331         for txIter.Next() {
332                 batch.Delete(txIter.Key())
333         }
334
335         txIndexIter := store.DB.IteratorPrefix([]byte(TxIndexPrefix))
336         defer txIndexIter.Release()
337
338         for txIndexIter.Next() {
339                 batch.Delete(txIndexIter.Key())
340         }
341         batch.Write()
342 }
343
344 // DeleteWalletUTXOs delete all txs in wallet
345 func (store *WalletStore) DeleteWalletUTXOs() {
346         batch := store.DB.NewBatch()
347         ruIter := store.DB.IteratorPrefix([]byte(UTXOPrefix))
348         defer ruIter.Release()
349         for ruIter.Next() {
350                 batch.Delete(ruIter.Key())
351         }
352
353         suIter := store.DB.IteratorPrefix([]byte(SUTXOPrefix))
354         defer suIter.Release()
355         for suIter.Next() {
356                 batch.Delete(suIter.Key())
357         }
358         batch.Write()
359 }
360
361 // GetAccountUTXOs get all account unspent outputs
362 func (store *WalletStore) GetAccountUTXOs(key string) [][]byte {
363         accountUtxoIter := store.DB.IteratorPrefix([]byte(key))
364         defer accountUtxoIter.Release()
365
366         rawUTXOs := make([][]byte, 0)
367         for accountUtxoIter.Next() {
368                 utxo := accountUtxoIter.Value()
369                 rawUTXOs = append(rawUTXOs, utxo)
370         }
371         return rawUTXOs
372 }
373
374 // SetRecoveryStatus set recovery status
375 func (store *WalletStore) SetRecoveryStatus(recoveryKey, rawStatus []byte) {
376         if store.batch == nil {
377                 store.DB.Set(recoveryKey, rawStatus)
378         } else {
379                 store.batch.Set(recoveryKey, rawStatus)
380         }
381 }
382
383 // DeleteRecoveryStatus delete recovery status
384 func (store *WalletStore) DeleteRecoveryStatus(recoveryKey []byte) {
385         if store.batch == nil {
386                 store.DB.Delete(recoveryKey)
387         } else {
388                 store.batch.Delete(recoveryKey)
389         }
390 }
391
392 // GetRecoveryStatus delete recovery status
393 func (store *WalletStore) GetRecoveryStatus(recoveryKey []byte) []byte {
394         return store.DB.Get(recoveryKey)
395 }