OSDN Git Service

update listutxos
[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) 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
56         batch.Set(AccountIDKey(account.ID), rawAccount)
57         batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
58
59         if store.batch == nil {
60                 batch.Write()
61         }
62         return nil
63 }
64
65 // SetAccountIndex set account account ID, account alias and raw account.
66 func (store *AccountStore) SetAccountIndex(account *acc.Account) error {
67         rawAccount, err := json.Marshal(account)
68         if err != nil {
69                 return acc.ErrMarshalAccount
70         }
71
72         batch := store.accountDB.NewBatch()
73         if store.batch != nil {
74                 batch = store.batch
75         }
76
77         batch.Set(AccountIDKey(account.ID), rawAccount)
78         batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
79         batch.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
80
81         if store.batch == nil {
82                 batch.Write()
83         }
84         return nil
85 }
86
87 // DeleteAccount set account account ID, account alias and raw account.
88 func (store *AccountStore) DeleteAccount(account *acc.Account) {
89         batch := store.accountDB.NewBatch()
90         if store.batch != nil {
91                 batch = store.batch
92         }
93         batch.Delete(AccountIDKey(account.ID))
94         batch.Delete(accountAliasKey(account.Alias))
95         if store.batch == nil {
96                 batch.Write()
97         }
98 }
99
100 // GetAccountIDByAlias get account ID by account alias
101 func (store *AccountStore) GetAccountIDByAlias(accountAlias string) string {
102         accountID := store.accountDB.Get(accountAliasKey(accountAlias))
103         return string(accountID)
104 }
105
106 // GetAccountByID get account by accountID
107 func (store *AccountStore) GetAccountByID(accountID string) (*acc.Account, error) {
108         account := new(acc.Account)
109         rawAccount := store.accountDB.Get(AccountIDKey(accountID))
110         if rawAccount == nil {
111                 return nil, acc.ErrFindAccount
112         }
113         if err := json.Unmarshal(rawAccount, account); err != nil {
114                 return nil, err
115         }
116         return account, nil
117 }
118
119 // GetAccountIndex get account index by account xpubs
120 func (store *AccountStore) GetAccountIndex(xpubs []chainkd.XPub) uint64 {
121         currentIndex := uint64(0)
122         if rawIndexBytes := store.accountDB.Get(accountIndexKey(xpubs)); rawIndexBytes != nil {
123                 currentIndex = common.BytesToUnit64(rawIndexBytes)
124         }
125         return currentIndex
126 }
127
128 // DeleteAccountByAlias delete account by account alias
129 func (store *AccountStore) DeleteAccountByAlias(accountAlias string) {
130         if store.batch == nil {
131                 store.accountDB.Delete(accountAliasKey(accountAlias))
132         } else {
133                 store.batch.Delete(accountAliasKey(accountAlias))
134         }
135 }
136
137 // DeleteControlProgram delete raw control program by hash
138 func (store *AccountStore) DeleteControlProgram(hash common.Hash) {
139         if store.batch == nil {
140                 store.accountDB.Delete(ContractKey(hash))
141         } else {
142                 store.batch.Delete(ContractKey(hash))
143         }
144 }
145
146 // DeleteBip44ContractIndex delete bip44 contract index by accountID
147 func (store *AccountStore) DeleteBip44ContractIndex(accountID string) {
148         batch := store.accountDB.NewBatch()
149         if store.batch != nil {
150                 batch = store.batch
151         }
152         batch.Delete(Bip44ContractIndexKey(accountID, false))
153         batch.Delete(Bip44ContractIndexKey(accountID, true))
154         if store.batch == nil {
155                 batch.Write()
156         }
157 }
158
159 // DeleteContractIndex delete contract index by accountID
160 func (store *AccountStore) DeleteContractIndex(accountID string) {
161         if store.batch == nil {
162                 store.accountDB.Delete(contractIndexKey(accountID))
163         } else {
164                 store.batch.Delete(contractIndexKey(accountID))
165         }
166 }
167
168 // GetContractIndex get contract index
169 func (store *AccountStore) GetContractIndex(accountID string) uint64 {
170         index := uint64(0)
171         if rawIndexBytes := store.accountDB.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
172                 index = common.BytesToUnit64(rawIndexBytes)
173         }
174         return index
175 }
176
177 // DeleteStandardUTXO delete utxo by outpu id
178 func (store *AccountStore) DeleteStandardUTXO(outputID bc.Hash) {
179         if store.batch == nil {
180                 store.accountDB.Delete(StandardUTXOKey(outputID))
181         } else {
182                 store.batch.Delete(StandardUTXOKey(outputID))
183         }
184 }
185
186 // DeleteAccountUTXOs delete account utxos by accountID
187 func (store *AccountStore) DeleteAccountUTXOs(accountID string) error {
188         batch := store.accountDB.NewBatch()
189         if store.batch != nil {
190                 batch = store.batch
191         }
192
193         accountUtxoIter := store.accountDB.IteratorPrefix([]byte(UTXOPrefix))
194         defer accountUtxoIter.Release()
195
196         for accountUtxoIter.Next() {
197                 accountUtxo := &acc.UTXO{}
198                 if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
199                         return err
200                 }
201                 if accountID == accountUtxo.AccountID {
202                         batch.Delete(StandardUTXOKey(accountUtxo.OutputID))
203                 }
204         }
205
206         if store.batch == nil {
207                 batch.Write()
208         }
209         return nil
210 }
211
212 // GetCoinbaseArbitrary get coinbase arbitrary
213 func (store *AccountStore) GetCoinbaseArbitrary() []byte {
214         return store.accountDB.Get([]byte(CoinbaseAbKey))
215 }
216
217 // SetCoinbaseArbitrary set coinbase arbitrary
218 func (store *AccountStore) SetCoinbaseArbitrary(arbitrary []byte) {
219         if store.batch == nil {
220                 store.accountDB.Set([]byte(CoinbaseAbKey), arbitrary)
221         } else {
222                 store.batch.Set([]byte(CoinbaseAbKey), arbitrary)
223         }
224 }
225
226 // GetMiningAddress get mining address
227 func (store *AccountStore) GetMiningAddress() (*acc.CtrlProgram, error) {
228         rawCP := store.accountDB.Get([]byte(MiningAddressKey))
229         if rawCP == nil {
230                 return nil, acc.ErrFindMiningAddress
231         }
232         cp := new(acc.CtrlProgram)
233         if err := json.Unmarshal(rawCP, cp); err != nil {
234                 return nil, err
235         }
236
237         return cp, nil
238 }
239
240 // SetMiningAddress set mining address
241 func (store *AccountStore) SetMiningAddress(program *acc.CtrlProgram) error {
242         rawProgram, err := json.Marshal(program)
243         if err != nil {
244                 return err
245         }
246
247         if store.batch == nil {
248                 store.accountDB.Set([]byte(MiningAddressKey), rawProgram)
249         } else {
250                 store.batch.Set([]byte(MiningAddressKey), rawProgram)
251         }
252         return nil
253 }
254
255 // GetBip44ContractIndex get bip44 contract index
256 func (store *AccountStore) GetBip44ContractIndex(accountID string, change bool) uint64 {
257         index := uint64(0)
258         if rawIndexBytes := store.accountDB.Get(Bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
259                 index = common.BytesToUnit64(rawIndexBytes)
260         }
261         return index
262 }
263
264 // GetControlProgram get control program
265 func (store *AccountStore) GetControlProgram(hash common.Hash) (*acc.CtrlProgram, error) {
266         rawProgram := store.accountDB.Get(ContractKey(hash))
267         if rawProgram == nil {
268                 return nil, acc.ErrFindCtrlProgram
269         }
270
271         cp := new(acc.CtrlProgram)
272         if err := json.Unmarshal(rawProgram, cp); err != nil {
273                 return nil, err
274         }
275         return cp, nil
276 }
277
278 // ListAccounts get all accounts which name prfix is id.
279 func (store *AccountStore) ListAccounts(id string) ([]*acc.Account, error) {
280         accounts := []*acc.Account{}
281         accountIter := store.accountDB.IteratorPrefix(AccountIDKey(strings.TrimSpace(id)))
282         defer accountIter.Release()
283
284         for accountIter.Next() {
285                 account := new(acc.Account)
286                 if err := json.Unmarshal(accountIter.Value(), &account); err != nil {
287                         return nil, err
288                 }
289                 accounts = append(accounts, account)
290         }
291         return accounts, nil
292 }
293
294 // ListControlPrograms get all local control programs
295 func (store *AccountStore) ListControlPrograms() ([]*acc.CtrlProgram, error) {
296         cps := []*acc.CtrlProgram{}
297         cpIter := store.accountDB.IteratorPrefix([]byte(ContractPrefix))
298         defer cpIter.Release()
299
300         for cpIter.Next() {
301                 cp := new(acc.CtrlProgram)
302                 if err := json.Unmarshal(cpIter.Value(), cp); err != nil {
303                         return nil, err
304                 }
305                 cps = append(cps, cp)
306         }
307         return cps, nil
308 }
309
310 // SetControlProgram set raw program
311 func (store *AccountStore) SetControlProgram(hash common.Hash, program *acc.CtrlProgram) error {
312         accountCP, err := json.Marshal(program)
313         if err != nil {
314                 return err
315         }
316         if store.batch == nil {
317                 store.accountDB.Set(ContractKey(hash), accountCP)
318         } else {
319                 store.batch.Set(ContractKey(hash), accountCP)
320         }
321         return nil
322 }
323
324 // SetContractIndex set contract index
325 func (store *AccountStore) SetContractIndex(accountID string, index uint64) {
326         if store.batch == nil {
327                 store.accountDB.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
328         } else {
329                 store.batch.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
330         }
331 }
332
333 // SetBip44ContractIndex set contract index
334 func (store *AccountStore) SetBip44ContractIndex(accountID string, change bool, index uint64) {
335         if store.batch == nil {
336                 store.accountDB.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
337         } else {
338                 store.batch.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
339         }
340 }
341
342 // ListUTXOs get utxos by accountID
343 func (store *AccountStore) ListUTXOs() []*acc.UTXO {
344         utxoIter := store.accountDB.IteratorPrefix([]byte(UTXOPrefix))
345         defer utxoIter.Release()
346
347         utxos := []*acc.UTXO{}
348         for utxoIter.Next() {
349                 utxo := new(acc.UTXO)
350                 if err := json.Unmarshal(utxoIter.Value(), utxo); err != nil {
351                         log.WithFields(log.Fields{"module": logModule, "err": err}).Error("utxoKeeper findUtxos fail on unmarshal utxo")
352                         continue
353                 }
354                 utxos = append(utxos, utxo)
355         }
356         return utxos
357 }
358
359 // GetUTXO get standard utxo by id
360 func (store *AccountStore) GetUTXO(outid bc.Hash) (*acc.UTXO, error) {
361         u := new(acc.UTXO)
362         if data := store.accountDB.Get(StandardUTXOKey(outid)); data != nil {
363                 return u, json.Unmarshal(data, u)
364         }
365         if data := store.accountDB.Get(ContractUTXOKey(outid)); data != nil {
366                 return u, json.Unmarshal(data, u)
367         }
368         return nil, acc.ErrMatchUTXO
369 }
370
371 // SetStandardUTXO set standard utxo
372 func (store *AccountStore) SetStandardUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
373         data, err := json.Marshal(utxo)
374         if err != nil {
375                 return err
376         }
377         if store.batch == nil {
378                 store.accountDB.Set(StandardUTXOKey(outputID), data)
379         } else {
380                 store.batch.Set(StandardUTXOKey(outputID), data)
381         }
382         return nil
383 }