OSDN Git Service

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