OSDN Git Service

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