8 acc "github.com/vapor/account"
9 "github.com/vapor/blockchain/signers"
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"
19 utxoPrefix byte = iota //UTXOPrefix is StandardUTXOKey prefix
22 accountPrefix // AccountPrefix is account ID prefix
28 accountStore = []byte("AS:")
29 UTXOPrefix = append(accountStore, utxoPrefix, colon)
30 ContractPrefix = append(accountStore, contractPrefix, colon)
31 ContractIndexPrefix = append(accountStore, contractIndexPrefix, colon)
32 AccountPrefix = append(accountStore, accountPrefix, colon) // AccountPrefix is account ID prefix
33 AccountIndexPrefix = append(accountStore, accountIndexPrefix, colon)
36 func accountIndexKey(xpubs []chainkd.XPub) []byte {
39 cpy := append([]chainkd.XPub{}, xpubs[:]...)
40 sort.Sort(signers.SortKeys(cpy))
41 for _, xpub := range cpy {
42 xPubs = append(xPubs, xpub[:]...)
44 sha3pool.Sum256(hash[:], xPubs)
45 return append(AccountIndexPrefix, hash[:]...)
48 func Bip44ContractIndexKey(accountID string, change bool) []byte {
49 key := append(ContractIndexPrefix, []byte(accountID)...)
51 return append(key, 0x01)
53 return append(key, 0x00)
56 // ContractKey account control promgram store prefix
57 func ContractKey(hash bc.Hash) []byte {
58 return append(ContractPrefix, hash.Bytes()...)
61 // AccountIDKey account id store prefix
62 func AccountIDKey(accountID string) []byte {
63 return append(AccountPrefix, []byte(accountID)...)
66 // StandardUTXOKey makes an account unspent outputs key to store
67 func StandardUTXOKey(id bc.Hash) []byte {
68 return append(UTXOPrefix, id.Bytes()...)
71 func accountAliasKey(name string) []byte {
72 return append(AccountAliasPrefix, []byte(name)...)
75 // AccountStore satisfies AccountStore interface.
76 type AccountStore struct {
81 // NewAccountStore create new AccountStore.
82 func NewAccountStore(db dbm.DB) *AccountStore {
89 // InitBatch initial new account store
90 func (store *AccountStore) InitBatch() acc.AccountStore {
91 newStore := NewAccountStore(store.db)
92 newStore.batch = newStore.db.NewBatch()
96 // CommitBatch commit batch
97 func (store *AccountStore) CommitBatch() error {
98 if store.batch == nil {
99 return errors.New("AccountStore commit fail, store batch is nil.")
106 // DeleteAccount set account account ID, account alias and raw account.
107 func (store *AccountStore) DeleteAccount(account *acc.Account) error {
108 batch := store.db.NewBatch()
109 if store.batch != nil {
113 // delete account utxos
114 store.deleteAccountUTXOs(account.ID, batch)
116 // delete account control program
117 if err := store.deleteAccountControlPrograms(account.ID, batch); err != nil {
121 // delete bip44 contract index
122 batch.Delete(Bip44ContractIndexKey(account.ID, false))
123 batch.Delete(Bip44ContractIndexKey(account.ID, true))
125 // delete contract index
126 batch.Delete(contractIndexKey(account.ID))
129 batch.Delete(AccountIDKey(account.ID))
130 batch.Delete(accountAliasKey(account.Alias))
131 if store.batch == nil {
137 // deleteAccountUTXOs delete account utxos by accountID
138 func (store *AccountStore) deleteAccountUTXOs(accountID string, batch dbm.Batch) error {
139 accountUtxoIter := store.db.IteratorPrefix(UTXOPrefix)
140 defer accountUtxoIter.Release()
142 for accountUtxoIter.Next() {
143 accountUtxo := new(acc.UTXO)
144 if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
148 if accountID == accountUtxo.AccountID {
149 batch.Delete(StandardUTXOKey(accountUtxo.OutputID))
156 // deleteAccountControlPrograms deletes account control program
157 func (store *AccountStore) deleteAccountControlPrograms(accountID string, batch dbm.Batch) error {
158 cps, err := store.ListControlPrograms()
164 for _, cp := range cps {
165 if cp.AccountID == accountID {
166 sha3pool.Sum256(hash[:], cp.ControlProgram)
167 batch.Delete(ContractKey(bc.NewHash(hash)))
173 // DeleteStandardUTXO delete utxo by outpu id
174 func (store *AccountStore) DeleteStandardUTXO(outputID bc.Hash) {
175 if store.batch == nil {
176 store.db.Delete(StandardUTXOKey(outputID))
178 store.batch.Delete(StandardUTXOKey(outputID))
182 // GetAccountByAlias get account by account alias
183 func (store *AccountStore) GetAccountByAlias(accountAlias string) (*acc.Account, error) {
184 accountID := store.db.Get(accountAliasKey(accountAlias))
185 if accountID == nil {
186 return nil, acc.ErrFindAccount
189 return store.GetAccountByID(string(accountID))
192 // GetAccountByID get account by accountID
193 func (store *AccountStore) GetAccountByID(accountID string) (*acc.Account, error) {
194 rawAccount := store.db.Get(AccountIDKey(accountID))
195 if rawAccount == nil {
196 return nil, acc.ErrFindAccount
199 account := new(acc.Account)
200 if err := json.Unmarshal(rawAccount, account); err != nil {
207 // GetAccountIndex get account index by account xpubs
208 func (store *AccountStore) GetAccountIndex(xpubs []chainkd.XPub) uint64 {
209 currentIndex := uint64(0)
210 if rawIndexBytes := store.db.Get(accountIndexKey(xpubs)); rawIndexBytes != nil {
211 currentIndex = common.BytesToUnit64(rawIndexBytes)
216 // GetBip44ContractIndex get bip44 contract index
217 func (store *AccountStore) GetBip44ContractIndex(accountID string, change bool) uint64 {
219 if rawIndexBytes := store.db.Get(Bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
220 index = common.BytesToUnit64(rawIndexBytes)
225 // GetCoinbaseArbitrary get coinbase arbitrary
226 func (store *AccountStore) GetCoinbaseArbitrary() []byte {
227 return store.db.Get(CoinbaseAbKey)
230 // GetContractIndex get contract index
231 func (store *AccountStore) GetContractIndex(accountID string) uint64 {
233 if rawIndexBytes := store.db.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
234 index = common.BytesToUnit64(rawIndexBytes)
239 // GetControlProgram get control program
240 func (store *AccountStore) GetControlProgram(hash bc.Hash) (*acc.CtrlProgram, error) {
241 rawProgram := store.db.Get(ContractKey(hash))
242 if rawProgram == nil {
243 return nil, acc.ErrFindCtrlProgram
246 cp := new(acc.CtrlProgram)
247 if err := json.Unmarshal(rawProgram, cp); err != nil {
254 // GetMiningAddress get mining address
255 func (store *AccountStore) GetMiningAddress() (*acc.CtrlProgram, error) {
256 rawCP := store.db.Get(MiningAddressKey)
258 return nil, acc.ErrFindMiningAddress
261 cp := new(acc.CtrlProgram)
262 if err := json.Unmarshal(rawCP, cp); err != nil {
269 // GetUTXO get standard utxo by id
270 func (store *AccountStore) GetUTXO(outid bc.Hash) (*acc.UTXO, error) {
272 if data := store.db.Get(StandardUTXOKey(outid)); data != nil {
273 return u, json.Unmarshal(data, u)
276 if data := store.db.Get(ContractUTXOKey(outid)); data != nil {
277 return u, json.Unmarshal(data, u)
280 return nil, acc.ErrMatchUTXO
283 // ListAccounts get all accounts which name prfix is id.
284 func (store *AccountStore) ListAccounts(id string) ([]*acc.Account, error) {
285 accounts := []*acc.Account{}
286 accountIter := store.db.IteratorPrefix(AccountIDKey(strings.TrimSpace(id)))
287 defer accountIter.Release()
289 for accountIter.Next() {
290 account := new(acc.Account)
291 if err := json.Unmarshal(accountIter.Value(), account); err != nil {
295 accounts = append(accounts, account)
300 // ListControlPrograms get all local control programs
301 func (store *AccountStore) ListControlPrograms() ([]*acc.CtrlProgram, error) {
302 cps := []*acc.CtrlProgram{}
303 cpIter := store.db.IteratorPrefix(ContractPrefix)
304 defer cpIter.Release()
307 cp := new(acc.CtrlProgram)
308 if err := json.Unmarshal(cpIter.Value(), cp); err != nil {
312 cps = append(cps, cp)
317 // ListUTXOs get utxos by accountID
318 func (store *AccountStore) ListUTXOs() ([]*acc.UTXO, error) {
319 utxoIter := store.db.IteratorPrefix(UTXOPrefix)
320 defer utxoIter.Release()
322 utxos := []*acc.UTXO{}
323 for utxoIter.Next() {
324 utxo := new(acc.UTXO)
325 if err := json.Unmarshal(utxoIter.Value(), utxo); err != nil {
329 utxos = append(utxos, utxo)
334 // SetAccount set account account ID, account alias and raw account.
335 func (store *AccountStore) SetAccount(account *acc.Account) error {
336 rawAccount, err := json.Marshal(account)
338 return acc.ErrMarshalAccount
341 batch := store.db.NewBatch()
342 if store.batch != nil {
346 batch.Set(AccountIDKey(account.ID), rawAccount)
347 batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
349 if store.batch == nil {
355 // SetAccountIndex update account index
356 func (store *AccountStore) SetAccountIndex(account *acc.Account) {
357 currentIndex := store.GetAccountIndex(account.XPubs)
358 if account.KeyIndex > currentIndex {
359 if store.batch == nil {
360 store.db.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
362 store.batch.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
367 // SetBip44ContractIndex set contract index
368 func (store *AccountStore) SetBip44ContractIndex(accountID string, change bool, index uint64) {
369 if store.batch == nil {
370 store.db.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
372 store.batch.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
376 // SetCoinbaseArbitrary set coinbase arbitrary
377 func (store *AccountStore) SetCoinbaseArbitrary(arbitrary []byte) {
378 if store.batch == nil {
379 store.db.Set(CoinbaseAbKey, arbitrary)
381 store.batch.Set(CoinbaseAbKey, arbitrary)
385 // SetContractIndex set contract index
386 func (store *AccountStore) SetContractIndex(accountID string, index uint64) {
387 if store.batch == nil {
388 store.db.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
390 store.batch.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
394 // SetControlProgram set raw program
395 func (store *AccountStore) SetControlProgram(hash bc.Hash, program *acc.CtrlProgram) error {
396 accountCP, err := json.Marshal(program)
400 if store.batch == nil {
401 store.db.Set(ContractKey(hash), accountCP)
403 store.batch.Set(ContractKey(hash), accountCP)
408 // SetMiningAddress set mining address
409 func (store *AccountStore) SetMiningAddress(program *acc.CtrlProgram) error {
410 rawProgram, err := json.Marshal(program)
415 if store.batch == nil {
416 store.db.Set(MiningAddressKey, rawProgram)
418 store.batch.Set(MiningAddressKey, rawProgram)
423 // SetStandardUTXO set standard utxo
424 func (store *AccountStore) SetStandardUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
425 data, err := json.Marshal(utxo)
430 if store.batch == nil {
431 store.db.Set(StandardUTXOKey(outputID), data)
433 store.batch.Set(StandardUTXOKey(outputID), data)