9 log "github.com/sirupsen/logrus"
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"
20 // AccountStore satisfies AccountStore interface.
21 type AccountStore struct {
26 // NewAccountStore create new AccountStore.
27 func NewAccountStore(db dbm.DB) *AccountStore {
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.")
39 store.batch = store.accountDB.NewBatch()
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.")
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 {
61 // delete account control program
62 cps, err := store.ListControlPrograms()
63 fmt.Println("len(cps):", len(cps))
68 for _, cp := range cps {
69 if cp.AccountID == account.ID {
70 sha3pool.Sum256(hash[:], cp.ControlProgram)
71 batch.Delete(ContractKey(bc.NewHash(hash)))
75 // delete bip44 contract index
76 batch.Delete(Bip44ContractIndexKey(account.ID, false))
77 batch.Delete(Bip44ContractIndexKey(account.ID, true))
79 // delete contract index
80 batch.Delete(contractIndexKey(account.ID))
83 batch.Delete(AccountIDKey(account.ID))
84 batch.Delete(accountAliasKey(account.Alias))
85 if store.batch == nil {
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 {
98 accountUtxoIter := store.accountDB.IteratorPrefix([]byte(UTXOPrefix))
99 defer accountUtxoIter.Release()
101 for accountUtxoIter.Next() {
102 accountUtxo := &acc.UTXO{}
103 if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
106 if accountID == accountUtxo.AccountID {
107 batch.Delete(StandardUTXOKey(accountUtxo.OutputID))
111 if store.batch == nil {
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))
122 store.batch.Delete(StandardUTXOKey(outputID))
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
132 return store.GetAccountByID(string(accountID))
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
141 account := new(acc.Account)
142 if err := json.Unmarshal(rawAccount, account); err != nil {
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)
157 // GetBip44ContractIndex get bip44 contract index
158 func (store *AccountStore) GetBip44ContractIndex(accountID string, change bool) uint64 {
160 if rawIndexBytes := store.accountDB.Get(Bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
161 index = common.BytesToUnit64(rawIndexBytes)
166 // GetCoinbaseArbitrary get coinbase arbitrary
167 func (store *AccountStore) GetCoinbaseArbitrary() []byte {
168 return store.accountDB.Get([]byte(CoinbaseAbKey))
171 // GetContractIndex get contract index
172 func (store *AccountStore) GetContractIndex(accountID string) uint64 {
174 if rawIndexBytes := store.accountDB.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
175 index = common.BytesToUnit64(rawIndexBytes)
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
186 cp := new(acc.CtrlProgram)
187 if err := json.Unmarshal(rawProgram, cp); err != nil {
193 // GetMiningAddress get mining address
194 func (store *AccountStore) GetMiningAddress() (*acc.CtrlProgram, error) {
195 rawCP := store.accountDB.Get([]byte(MiningAddressKey))
197 return nil, acc.ErrFindMiningAddress
199 cp := new(acc.CtrlProgram)
200 if err := json.Unmarshal(rawCP, cp); err != nil {
206 // GetUTXO get standard utxo by id
207 func (store *AccountStore) GetUTXO(outid bc.Hash) (*acc.UTXO, error) {
209 if data := store.accountDB.Get(StandardUTXOKey(outid)); data != nil {
210 return u, json.Unmarshal(data, u)
212 if data := store.accountDB.Get(ContractUTXOKey(outid)); data != nil {
213 return u, json.Unmarshal(data, u)
215 return nil, acc.ErrMatchUTXO
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()
224 for accountIter.Next() {
225 account := new(acc.Account)
226 if err := json.Unmarshal(accountIter.Value(), &account); err != nil {
229 accounts = append(accounts, account)
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()
242 cp := new(acc.CtrlProgram)
243 v := hex.EncodeToString(cpIter.Value())
245 if err := json.Unmarshal(cpIter.Value(), cp); err != nil {
248 cps = append(cps, cp)
253 // ListUTXOs get utxos by accountID
254 func (store *AccountStore) ListUTXOs() []*acc.UTXO {
255 utxoIter := store.accountDB.IteratorPrefix([]byte(UTXOPrefix))
256 defer utxoIter.Release()
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")
265 utxos = append(utxos, utxo)
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)
274 return acc.ErrMarshalAccount
277 batch := store.accountDB.NewBatch()
278 if store.batch != nil {
282 batch.Set(AccountIDKey(account.ID), rawAccount)
283 batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
285 if store.batch == nil {
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))
296 store.batch.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
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))
305 store.batch.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
309 // SetCoinbaseArbitrary set coinbase arbitrary
310 func (store *AccountStore) SetCoinbaseArbitrary(arbitrary []byte) {
311 if store.batch == nil {
312 store.accountDB.Set([]byte(CoinbaseAbKey), arbitrary)
314 store.batch.Set([]byte(CoinbaseAbKey), arbitrary)
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))
323 store.batch.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
327 // SetControlProgram set raw program
328 func (store *AccountStore) SetControlProgram(hash bc.Hash, program *acc.CtrlProgram) error {
329 accountCP, err := json.Marshal(program)
333 if store.batch == nil {
334 store.accountDB.Set(ContractKey(hash), accountCP)
336 store.batch.Set(ContractKey(hash), accountCP)
341 // SetMiningAddress set mining address
342 func (store *AccountStore) SetMiningAddress(program *acc.CtrlProgram) error {
343 rawProgram, err := json.Marshal(program)
348 if store.batch == nil {
349 store.accountDB.Set([]byte(MiningAddressKey), rawProgram)
351 store.batch.Set([]byte(MiningAddressKey), rawProgram)
356 // SetStandardUTXO set standard utxo
357 func (store *AccountStore) SetStandardUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
358 data, err := json.Marshal(utxo)
362 if store.batch == nil {
363 store.accountDB.Set(StandardUTXOKey(outputID), data)
365 store.batch.Set(StandardUTXOKey(outputID), data)