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"
19 // AccountStore satisfies AccountStore interface.
20 type AccountStore struct {
25 // NewAccountStore create new AccountStore.
26 func NewAccountStore(db dbm.DB) *AccountStore {
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.")
38 store.batch = store.accountDB.NewBatch()
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.")
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 {
60 // delete account control program
61 cps, err := store.ListControlPrograms()
62 fmt.Println("len(cps):", len(cps))
67 for _, cp := range cps {
68 if cp.AccountID == account.ID {
69 sha3pool.Sum256(hash[:], cp.ControlProgram)
70 batch.Delete(ContractKey(bc.NewHash(hash)))
74 // delete bip44 contract index
75 batch.Delete(Bip44ContractIndexKey(account.ID, false))
76 batch.Delete(Bip44ContractIndexKey(account.ID, true))
78 // delete contract index
79 batch.Delete(contractIndexKey(account.ID))
82 batch.Delete(AccountIDKey(account.ID))
83 batch.Delete(accountAliasKey(account.Alias))
84 if store.batch == nil {
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 {
97 accountUtxoIter := store.accountDB.IteratorPrefix([]byte(UTXOPrefix))
98 defer accountUtxoIter.Release()
100 for accountUtxoIter.Next() {
101 accountUtxo := &acc.UTXO{}
102 if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
105 if accountID == accountUtxo.AccountID {
106 batch.Delete(StandardUTXOKey(accountUtxo.OutputID))
110 if store.batch == nil {
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))
121 store.batch.Delete(StandardUTXOKey(outputID))
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
131 return store.GetAccountByID(string(accountID))
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
140 account := new(acc.Account)
141 if err := json.Unmarshal(rawAccount, account); err != nil {
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)
156 // GetBip44ContractIndex get bip44 contract index
157 func (store *AccountStore) GetBip44ContractIndex(accountID string, change bool) uint64 {
159 if rawIndexBytes := store.accountDB.Get(Bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
160 index = common.BytesToUnit64(rawIndexBytes)
165 // GetCoinbaseArbitrary get coinbase arbitrary
166 func (store *AccountStore) GetCoinbaseArbitrary() []byte {
167 return store.accountDB.Get([]byte(CoinbaseAbKey))
170 // GetContractIndex get contract index
171 func (store *AccountStore) GetContractIndex(accountID string) uint64 {
173 if rawIndexBytes := store.accountDB.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
174 index = common.BytesToUnit64(rawIndexBytes)
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
185 cp := new(acc.CtrlProgram)
186 if err := json.Unmarshal(rawProgram, cp); err != nil {
192 // GetMiningAddress get mining address
193 func (store *AccountStore) GetMiningAddress() (*acc.CtrlProgram, error) {
194 rawCP := store.accountDB.Get([]byte(MiningAddressKey))
196 return nil, acc.ErrFindMiningAddress
198 cp := new(acc.CtrlProgram)
199 if err := json.Unmarshal(rawCP, cp); err != nil {
205 // GetUTXO get standard utxo by id
206 func (store *AccountStore) GetUTXO(outid bc.Hash) (*acc.UTXO, error) {
208 if data := store.accountDB.Get(StandardUTXOKey(outid)); data != nil {
209 return u, json.Unmarshal(data, u)
211 if data := store.accountDB.Get(ContractUTXOKey(outid)); data != nil {
212 return u, json.Unmarshal(data, u)
214 return nil, acc.ErrMatchUTXO
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()
223 for accountIter.Next() {
224 account := new(acc.Account)
225 if err := json.Unmarshal(accountIter.Value(), &account); err != nil {
228 accounts = append(accounts, account)
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()
241 cp := new(acc.CtrlProgram)
242 v := hex.EncodeToString(cpIter.Value())
244 if err := json.Unmarshal(cpIter.Value(), cp); err != nil {
247 cps = append(cps, cp)
252 // ListUTXOs get utxos by accountID
253 func (store *AccountStore) ListUTXOs() []*acc.UTXO {
254 utxoIter := store.accountDB.IteratorPrefix([]byte(UTXOPrefix))
255 defer utxoIter.Release()
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")
264 utxos = append(utxos, utxo)
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)
273 return acc.ErrMarshalAccount
276 batch := store.accountDB.NewBatch()
277 if store.batch != nil {
281 batch.Set(AccountIDKey(account.ID), rawAccount)
282 batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
284 if store.batch == nil {
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))
295 store.batch.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
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))
304 store.batch.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
308 // SetCoinbaseArbitrary set coinbase arbitrary
309 func (store *AccountStore) SetCoinbaseArbitrary(arbitrary []byte) {
310 if store.batch == nil {
311 store.accountDB.Set([]byte(CoinbaseAbKey), arbitrary)
313 store.batch.Set([]byte(CoinbaseAbKey), arbitrary)
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))
322 store.batch.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
326 // SetControlProgram set raw program
327 func (store *AccountStore) SetControlProgram(hash bc.Hash, program *acc.CtrlProgram) error {
328 accountCP, err := json.Marshal(program)
332 if store.batch == nil {
333 store.accountDB.Set(ContractKey(hash), accountCP)
335 store.batch.Set(ContractKey(hash), accountCP)
340 // SetMiningAddress set mining address
341 func (store *AccountStore) SetMiningAddress(program *acc.CtrlProgram) error {
342 rawProgram, err := json.Marshal(program)
347 if store.batch == nil {
348 store.accountDB.Set([]byte(MiningAddressKey), rawProgram)
350 store.batch.Set([]byte(MiningAddressKey), rawProgram)
355 // SetStandardUTXO set standard utxo
356 func (store *AccountStore) SetStandardUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
357 data, err := json.Marshal(utxo)
361 if store.batch == nil {
362 store.accountDB.Set(StandardUTXOKey(outputID), data)
364 store.batch.Set(StandardUTXOKey(outputID), data)