OSDN Git Service

update
[bytom/vapor.git] / database / account_store.go
1 package database
2
3 import (
4         "encoding/json"
5         "sort"
6         "strings"
7
8         acc "github.com/vapor/account"
9         "github.com/vapor/blockchain/signers"
10         "github.com/vapor/common"
11         "github.com/vapor/crypto/ed25519/chainkd"
12         "github.com/vapor/crypto/sha3pool"
13         dbm "github.com/vapor/database/leveldb"
14         "github.com/vapor/errors"
15         "github.com/vapor/protocol/bc"
16 )
17
18 const (
19         utxoPrefix byte = iota //UTXOPrefix is StandardUTXOKey prefix
20         contractPrefix
21         contractIndexPrefix
22         accountPrefix // AccountPrefix is account ID prefix
23         accountIndexPrefix
24 )
25
26 // leveldb key prefix
27 var (
28         accountStore        = []byte("AS:")
29         UTXOPrefix          = append(accountStore, utxoPrefix, colon)
30         ContractPrefix      = append(accountStore, contractPrefix, colon)
31         ContractIndexPrefix = append(accountStore, contractIndexPrefix, colon)
32         AccountPrefix       = append(accountStore, accountPrefix, colon) // AccountPrefix is account ID prefix
33         AccountIndexPrefix  = append(accountStore, accountIndexPrefix, colon)
34 )
35
36 func accountIndexKey(xpubs []chainkd.XPub) []byte {
37         var hash [32]byte
38         var xPubs []byte
39         cpy := append([]chainkd.XPub{}, xpubs[:]...)
40         sort.Sort(signers.SortKeys(cpy))
41         for _, xpub := range cpy {
42                 xPubs = append(xPubs, xpub[:]...)
43         }
44         sha3pool.Sum256(hash[:], xPubs)
45         return append(AccountIndexPrefix, hash[:]...)
46 }
47
48 func Bip44ContractIndexKey(accountID string, change bool) []byte {
49         key := append(ContractIndexPrefix, []byte(accountID)...)
50         if change {
51                 return append(key, 0x01)
52         }
53         return append(key, 0x00)
54 }
55
56 // ContractKey account control promgram store prefix
57 func ContractKey(hash bc.Hash) []byte {
58         return append(ContractPrefix, hash.Bytes()...)
59 }
60
61 // AccountIDKey account id store prefix
62 func AccountIDKey(accountID string) []byte {
63         return append(AccountPrefix, []byte(accountID)...)
64 }
65
66 // StandardUTXOKey makes an account unspent outputs key to store
67 func StandardUTXOKey(id bc.Hash) []byte {
68         return append(UTXOPrefix, id.Bytes()...)
69 }
70
71 // AccountStore satisfies AccountStore interface.
72 type AccountStore struct {
73         db    dbm.DB
74         batch dbm.Batch
75 }
76
77 // NewAccountStore create new AccountStore.
78 func NewAccountStore(db dbm.DB) *AccountStore {
79         return &AccountStore{
80                 db:    db,
81                 batch: nil,
82         }
83 }
84
85 // InitStore initial new account store
86 func (store *AccountStore) InitStore() acc.AccountStore {
87         newStore := NewAccountStore(store.db)
88         newStore.batch = newStore.db.NewBatch()
89         return newStore
90 }
91
92 // CommitBatch commit batch
93 func (store *AccountStore) CommitBatch() error {
94         if store.batch == nil {
95                 return errors.New("AccountStore commit fail, store batch is nil.")
96         }
97         store.batch.Write()
98         store.batch = nil
99         return nil
100 }
101
102 // DeleteAccount set account account ID, account alias and raw account.
103 func (store *AccountStore) DeleteAccount(account *acc.Account) error {
104         batch := store.db.NewBatch()
105         if store.batch != nil {
106                 batch = store.batch
107         }
108
109         // delete account utxos
110         store.deleteAccountUTXOs(account.ID, batch)
111
112         // delete account control program
113         if err := store.deleteAccountControlPrograms(account.ID, batch); err != nil {
114                 return err
115         }
116
117         // delete bip44 contract index
118         batch.Delete(Bip44ContractIndexKey(account.ID, false))
119         batch.Delete(Bip44ContractIndexKey(account.ID, true))
120
121         // delete contract index
122         batch.Delete(contractIndexKey(account.ID))
123
124         // delete account id
125         batch.Delete(AccountIDKey(account.ID))
126         batch.Delete(accountAliasKey(account.Alias))
127         if store.batch == nil {
128                 batch.Write()
129         }
130         return nil
131 }
132
133 // deleteAccountUTXOs delete account utxos by accountID
134 func (store *AccountStore) deleteAccountUTXOs(accountID string, batch dbm.Batch) error {
135         accountUtxoIter := store.db.IteratorPrefix(UTXOPrefix)
136         defer accountUtxoIter.Release()
137
138         for accountUtxoIter.Next() {
139                 accountUtxo := new(acc.UTXO)
140                 if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
141                         return err
142                 }
143
144                 if accountID == accountUtxo.AccountID {
145                         batch.Delete(StandardUTXOKey(accountUtxo.OutputID))
146                 }
147         }
148
149         return nil
150 }
151
152 // deleteAccountControlPrograms deletes account control program
153 func (store *AccountStore) deleteAccountControlPrograms(accountID string, batch dbm.Batch) error {
154         cps, err := store.ListControlPrograms()
155         if err != nil {
156                 return err
157         }
158
159         var hash [32]byte
160         for _, cp := range cps {
161                 if cp.AccountID == accountID {
162                         sha3pool.Sum256(hash[:], cp.ControlProgram)
163                         batch.Delete(ContractKey(bc.NewHash(hash)))
164                 }
165         }
166         return nil
167 }
168
169 // DeleteStandardUTXO delete utxo by outpu id
170 func (store *AccountStore) DeleteStandardUTXO(outputID bc.Hash) {
171         if store.batch == nil {
172                 store.db.Delete(StandardUTXOKey(outputID))
173         } else {
174                 store.batch.Delete(StandardUTXOKey(outputID))
175         }
176 }
177
178 // GetAccountByAlias get account by account alias
179 func (store *AccountStore) GetAccountByAlias(accountAlias string) (*acc.Account, error) {
180         accountID := store.db.Get(accountAliasKey(accountAlias))
181         if accountID == nil {
182                 return nil, acc.ErrFindAccount
183         }
184         return store.GetAccountByID(string(accountID))
185 }
186
187 // GetAccountByID get account by accountID
188 func (store *AccountStore) GetAccountByID(accountID string) (*acc.Account, error) {
189         rawAccount := store.db.Get(AccountIDKey(accountID))
190         if rawAccount == nil {
191                 return nil, acc.ErrFindAccount
192         }
193
194         account := new(acc.Account)
195         if err := json.Unmarshal(rawAccount, account); err != nil {
196                 return nil, err
197         }
198
199         return account, nil
200 }
201
202 // GetAccountIndex get account index by account xpubs
203 func (store *AccountStore) GetAccountIndex(xpubs []chainkd.XPub) uint64 {
204         currentIndex := uint64(0)
205         if rawIndexBytes := store.db.Get(accountIndexKey(xpubs)); rawIndexBytes != nil {
206                 currentIndex = common.BytesToUnit64(rawIndexBytes)
207         }
208         return currentIndex
209 }
210
211 // GetBip44ContractIndex get bip44 contract index
212 func (store *AccountStore) GetBip44ContractIndex(accountID string, change bool) uint64 {
213         index := uint64(0)
214         if rawIndexBytes := store.db.Get(Bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
215                 index = common.BytesToUnit64(rawIndexBytes)
216         }
217         return index
218 }
219
220 // GetCoinbaseArbitrary get coinbase arbitrary
221 func (store *AccountStore) GetCoinbaseArbitrary() []byte {
222         return store.db.Get(CoinbaseAbKey)
223 }
224
225 // GetContractIndex get contract index
226 func (store *AccountStore) GetContractIndex(accountID string) uint64 {
227         index := uint64(0)
228         if rawIndexBytes := store.db.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
229                 index = common.BytesToUnit64(rawIndexBytes)
230         }
231         return index
232 }
233
234 // GetControlProgram get control program
235 func (store *AccountStore) GetControlProgram(hash bc.Hash) (*acc.CtrlProgram, error) {
236         rawProgram := store.db.Get(ContractKey(hash))
237         if rawProgram == nil {
238                 return nil, acc.ErrFindCtrlProgram
239         }
240
241         cp := new(acc.CtrlProgram)
242         if err := json.Unmarshal(rawProgram, cp); err != nil {
243                 return nil, err
244         }
245
246         return cp, nil
247 }
248
249 // GetMiningAddress get mining address
250 func (store *AccountStore) GetMiningAddress() (*acc.CtrlProgram, error) {
251         rawCP := store.db.Get(MiningAddressKey)
252         if rawCP == nil {
253                 return nil, acc.ErrFindMiningAddress
254         }
255
256         cp := new(acc.CtrlProgram)
257         if err := json.Unmarshal(rawCP, cp); err != nil {
258                 return nil, err
259         }
260
261         return cp, nil
262 }
263
264 // GetUTXO get standard utxo by id
265 func (store *AccountStore) GetUTXO(outid bc.Hash) (*acc.UTXO, error) {
266         u := new(acc.UTXO)
267         if data := store.db.Get(StandardUTXOKey(outid)); data != nil {
268                 return u, json.Unmarshal(data, u)
269         }
270
271         if data := store.db.Get(ContractUTXOKey(outid)); data != nil {
272                 return u, json.Unmarshal(data, u)
273         }
274
275         return nil, acc.ErrMatchUTXO
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.db.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
290                 accounts = append(accounts, account)
291         }
292         return accounts, nil
293 }
294
295 // ListControlPrograms get all local control programs
296 func (store *AccountStore) ListControlPrograms() ([]*acc.CtrlProgram, error) {
297         cps := []*acc.CtrlProgram{}
298         cpIter := store.db.IteratorPrefix(ContractPrefix)
299         defer cpIter.Release()
300
301         for cpIter.Next() {
302                 cp := new(acc.CtrlProgram)
303                 if err := json.Unmarshal(cpIter.Value(), cp); err != nil {
304                         return nil, err
305                 }
306
307                 cps = append(cps, cp)
308         }
309         return cps, nil
310 }
311
312 // ListUTXOs get utxos by accountID
313 func (store *AccountStore) ListUTXOs() ([]*acc.UTXO, error) {
314         utxoIter := store.db.IteratorPrefix(UTXOPrefix)
315         defer utxoIter.Release()
316
317         utxos := []*acc.UTXO{}
318         for utxoIter.Next() {
319                 utxo := new(acc.UTXO)
320                 if err := json.Unmarshal(utxoIter.Value(), utxo); err != nil {
321                         return nil, err
322                 }
323
324                 utxos = append(utxos, utxo)
325         }
326         return utxos, nil
327 }
328
329 // SetAccount set account account ID, account alias and raw account.
330 func (store *AccountStore) SetAccount(account *acc.Account) error {
331         rawAccount, err := json.Marshal(account)
332         if err != nil {
333                 return acc.ErrMarshalAccount
334         }
335
336         batch := store.db.NewBatch()
337         if store.batch != nil {
338                 batch = store.batch
339         }
340
341         batch.Set(AccountIDKey(account.ID), rawAccount)
342         batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
343
344         if store.batch == nil {
345                 batch.Write()
346         }
347         return nil
348 }
349
350 // SetAccountIndex update account index
351 func (store *AccountStore) SetAccountIndex(account *acc.Account) {
352         currentIndex := store.GetAccountIndex(account.XPubs)
353         if account.KeyIndex > currentIndex {
354                 if store.batch == nil {
355                         store.db.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
356                 } else {
357                         store.batch.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
358                 }
359         }
360 }
361
362 // SetBip44ContractIndex set contract index
363 func (store *AccountStore) SetBip44ContractIndex(accountID string, change bool, index uint64) {
364         if store.batch == nil {
365                 store.db.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
366         } else {
367                 store.batch.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
368         }
369 }
370
371 // SetCoinbaseArbitrary set coinbase arbitrary
372 func (store *AccountStore) SetCoinbaseArbitrary(arbitrary []byte) {
373         if store.batch == nil {
374                 store.db.Set(CoinbaseAbKey, arbitrary)
375         } else {
376                 store.batch.Set(CoinbaseAbKey, arbitrary)
377         }
378 }
379
380 // SetContractIndex set contract index
381 func (store *AccountStore) SetContractIndex(accountID string, index uint64) {
382         if store.batch == nil {
383                 store.db.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
384         } else {
385                 store.batch.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
386         }
387 }
388
389 // SetControlProgram set raw program
390 func (store *AccountStore) SetControlProgram(hash bc.Hash, program *acc.CtrlProgram) error {
391         accountCP, err := json.Marshal(program)
392         if err != nil {
393                 return err
394         }
395         if store.batch == nil {
396                 store.db.Set(ContractKey(hash), accountCP)
397         } else {
398                 store.batch.Set(ContractKey(hash), accountCP)
399         }
400         return nil
401 }
402
403 // SetMiningAddress set mining address
404 func (store *AccountStore) SetMiningAddress(program *acc.CtrlProgram) error {
405         rawProgram, err := json.Marshal(program)
406         if err != nil {
407                 return err
408         }
409
410         if store.batch == nil {
411                 store.db.Set(MiningAddressKey, rawProgram)
412         } else {
413                 store.batch.Set(MiningAddressKey, rawProgram)
414         }
415         return nil
416 }
417
418 // SetStandardUTXO set standard utxo
419 func (store *AccountStore) SetStandardUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
420         data, err := json.Marshal(utxo)
421         if err != nil {
422                 return err
423         }
424
425         if store.batch == nil {
426                 store.db.Set(StandardUTXOKey(outputID), data)
427         } else {
428                 store.batch.Set(StandardUTXOKey(outputID), data)
429         }
430         return nil
431 }