OSDN Git Service

update GetTransaction
[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 // GetGlobalTransaction get global tx by txID
336 func (store *WalletStore) GetGlobalTransaction(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) []byte {
375         return store.walletDB.Get(calcUnconfirmedTxKey(txID))
376 }
377
378 // SetUnconfirmedTransaction set unconfirmed tx by txID
379 func (store *WalletStore) SetUnconfirmedTransaction(txID string, rawTx []byte) {
380         if store.batch == nil {
381                 store.walletDB.Set(calcUnconfirmedTxKey(txID), rawTx)
382         } else {
383                 store.batch.Set(calcUnconfirmedTxKey(txID), rawTx)
384         }
385 }
386
387 // DeleteStardardUTXO delete stardard utxo by outputID
388 func (store *WalletStore) DeleteStardardUTXO(outputID bc.Hash) {
389         if store.batch == nil {
390                 store.walletDB.Delete(StandardUTXOKey(outputID))
391         } else {
392                 store.batch.Delete(StandardUTXOKey(outputID))
393         }
394 }
395
396 // DeleteContractUTXO delete contract utxo by outputID
397 func (store *WalletStore) DeleteContractUTXO(outputID bc.Hash) {
398         if store.batch == nil {
399                 store.walletDB.Delete(ContractUTXOKey(outputID))
400         } else {
401                 store.batch.Delete(ContractUTXOKey(outputID))
402         }
403 }
404
405 // SetStandardUTXO set standard utxo
406 func (store *WalletStore) SetStandardUTXO(outputID bc.Hash, data []byte) {
407         if store.batch == nil {
408                 store.walletDB.Set(StandardUTXOKey(outputID), data)
409         } else {
410                 store.batch.Set(StandardUTXOKey(outputID), data)
411         }
412 }
413
414 // SetContractUTXO set standard utxo
415 func (store *WalletStore) SetContractUTXO(outputID bc.Hash, data []byte) {
416         if store.batch == nil {
417                 store.walletDB.Set(ContractUTXOKey(outputID), data)
418         } else {
419                 store.batch.Set(ContractUTXOKey(outputID), data)
420         }
421 }
422
423 // GetWalletInfo get wallet information
424 func (store *WalletStore) GetWalletInfo() []byte {
425         return store.walletDB.Get([]byte(WalletKey))
426 }
427
428 // SetWalletInfo get wallet information
429 func (store *WalletStore) SetWalletInfo(rawWallet []byte) {
430         if store.batch == nil {
431                 store.walletDB.Set([]byte(WalletKey), rawWallet)
432         } else {
433                 store.batch.Set([]byte(WalletKey), rawWallet)
434         }
435 }
436
437 // DeleteWalletTransactions delete all txs in wallet
438 func (store *WalletStore) DeleteWalletTransactions() {
439         batch := store.walletDB.NewBatch()
440         if store.batch != nil {
441                 batch = store.batch
442         }
443         txIter := store.walletDB.IteratorPrefix([]byte(TxPrefix))
444         defer txIter.Release()
445
446         for txIter.Next() {
447                 batch.Delete(txIter.Key())
448         }
449
450         txIndexIter := store.walletDB.IteratorPrefix([]byte(TxIndexPrefix))
451         defer txIndexIter.Release()
452
453         for txIndexIter.Next() {
454                 batch.Delete(txIndexIter.Key())
455         }
456         if store.batch == nil {
457                 batch.Write()
458         }
459 }
460
461 // DeleteWalletUTXOs delete all txs in wallet
462 func (store *WalletStore) DeleteWalletUTXOs() {
463         batch := store.walletDB.NewBatch()
464         if store.batch != nil {
465                 batch = store.batch
466         }
467         ruIter := store.walletDB.IteratorPrefix([]byte(UTXOPrefix))
468         defer ruIter.Release()
469         for ruIter.Next() {
470                 batch.Delete(ruIter.Key())
471         }
472
473         suIter := store.walletDB.IteratorPrefix([]byte(SUTXOPrefix))
474         defer suIter.Release()
475         for suIter.Next() {
476                 batch.Delete(suIter.Key())
477         }
478         if store.batch == nil {
479                 batch.Write()
480         }
481 }
482
483 // GetAccountUTXOs get all account unspent outputs
484 func (store *WalletStore) GetAccountUTXOs(key string) [][]byte {
485         accountUtxoIter := store.walletDB.IteratorPrefix([]byte(key))
486         defer accountUtxoIter.Release()
487
488         rawUTXOs := make([][]byte, 0)
489         for accountUtxoIter.Next() {
490                 utxo := accountUtxoIter.Value()
491                 rawUTXOs = append(rawUTXOs, utxo)
492         }
493         return rawUTXOs
494 }
495
496 // SetRecoveryStatus set recovery status
497 func (store *WalletStore) SetRecoveryStatus(recoveryKey, rawStatus []byte) {
498         if store.batch == nil {
499                 store.walletDB.Set(recoveryKey, rawStatus)
500         } else {
501                 store.batch.Set(recoveryKey, rawStatus)
502         }
503 }
504
505 // DeleteRecoveryStatus delete recovery status
506 func (store *WalletStore) DeleteRecoveryStatus(recoveryKey []byte) {
507         if store.batch == nil {
508                 store.walletDB.Delete(recoveryKey)
509         } else {
510                 store.batch.Delete(recoveryKey)
511         }
512 }
513
514 // GetRecoveryStatus delete recovery status
515 func (store *WalletStore) GetRecoveryStatus(recoveryKey []byte) []byte {
516         return store.walletDB.Get(recoveryKey)
517 }