8 log "github.com/sirupsen/logrus"
9 acc "github.com/vapor/account"
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"
18 // AccountStore satisfies AccountStorer interface.
19 type AccountStore struct {
24 // NewAccountStore create new AccountStore.
25 func NewAccountStore(db dbm.DB) *AccountStore {
32 // InitBatch initial batch
33 func (store *AccountStore) InitBatch() error {
34 if store.batch != nil {
35 return errors.New("AccountStore initail fail, store batch is not nil.")
37 store.batch = store.accountDB.NewBatch()
41 // CommitBatch commit batch
42 func (store *AccountStore) CommitBatch() error {
43 if store.batch == nil {
44 return errors.New("AccountStore commit fail, store batch is nil.")
51 // DeleteAccount set account account ID, account alias and raw account.
52 func (store *AccountStore) DeleteAccount(account *acc.Account) error {
53 store.DeleteAccountUTXOs(account.ID)
54 batch := store.accountDB.NewBatch()
55 if store.batch != nil {
59 // delete account control program
60 cps, err := store.ListControlPrograms()
65 for _, cp := range cps {
66 if cp.AccountID == account.ID {
67 sha3pool.Sum256(hash[:], cp.ControlProgram)
68 batch.Delete(ContractKey(bc.NewHash(hash)))
72 // delete bip44 contract index
73 batch.Delete(Bip44ContractIndexKey(account.ID, false))
74 batch.Delete(Bip44ContractIndexKey(account.ID, true))
76 // delete contract index
77 batch.Delete(contractIndexKey(account.ID))
80 batch.Delete(AccountIDKey(account.ID))
81 batch.Delete(accountAliasKey(account.Alias))
82 if store.batch == nil {
88 // DeleteAccountUTXOs delete account utxos by accountID
89 func (store *AccountStore) DeleteAccountUTXOs(accountID string) error {
90 batch := store.accountDB.NewBatch()
91 if store.batch != nil {
95 accountUtxoIter := store.accountDB.IteratorPrefix([]byte(UTXOPrefix))
96 defer accountUtxoIter.Release()
98 for accountUtxoIter.Next() {
99 accountUtxo := &acc.UTXO{}
100 if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
103 if accountID == accountUtxo.AccountID {
104 batch.Delete(StandardUTXOKey(accountUtxo.OutputID))
108 if store.batch == nil {
114 // DeleteStandardUTXO delete utxo by outpu id
115 func (store *AccountStore) DeleteStandardUTXO(outputID bc.Hash) {
116 if store.batch == nil {
117 store.accountDB.Delete(StandardUTXOKey(outputID))
119 store.batch.Delete(StandardUTXOKey(outputID))
123 // GetAccountByAlias get account by account alias
124 func (store *AccountStore) GetAccountByAlias(accountAlias string) (*acc.Account, error) {
125 accountID := store.accountDB.Get(accountAliasKey(accountAlias))
126 if accountID == nil {
127 return nil, acc.ErrFindAccount
129 return store.GetAccountByID(string(accountID))
132 // GetAccountByID get account by accountID
133 func (store *AccountStore) GetAccountByID(accountID string) (*acc.Account, error) {
134 rawAccount := store.accountDB.Get(AccountIDKey(accountID))
135 if rawAccount == nil {
136 return nil, acc.ErrFindAccount
138 account := new(acc.Account)
139 if err := json.Unmarshal(rawAccount, account); err != nil {
145 // GetAccountIndex get account index by account xpubs
146 func (store *AccountStore) GetAccountIndex(xpubs []chainkd.XPub) uint64 {
147 currentIndex := uint64(0)
148 if rawIndexBytes := store.accountDB.Get(accountIndexKey(xpubs)); rawIndexBytes != nil {
149 currentIndex = common.BytesToUnit64(rawIndexBytes)
154 // GetBip44ContractIndex get bip44 contract index
155 func (store *AccountStore) GetBip44ContractIndex(accountID string, change bool) uint64 {
157 if rawIndexBytes := store.accountDB.Get(Bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
158 index = common.BytesToUnit64(rawIndexBytes)
163 // GetCoinbaseArbitrary get coinbase arbitrary
164 func (store *AccountStore) GetCoinbaseArbitrary() []byte {
165 return store.accountDB.Get([]byte(CoinbaseAbKey))
168 // GetContractIndex get contract index
169 func (store *AccountStore) GetContractIndex(accountID string) uint64 {
171 if rawIndexBytes := store.accountDB.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
172 index = common.BytesToUnit64(rawIndexBytes)
177 // GetControlProgram get control program
178 func (store *AccountStore) GetControlProgram(hash bc.Hash) (*acc.CtrlProgram, error) {
179 rawProgram := store.accountDB.Get(ContractKey(hash))
180 if rawProgram == nil {
181 return nil, acc.ErrFindCtrlProgram
183 cp := new(acc.CtrlProgram)
184 if err := json.Unmarshal(rawProgram, cp); err != nil {
190 // GetMiningAddress get mining address
191 func (store *AccountStore) GetMiningAddress() (*acc.CtrlProgram, error) {
192 rawCP := store.accountDB.Get([]byte(MiningAddressKey))
194 return nil, acc.ErrFindMiningAddress
196 cp := new(acc.CtrlProgram)
197 if err := json.Unmarshal(rawCP, cp); err != nil {
203 // GetUTXO get standard utxo by id
204 func (store *AccountStore) GetUTXO(outid bc.Hash) (*acc.UTXO, error) {
206 if data := store.accountDB.Get(StandardUTXOKey(outid)); data != nil {
207 return u, json.Unmarshal(data, u)
209 if data := store.accountDB.Get(ContractUTXOKey(outid)); data != nil {
210 return u, json.Unmarshal(data, u)
212 return nil, acc.ErrMatchUTXO
215 // ListAccounts get all accounts which name prfix is id.
216 func (store *AccountStore) ListAccounts(id string) ([]*acc.Account, error) {
217 accounts := []*acc.Account{}
218 accountIter := store.accountDB.IteratorPrefix(AccountIDKey(strings.TrimSpace(id)))
219 defer accountIter.Release()
221 for accountIter.Next() {
222 account := new(acc.Account)
223 if err := json.Unmarshal(accountIter.Value(), &account); err != nil {
226 accounts = append(accounts, account)
231 // ListControlPrograms get all local control programs
232 func (store *AccountStore) ListControlPrograms() ([]*acc.CtrlProgram, error) {
233 cps := []*acc.CtrlProgram{}
234 cpIter := store.accountDB.IteratorPrefix([]byte(ContractPrefix))
235 defer cpIter.Release()
238 cp := new(acc.CtrlProgram)
239 fmt.Printf("cpiter value: %s, len: %v", cpIter.Value(), len(cpIter.Value()))
241 if err := json.Unmarshal(cpIter.Value(), cp); err != nil {
244 cps = append(cps, cp)
249 // ListUTXOs get utxos by accountID
250 func (store *AccountStore) ListUTXOs() []*acc.UTXO {
251 utxoIter := store.accountDB.IteratorPrefix([]byte(UTXOPrefix))
252 defer utxoIter.Release()
254 utxos := []*acc.UTXO{}
255 for utxoIter.Next() {
256 utxo := new(acc.UTXO)
257 if err := json.Unmarshal(utxoIter.Value(), utxo); err != nil {
258 log.WithFields(log.Fields{"module": logModule, "err": err}).Error("utxoKeeper findUtxos fail on unmarshal utxo")
261 utxos = append(utxos, utxo)
266 // SetAccount set account account ID, account alias and raw account.
267 func (store *AccountStore) SetAccount(account *acc.Account) error {
268 rawAccount, err := json.Marshal(account)
270 return acc.ErrMarshalAccount
273 batch := store.accountDB.NewBatch()
274 if store.batch != nil {
278 batch.Set(AccountIDKey(account.ID), rawAccount)
279 batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
281 if store.batch == nil {
287 // SetAccountIndex set account account ID, account alias and raw account.
288 func (store *AccountStore) SetAccountIndex(account *acc.Account) error {
289 rawAccount, err := json.Marshal(account)
291 return acc.ErrMarshalAccount
294 batch := store.accountDB.NewBatch()
295 if store.batch != nil {
299 batch.Set(AccountIDKey(account.ID), rawAccount)
300 batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
301 batch.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
303 if store.batch == nil {
309 // SetBip44ContractIndex set contract index
310 func (store *AccountStore) SetBip44ContractIndex(accountID string, change bool, index uint64) {
311 if store.batch == nil {
312 store.accountDB.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
314 store.batch.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
318 // SetCoinbaseArbitrary set coinbase arbitrary
319 func (store *AccountStore) SetCoinbaseArbitrary(arbitrary []byte) {
320 if store.batch == nil {
321 store.accountDB.Set([]byte(CoinbaseAbKey), arbitrary)
323 store.batch.Set([]byte(CoinbaseAbKey), arbitrary)
327 // SetContractIndex set contract index
328 func (store *AccountStore) SetContractIndex(accountID string, index uint64) {
329 if store.batch == nil {
330 store.accountDB.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
332 store.batch.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
336 // SetControlProgram set raw program
337 func (store *AccountStore) SetControlProgram(hash bc.Hash, program *acc.CtrlProgram) error {
338 accountCP, err := json.Marshal(program)
342 if store.batch == nil {
343 store.accountDB.Set(ContractKey(hash), accountCP)
345 store.batch.Set(ContractKey(hash), accountCP)
350 // SetMiningAddress set mining address
351 func (store *AccountStore) SetMiningAddress(program *acc.CtrlProgram) error {
352 rawProgram, err := json.Marshal(program)
357 if store.batch == nil {
358 store.accountDB.Set([]byte(MiningAddressKey), rawProgram)
360 store.batch.Set([]byte(MiningAddressKey), rawProgram)
365 // SetStandardUTXO set standard utxo
366 func (store *AccountStore) SetStandardUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
367 data, err := json.Marshal(utxo)
371 if store.batch == nil {
372 store.accountDB.Set(StandardUTXOKey(outputID), data)
374 store.batch.Set(StandardUTXOKey(outputID), data)