OSDN Git Service

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