OSDN Git Service

update SetUnconfirmedTransaction
[bytom/vapor.git] / database / wallet_store.go
1 package database
2
3 import (
4         "encoding/binary"
5         "encoding/json"
6         "fmt"
7         "sort"
8
9         acc "github.com/vapor/account"
10         "github.com/vapor/asset"
11         "github.com/vapor/blockchain/query"
12         "github.com/vapor/blockchain/signers"
13         "github.com/vapor/common"
14         "github.com/vapor/crypto/ed25519/chainkd"
15         "github.com/vapor/crypto/sha3pool"
16         dbm "github.com/vapor/database/leveldb"
17         "github.com/vapor/errors"
18         "github.com/vapor/protocol/bc"
19 )
20
21 const (
22         // UTXOPrefix          = "ACU:" //UTXOPrefix is StandardUTXOKey prefix
23         // SUTXOPrefix         = "SCU:" //SUTXOPrefix is ContractUTXOKey prefix
24
25         ContractPrefix = "Contract:"
26
27 // ContractIndexPrefix = "ContractIndex:"
28 // AccountPrefix       = "Account:" // AccountPrefix is account ID prefix
29 // AccountAliasPrefix  = "AccountAlias:"
30 // AccountIndexPrefix  = "AccountIndex:"
31 // TxPrefix            = "TXS:"  //TxPrefix is wallet database transactions prefix
32 // TxIndexPrefix       = "TID:"  //TxIndexPrefix is wallet database tx index prefix
33 // UnconfirmedTxPrefix = "UTXS:" //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
34 // GlobalTxIndexPrefix = "GTID:" //GlobalTxIndexPrefix is wallet database global tx index prefix
35 // WalletKey        = "WalletInfo"
36 // MiningAddressKey = "MiningAddress"
37 // CoinbaseAbKey    = "CoinbaseArbitrary"
38 )
39
40 const (
41         utxoPrefix  byte = iota //UTXOPrefix is StandardUTXOKey prefix
42         sUTXOPrefix             //SUTXOPrefix is ContractUTXOKey prefix
43         contractPrefix
44         contractIndexPrefix
45         accountPrefix // AccountPrefix is account ID prefix
46         accountAliasPrefix
47         accountIndexPrefix
48         txPrefix            //TxPrefix is wallet database transactions prefix
49         txIndexPrefix       //TxIndexPrefix is wallet database tx index prefix
50         unconfirmedTxPrefix //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
51         globalTxIndexPrefix //GlobalTxIndexPrefix is wallet database global tx index prefix
52         walletKey
53         miningAddressKey
54         coinbaseAbKey
55 )
56
57 // leveldb key prefix
58 var (
59         UTXOPrefix  = []byte{utxoPrefix, colon}
60         SUTXOPrefix = []byte{sUTXOPrefix, colon}
61         // ContractPrefix      = []byte{contractPrefix, colon}
62         ContractIndexPrefix = []byte{contractIndexPrefix, colon}
63         AccountPrefix       = []byte{accountPrefix, colon} // AccountPrefix is account ID prefix
64         AccountAliasPrefix  = []byte{accountAliasPrefix, colon}
65         AccountIndexPrefix  = []byte{accountIndexPrefix, colon}
66         TxPrefix            = []byte{txPrefix, colon}            //TxPrefix is wallet database transactions prefix
67         TxIndexPrefix       = []byte{txIndexPrefix, colon}       //TxIndexPrefix is wallet database tx index prefix
68         UnconfirmedTxPrefix = []byte{unconfirmedTxPrefix, colon} //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
69         GlobalTxIndexPrefix = []byte{globalTxIndexPrefix, colon} //GlobalTxIndexPrefix is wallet database global tx index prefix
70         WalletKey           = []byte{walletKey}
71         MiningAddressKey    = []byte{miningAddressKey}
72         CoinbaseAbKey       = []byte{coinbaseAbKey}
73 )
74
75 // errors
76 var (
77         // ErrFindAccount        = errors.New("Failed to find account")
78         errAccntTxIDNotFound  = errors.New("account TXID not found")
79         errGetAssetDefinition = errors.New("Failed to find asset definition")
80 )
81
82 func accountIndexKey(xpubs []chainkd.XPub) []byte {
83         var hash [32]byte
84         var xPubs []byte
85         cpy := append([]chainkd.XPub{}, xpubs[:]...)
86         sort.Sort(signers.SortKeys(cpy))
87         for _, xpub := range cpy {
88                 xPubs = append(xPubs, xpub[:]...)
89         }
90         sha3pool.Sum256(hash[:], xPubs)
91         return append([]byte(AccountIndexPrefix), hash[:]...)
92 }
93
94 func Bip44ContractIndexKey(accountID string, change bool) []byte {
95         key := append([]byte(ContractIndexPrefix), accountID...)
96         if change {
97                 return append(key, []byte{1}...)
98         }
99         return append(key, []byte{0}...)
100 }
101
102 // ContractKey account control promgram store prefix
103 func ContractKey(hash common.Hash) []byte {
104         // h := hash.Str()
105         // return append([]byte(ContractPrefix), []byte(h)...)
106         return append([]byte(ContractPrefix), hash.Bytes()...)
107 }
108
109 // AccountIDKey account id store prefix
110 func AccountIDKey(accountID string) []byte {
111         return append([]byte(AccountPrefix), []byte(accountID)...)
112 }
113
114 // StandardUTXOKey makes an account unspent outputs key to store
115 func StandardUTXOKey(id bc.Hash) []byte {
116         name := id.String()
117         return append(UTXOPrefix, []byte(name)...)
118 }
119
120 // ContractUTXOKey makes a smart contract unspent outputs key to store
121 func ContractUTXOKey(id bc.Hash) []byte {
122         name := id.String()
123         return append(SUTXOPrefix, []byte(name)...)
124 }
125
126 func calcDeleteKey(blockHeight uint64) []byte {
127         return []byte(fmt.Sprintf("%s%016x", TxPrefix, blockHeight))
128 }
129
130 func calcTxIndexKey(txID string) []byte {
131         return append(TxIndexPrefix, []byte(txID)...)
132 }
133
134 func calcAnnotatedKey(formatKey string) []byte {
135         return append(TxPrefix, []byte(formatKey)...)
136 }
137
138 func calcUnconfirmedTxKey(formatKey string) []byte {
139         return append(UnconfirmedTxPrefix, []byte(formatKey)...)
140 }
141
142 func calcGlobalTxIndexKey(txID string) []byte {
143         return append(GlobalTxIndexPrefix, []byte(txID)...)
144 }
145
146 func CalcGlobalTxIndex(blockHash *bc.Hash, position uint64) []byte {
147         txIdx := make([]byte, 40)
148         copy(txIdx[:32], blockHash.Bytes())
149         binary.BigEndian.PutUint64(txIdx[32:], position)
150         return txIdx
151 }
152
153 func formatKey(blockHeight uint64, position uint32) string {
154         return fmt.Sprintf("%016x%08x", blockHeight, position)
155 }
156
157 func contractIndexKey(accountID string) []byte {
158         return append([]byte(ContractIndexPrefix), []byte(accountID)...)
159 }
160
161 func accountAliasKey(name string) []byte {
162         return append([]byte(AccountAliasPrefix), []byte(name)...)
163 }
164
165 // WalletStore store wallet using leveldb
166 type WalletStore struct {
167         walletDB dbm.DB
168         batch    dbm.Batch
169 }
170
171 // NewWalletStore create new WalletStore struct
172 func NewWalletStore(db dbm.DB) *WalletStore {
173         return &WalletStore{
174                 walletDB: db,
175                 batch:    nil,
176         }
177 }
178
179 // InitBatch initial batch
180 func (store *WalletStore) InitBatch() {
181         if store.batch == nil {
182                 store.batch = store.walletDB.NewBatch()
183         }
184 }
185
186 // CommitBatch commit batch
187 func (store *WalletStore) CommitBatch() {
188         if store.batch != nil {
189                 store.batch.Write()
190                 store.batch = nil
191         }
192 }
193
194 // GetAssetDefinition get asset definition by assetiD
195 func (store *WalletStore) GetAssetDefinition(assetID *bc.AssetID) (*asset.Asset, error) {
196         definitionByte := store.walletDB.Get(asset.ExtAssetKey(assetID))
197         if definitionByte == nil {
198                 return nil, errGetAssetDefinition
199         }
200         definitionMap := make(map[string]interface{})
201         if err := json.Unmarshal(definitionByte, &definitionMap); err != nil {
202                 return nil, err
203         }
204         alias := assetID.String()
205         externalAsset := &asset.Asset{
206                 AssetID:           *assetID,
207                 Alias:             &alias,
208                 DefinitionMap:     definitionMap,
209                 RawDefinitionByte: definitionByte,
210         }
211         return externalAsset, nil
212 }
213
214 // SetAssetDefinition set assetID and definition
215 func (store *WalletStore) SetAssetDefinition(assetID *bc.AssetID, definition []byte) {
216         if store.batch == nil {
217                 store.walletDB.Set(asset.ExtAssetKey(assetID), definition)
218         } else {
219                 store.batch.Set(asset.ExtAssetKey(assetID), definition)
220         }
221 }
222
223 // GetControlProgram get raw program by hash
224 func (store *WalletStore) GetControlProgram(hash common.Hash) (*acc.CtrlProgram, error) {
225         rawProgram := store.walletDB.Get(ContractKey(hash))
226         if rawProgram == nil {
227                 return nil, fmt.Errorf("failed get account control program:%x ", hash)
228         }
229         accountCP := new(acc.CtrlProgram)
230         if err := json.Unmarshal(rawProgram, &accountCP); err != nil {
231                 return nil, err
232         }
233         return accountCP, nil
234 }
235
236 // GetAccountByAccountID get account value by account ID
237 func (store *WalletStore) GetAccountByAccountID(accountID string) (*acc.Account, error) {
238         rawAccount := store.walletDB.Get(AccountIDKey(accountID))
239         if rawAccount == nil {
240                 return nil, fmt.Errorf("failed get account, accountID: %s ", accountID)
241         }
242         account := new(acc.Account)
243         if err := json.Unmarshal(rawAccount, account); err != nil {
244                 return nil, err
245         }
246         return account, nil
247 }
248
249 // DeleteTransactions delete transactions when orphan block rollback
250 func (store *WalletStore) DeleteTransactions(height uint64) {
251         batch := store.walletDB.NewBatch()
252         if store.batch != nil {
253                 batch = store.batch
254         }
255         txIter := store.walletDB.IteratorPrefix(calcDeleteKey(height))
256         defer txIter.Release()
257
258         tmpTx := query.AnnotatedTx{}
259         for txIter.Next() {
260                 if err := json.Unmarshal(txIter.Value(), &tmpTx); err == nil {
261                         batch.Delete(calcTxIndexKey(tmpTx.ID.String()))
262                 }
263                 batch.Delete(txIter.Key())
264         }
265         if store.batch == nil {
266                 batch.Write()
267         }
268 }
269
270 // SetTransaction set raw transaction by block height and tx position
271 func (store *WalletStore) SetTransaction(height uint64, tx *query.AnnotatedTx) error {
272         batch := store.walletDB.NewBatch()
273         if store.batch != nil {
274                 batch = store.batch
275         }
276
277         rawTx, err := json.Marshal(tx)
278         if err != nil {
279                 return err
280         }
281         batch.Set(calcAnnotatedKey(formatKey(height, tx.Position)), rawTx)
282         batch.Set(calcTxIndexKey(tx.ID.String()), []byte(formatKey(height, tx.Position)))
283
284         if store.batch == nil {
285                 batch.Write()
286         }
287         return nil
288 }
289
290 // DeleteUnconfirmedTransaction delete unconfirmed tx by txID
291 func (store *WalletStore) DeleteUnconfirmedTransaction(txID string) {
292         if store.batch == nil {
293                 store.walletDB.Delete(calcUnconfirmedTxKey(txID))
294         } else {
295                 store.batch.Delete(calcUnconfirmedTxKey(txID))
296         }
297 }
298
299 // SetGlobalTransactionIndex set global tx index by blockhash and position
300 func (store *WalletStore) SetGlobalTransactionIndex(globalTxID string, blockHash *bc.Hash, position uint64) {
301         if store.batch == nil {
302                 store.walletDB.Set(calcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
303         } else {
304                 store.batch.Set(calcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
305         }
306 }
307
308 // GetStandardUTXO get standard utxo by id
309 func (store *WalletStore) GetStandardUTXO(outid bc.Hash) (*acc.UTXO, error) {
310         rawUTXO := store.walletDB.Get(StandardUTXOKey(outid))
311         if rawUTXO == nil {
312                 return nil, fmt.Errorf("failed get standard UTXO, outputID: %s ", outid.String())
313         }
314         UTXO := new(acc.UTXO)
315         if err := json.Unmarshal(rawUTXO, UTXO); err != nil {
316                 return nil, err
317         }
318         return UTXO, nil
319 }
320
321 // GetTransaction get tx by txid
322 func (store *WalletStore) GetTransaction(txID string) (*query.AnnotatedTx, error) {
323         formatKey := store.walletDB.Get(calcTxIndexKey(txID))
324         if formatKey == nil {
325                 return nil, errAccntTxIDNotFound
326         }
327         rawTx := store.walletDB.Get(calcAnnotatedKey(string(formatKey)))
328         tx := new(query.AnnotatedTx)
329         if err := json.Unmarshal(rawTx, tx); err != nil {
330                 return nil, err
331         }
332         return tx, nil
333 }
334
335 // GetGlobalTransactionIndex get global tx by txID
336 func (store *WalletStore) GetGlobalTransactionIndex(txID string) []byte {
337         return store.walletDB.Get(calcGlobalTxIndexKey(txID))
338 }
339
340 // GetTransactions get all walletDB transactions
341 func (store *WalletStore) GetTransactions() ([]*query.AnnotatedTx, error) {
342         annotatedTxs := []*query.AnnotatedTx{}
343
344         txIter := store.walletDB.IteratorPrefix([]byte(TxPrefix))
345         defer txIter.Release()
346         for txIter.Next() {
347                 annotatedTx := &query.AnnotatedTx{}
348                 if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
349                         return nil, err
350                 }
351                 annotatedTxs = append(annotatedTxs, annotatedTx)
352         }
353
354         return annotatedTxs, nil
355 }
356
357 // GetUnconfirmedTransactions get all unconfirmed txs
358 func (store *WalletStore) GetUnconfirmedTransactions() ([]*query.AnnotatedTx, error) {
359         annotatedTxs := []*query.AnnotatedTx{}
360         txIter := store.walletDB.IteratorPrefix([]byte(UnconfirmedTxPrefix))
361         defer txIter.Release()
362
363         for txIter.Next() {
364                 annotatedTx := &query.AnnotatedTx{}
365                 if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
366                         return nil, err
367                 }
368                 annotatedTxs = append(annotatedTxs, annotatedTx)
369         }
370         return annotatedTxs, nil
371 }
372
373 // GetUnconfirmedTransaction get unconfirmed tx by txID
374 func (store *WalletStore) GetUnconfirmedTransaction(txID string) (*query.AnnotatedTx, error) {
375         rawUnconfirmedTx := store.walletDB.Get(calcUnconfirmedTxKey(txID))
376         if rawUnconfirmedTx == nil {
377                 return nil, fmt.Errorf("failed get unconfirmed tx, txID: %s ", txID)
378         }
379         tx := new(query.AnnotatedTx)
380         if err := json.Unmarshal(rawUnconfirmedTx, tx); err != nil {
381                 return nil, err
382         }
383         return tx, nil
384 }
385
386 // SetUnconfirmedTransaction set unconfirmed tx by txID
387 func (store *WalletStore) SetUnconfirmedTransaction(txID string, tx *query.AnnotatedTx) error {
388         rawTx, err := json.Marshal(tx)
389         if err != nil {
390                 return err
391         }
392         if store.batch == nil {
393                 store.walletDB.Set(calcUnconfirmedTxKey(txID), rawTx)
394         } else {
395                 store.batch.Set(calcUnconfirmedTxKey(txID), rawTx)
396         }
397         return nil
398 }
399
400 // DeleteStardardUTXO delete stardard utxo by outputID
401 func (store *WalletStore) DeleteStardardUTXO(outputID bc.Hash) {
402         if store.batch == nil {
403                 store.walletDB.Delete(StandardUTXOKey(outputID))
404         } else {
405                 store.batch.Delete(StandardUTXOKey(outputID))
406         }
407 }
408
409 // DeleteContractUTXO delete contract utxo by outputID
410 func (store *WalletStore) DeleteContractUTXO(outputID bc.Hash) {
411         if store.batch == nil {
412                 store.walletDB.Delete(ContractUTXOKey(outputID))
413         } else {
414                 store.batch.Delete(ContractUTXOKey(outputID))
415         }
416 }
417
418 // SetStandardUTXO set standard utxo
419 func (store *WalletStore) SetStandardUTXO(outputID bc.Hash, data []byte) {
420         if store.batch == nil {
421                 store.walletDB.Set(StandardUTXOKey(outputID), data)
422         } else {
423                 store.batch.Set(StandardUTXOKey(outputID), data)
424         }
425 }
426
427 // SetContractUTXO set standard utxo
428 func (store *WalletStore) SetContractUTXO(outputID bc.Hash, data []byte) {
429         if store.batch == nil {
430                 store.walletDB.Set(ContractUTXOKey(outputID), data)
431         } else {
432                 store.batch.Set(ContractUTXOKey(outputID), data)
433         }
434 }
435
436 // GetWalletInfo get wallet information
437 func (store *WalletStore) GetWalletInfo() []byte {
438         return store.walletDB.Get([]byte(WalletKey))
439 }
440
441 // SetWalletInfo get wallet information
442 func (store *WalletStore) SetWalletInfo(rawWallet []byte) {
443         if store.batch == nil {
444                 store.walletDB.Set([]byte(WalletKey), rawWallet)
445         } else {
446                 store.batch.Set([]byte(WalletKey), rawWallet)
447         }
448 }
449
450 // DeleteWalletTransactions delete all txs in wallet
451 func (store *WalletStore) DeleteWalletTransactions() {
452         batch := store.walletDB.NewBatch()
453         if store.batch != nil {
454                 batch = store.batch
455         }
456         txIter := store.walletDB.IteratorPrefix([]byte(TxPrefix))
457         defer txIter.Release()
458
459         for txIter.Next() {
460                 batch.Delete(txIter.Key())
461         }
462
463         txIndexIter := store.walletDB.IteratorPrefix([]byte(TxIndexPrefix))
464         defer txIndexIter.Release()
465
466         for txIndexIter.Next() {
467                 batch.Delete(txIndexIter.Key())
468         }
469         if store.batch == nil {
470                 batch.Write()
471         }
472 }
473
474 // DeleteWalletUTXOs delete all txs in wallet
475 func (store *WalletStore) DeleteWalletUTXOs() {
476         batch := store.walletDB.NewBatch()
477         if store.batch != nil {
478                 batch = store.batch
479         }
480         ruIter := store.walletDB.IteratorPrefix([]byte(UTXOPrefix))
481         defer ruIter.Release()
482         for ruIter.Next() {
483                 batch.Delete(ruIter.Key())
484         }
485
486         suIter := store.walletDB.IteratorPrefix([]byte(SUTXOPrefix))
487         defer suIter.Release()
488         for suIter.Next() {
489                 batch.Delete(suIter.Key())
490         }
491         if store.batch == nil {
492                 batch.Write()
493         }
494 }
495
496 // GetAccountUTXOs get all account unspent outputs
497 func (store *WalletStore) GetAccountUTXOs(key string) [][]byte {
498         accountUtxoIter := store.walletDB.IteratorPrefix([]byte(key))
499         defer accountUtxoIter.Release()
500
501         rawUTXOs := make([][]byte, 0)
502         for accountUtxoIter.Next() {
503                 utxo := accountUtxoIter.Value()
504                 rawUTXOs = append(rawUTXOs, utxo)
505         }
506         return rawUTXOs
507 }
508
509 // SetRecoveryStatus set recovery status
510 func (store *WalletStore) SetRecoveryStatus(recoveryKey, rawStatus []byte) {
511         if store.batch == nil {
512                 store.walletDB.Set(recoveryKey, rawStatus)
513         } else {
514                 store.batch.Set(recoveryKey, rawStatus)
515         }
516 }
517
518 // DeleteRecoveryStatus delete recovery status
519 func (store *WalletStore) DeleteRecoveryStatus(recoveryKey []byte) {
520         if store.batch == nil {
521                 store.walletDB.Delete(recoveryKey)
522         } else {
523                 store.batch.Delete(recoveryKey)
524         }
525 }
526
527 // GetRecoveryStatus delete recovery status
528 func (store *WalletStore) GetRecoveryStatus(recoveryKey []byte) []byte {
529         return store.walletDB.Get(recoveryKey)
530 }