OSDN Git Service

832616781fa644bc2c243aec86a5ef0ee3560578
[bytom/vapor.git] / database / account_store.go
1 package database
2
3 import (
4         "encoding/json"
5         "strings"
6
7         log "github.com/sirupsen/logrus"
8         acc "github.com/vapor/account"
9         "github.com/vapor/common"
10         "github.com/vapor/crypto/ed25519/chainkd"
11         dbm "github.com/vapor/database/leveldb"
12         "github.com/vapor/protocol/bc"
13 )
14
15 // AccountStore satisfies AccountStorer interface.
16 type AccountStore struct {
17         accountDB dbm.DB
18         batch     dbm.Batch
19 }
20
21 // NewAccountStore create new AccountStore.
22 func NewAccountStore(db dbm.DB) *AccountStore {
23         return &AccountStore{
24                 accountDB: db,
25                 batch:     nil,
26         }
27 }
28
29 // InitBatch initial batch
30 func (store *AccountStore) InitBatch() {
31         if store.batch == nil {
32                 store.batch = store.accountDB.NewBatch()
33         }
34 }
35
36 // CommitBatch commit batch
37 func (store *AccountStore) CommitBatch() {
38         if store.batch != nil {
39                 store.batch.Write()
40                 store.batch = nil
41         }
42 }
43
44 // SetAccount set account account ID, account alias and raw account.
45 func (store *AccountStore) SetAccount(account *acc.Account, updateIndex bool) error {
46         rawAccount, err := json.Marshal(account)
47         if err != nil {
48                 return acc.ErrMarshalAccount
49         }
50
51         batch := store.accountDB.NewBatch()
52         if store.batch != nil {
53                 batch = store.batch
54         }
55         batch.Set(AccountIDKey(account.ID), rawAccount)
56         batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
57         if updateIndex {
58                 batch.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
59         }
60
61         if store.batch == nil {
62                 batch.Write()
63         }
64         return nil
65 }
66
67 // DeleteAccount set account account ID, account alias and raw account.
68 func (store *AccountStore) DeleteAccount(accountID, accountAlias string) {
69         batch := store.accountDB.NewBatch()
70         if store.batch != nil {
71                 batch = store.batch
72         }
73         batch.Delete(AccountIDKey(accountID))
74         batch.Delete(accountAliasKey(accountAlias))
75         if store.batch == nil {
76                 batch.Write()
77         }
78 }
79
80 // GetAccountIDByAccountAlias get account ID by account alias
81 func (store *AccountStore) GetAccountIDByAccountAlias(accountAlias string) string {
82         accountID := store.accountDB.Get(accountAliasKey(accountAlias))
83         return string(accountID)
84 }
85
86 // GetAccountByAccountID get account by accountID
87 func (store *AccountStore) GetAccountByAccountID(accountID string) (*acc.Account, error) {
88         account := new(acc.Account)
89         rawAccount := store.accountDB.Get(AccountIDKey(accountID))
90         if rawAccount == nil {
91                 return nil, acc.ErrFindAccount
92         }
93         if err := json.Unmarshal(rawAccount, account); err != nil {
94                 return nil, err
95         }
96         return account, nil
97 }
98
99 // GetAccountIndex get account index by account xpubs
100 func (store *AccountStore) GetAccountIndex(xpubs []chainkd.XPub) uint64 {
101         currentIndex := uint64(0)
102         if rawIndexBytes := store.accountDB.Get(accountIndexKey(xpubs)); rawIndexBytes != nil {
103                 currentIndex = common.BytesToUnit64(rawIndexBytes)
104         }
105         return currentIndex
106 }
107
108 // DeleteAccountByAccountAlias delete account by account alias
109 func (store *AccountStore) DeleteAccountByAccountAlias(accountAlias string) {
110         if store.batch == nil {
111                 store.accountDB.Delete(accountAliasKey(accountAlias))
112         } else {
113                 store.batch.Delete(accountAliasKey(accountAlias))
114         }
115 }
116
117 // DeleteAccountByAccountID delete account by accountID
118 func (store *AccountStore) DeleteAccountByAccountID(accountID string) {
119         if store.batch == nil {
120                 store.accountDB.Delete(AccountIDKey(accountID))
121         } else {
122                 store.batch.Delete(AccountIDKey(accountID))
123         }
124 }
125
126 // DeleteRawProgram delete raw control program by hash
127 func (store *AccountStore) DeleteRawProgram(hash common.Hash) {
128         if store.batch == nil {
129                 store.accountDB.Delete(ContractKey(hash))
130         } else {
131                 store.batch.Delete(ContractKey(hash))
132         }
133 }
134
135 // DeleteBip44ContractIndex delete bip44 contract index by accountID
136 func (store *AccountStore) DeleteBip44ContractIndex(accountID string) {
137         batch := store.accountDB.NewBatch()
138         if store.batch != nil {
139                 batch = store.batch
140         }
141         batch.Delete(Bip44ContractIndexKey(accountID, false))
142         batch.Delete(Bip44ContractIndexKey(accountID, true))
143         if store.batch == nil {
144                 batch.Write()
145         }
146 }
147
148 // DeleteContractIndex delete contract index by accountID
149 func (store *AccountStore) DeleteContractIndex(accountID string) {
150         if store.batch == nil {
151                 store.accountDB.Delete(contractIndexKey(accountID))
152         } else {
153                 store.batch.Delete(contractIndexKey(accountID))
154         }
155 }
156
157 // GetContractIndex get contract index
158 func (store *AccountStore) GetContractIndex(accountID string) uint64 {
159         index := uint64(0)
160         if rawIndexBytes := store.accountDB.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
161                 index = common.BytesToUnit64(rawIndexBytes)
162         }
163         return index
164 }
165
166 // DeleteStandardUTXO delete utxo by outpu id
167 func (store *AccountStore) DeleteStandardUTXO(outputID bc.Hash) {
168         if store.batch == nil {
169                 store.accountDB.Delete(StandardUTXOKey(outputID))
170         } else {
171                 store.batch.Delete(StandardUTXOKey(outputID))
172         }
173 }
174
175 // DeleteAccountUTXOs delete account utxos by accountID
176 func (store *AccountStore) DeleteAccountUTXOs(accountID string) error {
177         batch := store.accountDB.NewBatch()
178         if store.batch != nil {
179                 batch = store.batch
180         }
181
182         accountUtxoIter := store.accountDB.IteratorPrefix([]byte(UTXOPrefix))
183         defer accountUtxoIter.Release()
184
185         for accountUtxoIter.Next() {
186                 accountUtxo := &acc.UTXO{}
187                 if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
188                         return err
189                 }
190                 if accountID == accountUtxo.AccountID {
191                         batch.Delete(StandardUTXOKey(accountUtxo.OutputID))
192                 }
193         }
194
195         if store.batch == nil {
196                 batch.Write()
197         }
198         return nil
199 }
200
201 // GetCoinbaseArbitrary get coinbase arbitrary
202 func (store *AccountStore) GetCoinbaseArbitrary() []byte {
203         return store.accountDB.Get([]byte(CoinbaseAbKey))
204 }
205
206 // SetCoinbaseArbitrary set coinbase arbitrary
207 func (store *AccountStore) SetCoinbaseArbitrary(arbitrary []byte) {
208         if store.batch == nil {
209                 store.accountDB.Set([]byte(CoinbaseAbKey), arbitrary)
210         } else {
211                 store.batch.Set([]byte(CoinbaseAbKey), arbitrary)
212         }
213 }
214
215 // GetMiningAddress get mining address
216 func (store *AccountStore) GetMiningAddress() (*acc.CtrlProgram, error) {
217         rawCP := store.accountDB.Get([]byte(MiningAddressKey))
218         if rawCP == nil {
219                 return nil, acc.ErrFindMiningAddress
220         }
221         cp := new(acc.CtrlProgram)
222         if err := json.Unmarshal(rawCP, cp); err != nil {
223                 return nil, err
224         }
225
226         return cp, nil
227 }
228
229 // SetMiningAddress set mining address
230 func (store *AccountStore) SetMiningAddress(program *acc.CtrlProgram) error {
231         rawProgram, err := json.Marshal(program)
232         if err != nil {
233                 return err
234         }
235
236         if store.batch == nil {
237                 store.accountDB.Set([]byte(MiningAddressKey), rawProgram)
238         } else {
239                 store.batch.Set([]byte(MiningAddressKey), rawProgram)
240         }
241         return nil
242 }
243
244 // GetBip44ContractIndex get bip44 contract index
245 func (store *AccountStore) GetBip44ContractIndex(accountID string, change bool) uint64 {
246         index := uint64(0)
247         if rawIndexBytes := store.accountDB.Get(Bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
248                 index = common.BytesToUnit64(rawIndexBytes)
249         }
250         return index
251 }
252
253 // GetControlProgram get control program
254 func (store *AccountStore) GetControlProgram(hash common.Hash) (*acc.CtrlProgram, error) {
255         rawProgram := store.accountDB.Get(ContractKey(hash))
256         if rawProgram == nil {
257                 return nil, acc.ErrFindCtrlProgram
258         }
259
260         cp := new(acc.CtrlProgram)
261         if err := json.Unmarshal(rawProgram, cp); err != nil {
262                 return nil, err
263         }
264         return cp, nil
265 }
266
267 // GetAccounts get all accounts which name prfix is id.
268 func (store *AccountStore) GetAccounts(id string) ([]*acc.Account, error) {
269         accounts := []*acc.Account{}
270         accountIter := store.accountDB.IteratorPrefix(AccountIDKey(strings.TrimSpace(id)))
271         defer accountIter.Release()
272
273         for accountIter.Next() {
274                 account := new(acc.Account)
275                 if err := json.Unmarshal(accountIter.Value(), &account); err != nil {
276                         return nil, err
277                 }
278                 accounts = append(accounts, account)
279         }
280         return accounts, nil
281 }
282
283 // GetControlPrograms get all local control programs
284 func (store *AccountStore) GetControlPrograms() ([]*acc.CtrlProgram, error) {
285         cps := []*acc.CtrlProgram{}
286         cpIter := store.accountDB.IteratorPrefix([]byte(ContractPrefix))
287         defer cpIter.Release()
288
289         for cpIter.Next() {
290                 cp := new(acc.CtrlProgram)
291                 if err := json.Unmarshal(cpIter.Value(), cp); err != nil {
292                         return nil, err
293                 }
294                 cps = append(cps, cp)
295         }
296         return cps, nil
297 }
298
299 // SetControlProgram set raw program
300 func (store *AccountStore) SetControlProgram(hash common.Hash, program *acc.CtrlProgram) error {
301         accountCP, err := json.Marshal(program)
302         if err != nil {
303                 return err
304         }
305         if store.batch == nil {
306                 store.accountDB.Set(ContractKey(hash), accountCP)
307         } else {
308                 store.batch.Set(ContractKey(hash), accountCP)
309         }
310         return nil
311 }
312
313 // SetContractIndex set contract index
314 func (store *AccountStore) SetContractIndex(accountID string, index uint64) {
315         if store.batch == nil {
316                 store.accountDB.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
317         } else {
318                 store.batch.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
319         }
320 }
321
322 // SetBip44ContractIndex set contract index
323 func (store *AccountStore) SetBip44ContractIndex(accountID string, change bool, index uint64) {
324         if store.batch == nil {
325                 store.accountDB.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
326         } else {
327                 store.batch.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
328         }
329 }
330
331 // GetUTXOs get utxos by accountID
332 func (store *AccountStore) GetUTXOs() []*acc.UTXO {
333         utxoIter := store.accountDB.IteratorPrefix([]byte(UTXOPrefix))
334         defer utxoIter.Release()
335
336         utxos := []*acc.UTXO{}
337         for utxoIter.Next() {
338                 utxo := new(acc.UTXO)
339                 if err := json.Unmarshal(utxoIter.Value(), utxo); err != nil {
340                         log.WithFields(log.Fields{"module": logModule, "err": err}).Error("utxoKeeper findUtxos fail on unmarshal utxo")
341                         continue
342                 }
343                 utxos = append(utxos, utxo)
344         }
345         return utxos
346 }
347
348 // GetUTXO get standard utxo by id
349 func (store *AccountStore) GetUTXO(outid bc.Hash) (*acc.UTXO, error) {
350         u := new(acc.UTXO)
351         if data := store.accountDB.Get(StandardUTXOKey(outid)); data != nil {
352                 return u, json.Unmarshal(data, u)
353         }
354         if data := store.accountDB.Get(ContractUTXOKey(outid)); data != nil {
355                 return u, json.Unmarshal(data, u)
356         }
357         return nil, acc.ErrMatchUTXO
358 }
359
360 // SetStandardUTXO set standard utxo
361 func (store *AccountStore) SetStandardUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
362         data, err := json.Marshal(utxo)
363         if err != nil {
364                 return err
365         }
366         if store.batch == nil {
367                 store.accountDB.Set(StandardUTXOKey(outputID), data)
368         } else {
369                 store.batch.Set(StandardUTXOKey(outputID), data)
370         }
371         return nil
372 }