OSDN Git Service

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