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"
18 func accountIndexKey(xpubs []chainkd.XPub) []byte {
21 cpy := append([]chainkd.XPub{}, xpubs[:]...)
22 sort.Sort(signers.SortKeys(cpy))
23 for _, xpub := range cpy {
24 xPubs = append(xPubs, xpub[:]...)
26 sha3pool.Sum256(hash[:], xPubs)
27 return append(AccountIndexPrefix, hash[:]...)
30 func Bip44ContractIndexKey(accountID string, change bool) []byte {
31 key := append(ContractIndexPrefix, []byte(accountID)...)
33 return append(key, []byte{1}...)
35 return append(key, []byte{0}...)
38 // ContractKey account control promgram store prefix
39 func ContractKey(hash bc.Hash) []byte {
40 return append(ContractPrefix, hash.Bytes()...)
43 // AccountIDKey account id store prefix
44 func AccountIDKey(accountID string) []byte {
45 return append(AccountPrefix, []byte(accountID)...)
48 // StandardUTXOKey makes an account unspent outputs key to store
49 func StandardUTXOKey(id bc.Hash) []byte {
50 return append(UTXOPrefix, id.Bytes()...)
53 // AccountStore satisfies AccountStore interface.
54 type AccountStore struct {
59 // NewAccountStore create new AccountStore.
60 func NewAccountStore(db dbm.DB) *AccountStore {
67 // InitBatch initial batch
68 func (store *AccountStore) InitBatch() error {
69 if store.batch != nil {
70 return errors.New("AccountStore initail fail, store batch is not nil.")
72 store.batch = store.db.NewBatch()
76 // CommitBatch commit batch
77 func (store *AccountStore) CommitBatch() error {
78 if store.batch == nil {
79 return errors.New("AccountStore commit fail, store batch is nil.")
86 // DeleteAccount set account account ID, account alias and raw account.
87 func (store *AccountStore) DeleteAccount(account *acc.Account) error {
88 batch := store.db.NewBatch()
89 if store.batch != nil {
93 // delete account utxos
94 store.deleteAccountUTXOs(account.ID, batch)
96 // delete account control program
97 if err := store.deleteAccountControlPrograms(account.ID, batch); err != nil {
101 // delete bip44 contract index
102 batch.Delete(Bip44ContractIndexKey(account.ID, false))
103 batch.Delete(Bip44ContractIndexKey(account.ID, true))
105 // delete contract index
106 batch.Delete(contractIndexKey(account.ID))
109 batch.Delete(AccountIDKey(account.ID))
110 batch.Delete(accountAliasKey(account.Alias))
111 if store.batch == nil {
117 // deleteAccountUTXOs delete account utxos by accountID
118 func (store *AccountStore) deleteAccountUTXOs(accountID string, batch dbm.Batch) error {
119 accountUtxoIter := store.db.IteratorPrefix(dbm.UTXOPrefix)
120 defer accountUtxoIter.Release()
122 for accountUtxoIter.Next() {
123 accountUtxo := new(acc.UTXO)
124 if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
128 if accountID == accountUtxo.AccountID {
129 batch.Delete(StandardUTXOKey(accountUtxo.OutputID))
136 // deleteAccountControlPrograms deletes account control program
137 func (store *AccountStore) deleteAccountControlPrograms(accountID string, batch dbm.Batch) error {
138 cps, err := store.ListControlPrograms()
144 for _, cp := range cps {
145 if cp.AccountID == accountID {
146 sha3pool.Sum256(hash[:], cp.ControlProgram)
147 batch.Delete(ContractKey(bc.NewHash(hash)))
153 // DeleteStandardUTXO delete utxo by outpu id
154 func (store *AccountStore) DeleteStandardUTXO(outputID bc.Hash) {
155 if store.batch == nil {
156 store.db.Delete(StandardUTXOKey(outputID))
158 store.batch.Delete(StandardUTXOKey(outputID))
162 // GetAccountByAlias get account by account alias
163 func (store *AccountStore) GetAccountByAlias(accountAlias string) (*acc.Account, error) {
164 accountID := store.db.Get(accountAliasKey(accountAlias))
165 if accountID == nil {
166 return nil, acc.ErrFindAccount
168 return store.GetAccountByID(string(accountID))
171 // GetAccountByID get account by accountID
172 func (store *AccountStore) GetAccountByID(accountID string) (*acc.Account, error) {
173 rawAccount := store.db.Get(AccountIDKey(accountID))
174 if rawAccount == nil {
175 return nil, acc.ErrFindAccount
178 account := new(acc.Account)
179 if err := json.Unmarshal(rawAccount, account); err != nil {
186 // GetAccountIndex get account index by account xpubs
187 func (store *AccountStore) GetAccountIndex(xpubs []chainkd.XPub) uint64 {
188 currentIndex := uint64(0)
189 if rawIndexBytes := store.db.Get(accountIndexKey(xpubs)); rawIndexBytes != nil {
190 currentIndex = common.BytesToUnit64(rawIndexBytes)
195 // GetBip44ContractIndex get bip44 contract index
196 func (store *AccountStore) GetBip44ContractIndex(accountID string, change bool) uint64 {
198 if rawIndexBytes := store.db.Get(Bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
199 index = common.BytesToUnit64(rawIndexBytes)
204 // GetCoinbaseArbitrary get coinbase arbitrary
205 func (store *AccountStore) GetCoinbaseArbitrary() []byte {
206 return store.db.Get(dbm.CoinbaseAbKey)
209 // GetContractIndex get contract index
210 func (store *AccountStore) GetContractIndex(accountID string) uint64 {
212 if rawIndexBytes := store.db.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
213 index = common.BytesToUnit64(rawIndexBytes)
218 // GetControlProgram get control program
219 func (store *AccountStore) GetControlProgram(hash bc.Hash) (*acc.CtrlProgram, error) {
220 rawProgram := store.db.Get(ContractKey(hash))
221 if rawProgram == nil {
222 return nil, acc.ErrFindCtrlProgram
225 cp := new(acc.CtrlProgram)
226 if err := json.Unmarshal(rawProgram, cp); err != nil {
233 // GetMiningAddress get mining address
234 func (store *AccountStore) GetMiningAddress() (*acc.CtrlProgram, error) {
235 rawCP := store.db.Get(dbm.MiningAddressKey)
237 return nil, acc.ErrFindMiningAddress
240 cp := new(acc.CtrlProgram)
241 if err := json.Unmarshal(rawCP, cp); err != nil {
248 // GetUTXO get standard utxo by id
249 func (store *AccountStore) GetUTXO(outid bc.Hash) (*acc.UTXO, error) {
251 if data := store.db.Get(StandardUTXOKey(outid)); data != nil {
252 return u, json.Unmarshal(data, u)
255 if data := store.db.Get(ContractUTXOKey(outid)); data != nil {
256 return u, json.Unmarshal(data, u)
259 return nil, acc.ErrMatchUTXO
262 // ListAccounts get all accounts which name prfix is id.
263 func (store *AccountStore) ListAccounts(id string) ([]*acc.Account, error) {
264 accounts := []*acc.Account{}
265 accountIter := store.db.IteratorPrefix(AccountIDKey(strings.TrimSpace(id)))
266 defer accountIter.Release()
268 for accountIter.Next() {
269 account := new(acc.Account)
270 if err := json.Unmarshal(accountIter.Value(), account); err != nil {
274 accounts = append(accounts, account)
279 // ListControlPrograms get all local control programs
280 func (store *AccountStore) ListControlPrograms() ([]*acc.CtrlProgram, error) {
281 cps := []*acc.CtrlProgram{}
282 cpIter := store.db.IteratorPrefix(dbm.ContractPrefix)
283 defer cpIter.Release()
286 cp := new(acc.CtrlProgram)
287 if err := json.Unmarshal(cpIter.Value(), cp); err != nil {
291 cps = append(cps, cp)
296 // ListUTXOs get utxos by accountID
297 func (store *AccountStore) ListUTXOs() ([]*acc.UTXO, error) {
298 utxoIter := store.db.IteratorPrefix(dbm.UTXOPrefix)
299 defer utxoIter.Release()
301 utxos := []*acc.UTXO{}
302 for utxoIter.Next() {
303 utxo := new(acc.UTXO)
304 if err := json.Unmarshal(utxoIter.Value(), utxo); err != nil {
308 utxos = append(utxos, utxo)
313 // SetAccount set account account ID, account alias and raw account.
314 func (store *AccountStore) SetAccount(account *acc.Account) error {
315 rawAccount, err := json.Marshal(account)
317 return acc.ErrMarshalAccount
320 batch := store.db.NewBatch()
321 if store.batch != nil {
325 batch.Set(AccountIDKey(account.ID), rawAccount)
326 batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
328 if store.batch == nil {
334 // SetAccountIndex update account index
335 func (store *AccountStore) SetAccountIndex(account *acc.Account) {
336 currentIndex := store.GetAccountIndex(account.XPubs)
337 if account.KeyIndex > currentIndex {
338 if store.batch == nil {
339 store.db.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
341 store.batch.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
346 // SetBip44ContractIndex set contract index
347 func (store *AccountStore) SetBip44ContractIndex(accountID string, change bool, index uint64) {
348 if store.batch == nil {
349 store.db.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
351 store.batch.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
355 // SetCoinbaseArbitrary set coinbase arbitrary
356 func (store *AccountStore) SetCoinbaseArbitrary(arbitrary []byte) {
357 if store.batch == nil {
358 store.db.Set(dbm.CoinbaseAbKey, arbitrary)
360 store.batch.Set(dbm.CoinbaseAbKey, arbitrary)
364 // SetContractIndex set contract index
365 func (store *AccountStore) SetContractIndex(accountID string, index uint64) {
366 if store.batch == nil {
367 store.db.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
369 store.batch.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
373 // SetControlProgram set raw program
374 func (store *AccountStore) SetControlProgram(hash bc.Hash, program *acc.CtrlProgram) error {
375 accountCP, err := json.Marshal(program)
379 if store.batch == nil {
380 store.db.Set(ContractKey(hash), accountCP)
382 store.batch.Set(ContractKey(hash), accountCP)
387 // SetMiningAddress set mining address
388 func (store *AccountStore) SetMiningAddress(program *acc.CtrlProgram) error {
389 rawProgram, err := json.Marshal(program)
394 if store.batch == nil {
395 store.db.Set(dbm.MiningAddressKey, rawProgram)
397 store.batch.Set(dbm.MiningAddressKey, rawProgram)
402 // SetStandardUTXO set standard utxo
403 func (store *AccountStore) SetStandardUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
404 data, err := json.Marshal(utxo)
409 if store.batch == nil {
410 store.db.Set(StandardUTXOKey(outputID), data)
412 store.batch.Set(StandardUTXOKey(outputID), data)