15 "github.com/vapor/account"
16 acc "github.com/vapor/account"
17 "github.com/vapor/asset"
18 "github.com/vapor/blockchain/query"
19 "github.com/vapor/blockchain/signers"
20 "github.com/vapor/blockchain/txbuilder"
21 "github.com/vapor/common"
22 "github.com/vapor/config"
23 "github.com/vapor/consensus"
24 "github.com/vapor/crypto/ed25519/chainkd"
25 "github.com/vapor/crypto/sha3pool"
26 dbm "github.com/vapor/database/leveldb"
27 "github.com/vapor/errors"
28 "github.com/vapor/event"
29 "github.com/vapor/protocol"
30 "github.com/vapor/protocol/bc"
31 "github.com/vapor/protocol/bc/types"
34 func TestEncodeDecodeGlobalTxIndex(t *testing.T) {
39 BlockHash: bc.NewHash([32]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20}),
43 globalTxIdx := CalcGlobalTxIndex(&want.BlockHash, want.Position)
44 blockHashGot, positionGot := parseGlobalTxIdx(globalTxIdx)
45 if *blockHashGot != want.BlockHash {
46 t.Errorf("blockHash mismatch. Get: %v. Expect: %v", *blockHashGot, want.BlockHash)
49 if positionGot != want.Position {
50 t.Errorf("position mismatch. Get: %v. Expect: %v", positionGot, want.Position)
54 func TestWalletVersion(t *testing.T) {
56 dirPath, err := ioutil.TempDir(".", "")
60 defer os.RemoveAll(dirPath)
62 testDB := dbm.NewDB("testdb", "leveldb", "temp")
63 walletStore := NewMockWalletStore(testDB)
69 dispatcher := event.NewDispatcher()
70 w := mockWallet(walletStore, nil, nil, nil, dispatcher, false)
72 walletStatus := new(StatusInfo)
73 if err := w.store.SetWalletInfo(walletStatus); err != nil {
77 status, err := w.store.GetWalletInfo()
83 if err := w.checkWalletInfo(); err != errWalletVersionMismatch {
84 t.Fatal("fail to detect legacy wallet version")
87 // lower wallet version test case
88 lowerVersion := StatusInfo{Version: currentVersion - 1}
89 if err := w.store.SetWalletInfo(&lowerVersion); err != nil {
93 status, err = w.store.GetWalletInfo()
99 if err := w.checkWalletInfo(); err != errWalletVersionMismatch {
100 t.Fatal("fail to detect expired wallet version")
104 func mockUTXO(controlProg *account.CtrlProgram, assetID *bc.AssetID) *account.UTXO {
105 utxo := &account.UTXO{}
106 utxo.OutputID = bc.Hash{V0: 1}
107 utxo.SourceID = bc.Hash{V0: 2}
108 utxo.AssetID = *assetID
109 utxo.Amount = 1000000000
111 utxo.ControlProgram = controlProg.ControlProgram
112 utxo.AccountID = controlProg.AccountID
113 utxo.Address = controlProg.Address
114 utxo.ControlProgramIndex = controlProg.KeyIndex
118 func mockTxData(utxos []*account.UTXO, testAccount *account.Account) (*txbuilder.Template, *types.TxData, error) {
119 tplBuilder := txbuilder.NewBuilder(time.Now())
121 for _, utxo := range utxos {
122 txInput, sigInst, err := account.UtxoToInputs(testAccount.Signer, utxo)
126 tplBuilder.AddInput(txInput, sigInst)
128 out := &types.TxOutput{}
129 if utxo.AssetID == *consensus.BTMAssetID {
130 out = types.NewIntraChainOutput(utxo.AssetID, 100, utxo.ControlProgram)
132 out = types.NewIntraChainOutput(utxo.AssetID, utxo.Amount, utxo.ControlProgram)
134 tplBuilder.AddOutput(out)
137 return tplBuilder.Build()
140 func mockWallet(store WalletStore, account *account.Manager, asset *asset.Registry, chain *protocol.Chain, dispatcher *event.Dispatcher, txIndexFlag bool) *Wallet {
146 RecoveryMgr: newRecoveryManager(store, account),
147 EventDispatcher: dispatcher,
148 TxIndexFlag: txIndexFlag,
150 wallet.txMsgSub, _ = wallet.EventDispatcher.Subscribe(protocol.TxMsgEvent{})
154 func mockSingleBlock(tx *types.Tx) *types.Block {
156 BlockHeader: types.BlockHeader{
160 Transactions: []*types.Tx{config.GenesisTx(), tx},
166 errAccntTxIDNotFound = errors.New("account TXID not found")
167 errGetAsset = errors.New("Failed to find asset definition")
171 utxoPrefix byte = iota //UTXOPrefix is StandardUTXOKey prefix
174 accountPrefix // AccountPrefix is account ID prefix
178 // leveldb key prefix
181 accountStore = []byte("AS:")
182 UTXOPrefix = append(accountStore, utxoPrefix, colon)
183 ContractPrefix = append(accountStore, contractPrefix, colon)
184 ContractIndexPrefix = append(accountStore, contractIndexPrefix, colon)
185 AccountPrefix = append(accountStore, accountPrefix, colon) // AccountPrefix is account ID prefix
186 AccountIndexPrefix = append(accountStore, accountIndexPrefix, colon)
190 sutxoPrefix byte = iota //SUTXOPrefix is ContractUTXOKey prefix
192 txPrefix //TxPrefix is wallet database transactions prefix
193 txIndexPrefix //TxIndexPrefix is wallet database tx index prefix
194 unconfirmedTxPrefix //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
195 globalTxIndexPrefix //GlobalTxIndexPrefix is wallet database global tx index prefix
199 recoveryKey //recoveryKey key for db store recovery info.
203 walletStore = []byte("WS:")
204 SUTXOPrefix = append(walletStore, sutxoPrefix, colon)
205 AccountAliasPrefix = append(walletStore, accountAliasPrefix, colon)
206 TxPrefix = append(walletStore, txPrefix, colon) //TxPrefix is wallet database transactions prefix
207 TxIndexPrefix = append(walletStore, txIndexPrefix, colon) //TxIndexPrefix is wallet database tx index prefix
208 UnconfirmedTxPrefix = append(walletStore, unconfirmedTxPrefix, colon) //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
209 GlobalTxIndexPrefix = append(walletStore, globalTxIndexPrefix, colon) //GlobalTxIndexPrefix is wallet database global tx index prefix
210 WalletKey = append(walletStore, walletKey)
211 MiningAddressKey = append(walletStore, miningAddressKey)
212 CoinbaseAbKey = append(walletStore, coinbaseAbKey)
213 RecoveryKey = append(walletStore, recoveryKey)
216 func accountIndexKey(xpubs []chainkd.XPub) []byte {
219 cpy := append([]chainkd.XPub{}, xpubs[:]...)
220 sort.Sort(signers.SortKeys(cpy))
221 for _, xpub := range cpy {
222 xPubs = append(xPubs, xpub[:]...)
224 sha3pool.Sum256(hash[:], xPubs)
225 return append([]byte(AccountIndexPrefix), hash[:]...)
228 func Bip44ContractIndexKey(accountID string, change bool) []byte {
229 key := append([]byte(ContractIndexPrefix), accountID...)
231 return append(key, []byte{1}...)
233 return append(key, []byte{0}...)
236 // ContractKey account control promgram store prefix
237 func ContractKey(hash bc.Hash) []byte {
238 return append([]byte(ContractPrefix), hash.Bytes()...)
241 // AccountIDKey account id store prefix
242 func AccountIDKey(accountID string) []byte {
243 return append([]byte(AccountPrefix), []byte(accountID)...)
246 // StandardUTXOKey makes an account unspent outputs key to store
247 func StandardUTXOKey(id bc.Hash) []byte {
248 return append(UTXOPrefix, id.Bytes()...)
251 // ContractUTXOKey makes a smart contract unspent outputs key to store
252 func ContractUTXOKey(id bc.Hash) []byte {
253 return append(SUTXOPrefix, id.Bytes()...)
256 func calcDeleteKey(blockHeight uint64) []byte {
257 return []byte(fmt.Sprintf("%s%016x", TxPrefix, blockHeight))
260 func calcTxIndexKey(txID string) []byte {
261 return append(TxIndexPrefix, []byte(txID)...)
264 func calcAnnotatedKey(formatKey string) []byte {
265 return append(TxPrefix, []byte(formatKey)...)
268 func calcUnconfirmedTxKey(formatKey string) []byte {
269 return append(UnconfirmedTxPrefix, []byte(formatKey)...)
272 func CalcGlobalTxIndexKey(txID string) []byte {
273 return append(GlobalTxIndexPrefix, []byte(txID)...)
276 func CalcGlobalTxIndex(blockHash *bc.Hash, position uint64) []byte {
277 txIdx := make([]byte, 40)
278 copy(txIdx[:32], blockHash.Bytes())
279 binary.BigEndian.PutUint64(txIdx[32:], position)
283 func formatKey(blockHeight uint64, position uint32) string {
284 return fmt.Sprintf("%016x%08x", blockHeight, position)
287 func contractIndexKey(accountID string) []byte {
288 return append([]byte(ContractIndexPrefix), []byte(accountID)...)
291 func accountAliasKey(name string) []byte {
292 return append([]byte(AccountAliasPrefix), []byte(name)...)
295 // MockWalletStore store wallet using leveldb
296 type MockWalletStore struct {
301 // NewMockWalletStore create new MockWalletStore struct
302 func NewMockWalletStore(db dbm.DB) *MockWalletStore {
303 return &MockWalletStore{
309 // InitBatch initial batch
310 func (store *MockWalletStore) InitBatch() error {
311 if store.batch != nil {
312 return errors.New("MockWalletStore initail fail, store batch is not nil.")
314 store.batch = store.db.NewBatch()
318 // CommitBatch commit batch
319 func (store *MockWalletStore) CommitBatch() error {
320 if store.batch == nil {
321 return errors.New("MockWalletStore commit fail, store batch is nil.")
328 // DeleteContractUTXO delete contract utxo by outputID
329 func (store *MockWalletStore) DeleteContractUTXO(outputID bc.Hash) {
330 if store.batch == nil {
331 store.db.Delete(ContractUTXOKey(outputID))
333 store.batch.Delete(ContractUTXOKey(outputID))
337 // DeleteRecoveryStatus delete recovery status
338 func (store *MockWalletStore) DeleteRecoveryStatus() {
339 if store.batch == nil {
340 store.db.Delete(RecoveryKey)
342 store.batch.Delete(RecoveryKey)
346 // DeleteTransactions delete transactions when orphan block rollback
347 func (store *MockWalletStore) DeleteTransactions(height uint64) {
348 batch := store.db.NewBatch()
349 if store.batch != nil {
352 txIter := store.db.IteratorPrefix(calcDeleteKey(height))
353 defer txIter.Release()
355 tmpTx := query.AnnotatedTx{}
357 if err := json.Unmarshal(txIter.Value(), &tmpTx); err == nil {
358 batch.Delete(calcTxIndexKey(tmpTx.ID.String()))
360 batch.Delete(txIter.Key())
362 if store.batch == nil {
367 // DeleteUnconfirmedTransaction delete unconfirmed tx by txID
368 func (store *MockWalletStore) DeleteUnconfirmedTransaction(txID string) {
369 if store.batch == nil {
370 store.db.Delete(calcUnconfirmedTxKey(txID))
372 store.batch.Delete(calcUnconfirmedTxKey(txID))
376 // DeleteWalletTransactions delete all txs in wallet
377 func (store *MockWalletStore) DeleteWalletTransactions() {
378 batch := store.db.NewBatch()
379 if store.batch != nil {
382 txIter := store.db.IteratorPrefix([]byte(TxPrefix))
383 defer txIter.Release()
386 batch.Delete(txIter.Key())
389 txIndexIter := store.db.IteratorPrefix([]byte(TxIndexPrefix))
390 defer txIndexIter.Release()
392 for txIndexIter.Next() {
393 batch.Delete(txIndexIter.Key())
395 if store.batch == nil {
400 // DeleteWalletUTXOs delete all txs in wallet
401 func (store *MockWalletStore) DeleteWalletUTXOs() {
402 batch := store.db.NewBatch()
403 if store.batch != nil {
406 ruIter := store.db.IteratorPrefix([]byte(UTXOPrefix))
407 defer ruIter.Release()
409 batch.Delete(ruIter.Key())
412 suIter := store.db.IteratorPrefix([]byte(SUTXOPrefix))
413 defer suIter.Release()
415 batch.Delete(suIter.Key())
417 if store.batch == nil {
422 // GetAsset get asset by assetID
423 func (store *MockWalletStore) GetAsset(assetID *bc.AssetID) (*asset.Asset, error) {
424 definitionByte := store.db.Get(asset.ExtAssetKey(assetID))
425 if definitionByte == nil {
426 return nil, errGetAsset
428 definitionMap := make(map[string]interface{})
429 if err := json.Unmarshal(definitionByte, &definitionMap); err != nil {
432 alias := assetID.String()
433 externalAsset := &asset.Asset{
436 DefinitionMap: definitionMap,
437 RawDefinitionByte: definitionByte,
439 return externalAsset, nil
442 // GetGlobalTransactionIndex get global tx by txID
443 func (store *MockWalletStore) GetGlobalTransactionIndex(txID string) []byte {
444 return store.db.Get(CalcGlobalTxIndexKey(txID))
447 // GetStandardUTXO get standard utxo by id
448 func (store *MockWalletStore) GetStandardUTXO(outid bc.Hash) (*acc.UTXO, error) {
449 rawUTXO := store.db.Get(StandardUTXOKey(outid))
451 return nil, fmt.Errorf("failed get standard UTXO, outputID: %s ", outid.String())
453 UTXO := new(acc.UTXO)
454 if err := json.Unmarshal(rawUTXO, UTXO); err != nil {
460 // GetTransaction get tx by txid
461 func (store *MockWalletStore) GetTransaction(txID string) (*query.AnnotatedTx, error) {
462 formatKey := store.db.Get(calcTxIndexKey(txID))
463 if formatKey == nil {
464 return nil, errAccntTxIDNotFound
466 rawTx := store.db.Get(calcAnnotatedKey(string(formatKey)))
467 tx := new(query.AnnotatedTx)
468 if err := json.Unmarshal(rawTx, tx); err != nil {
474 // GetUnconfirmedTransaction get unconfirmed tx by txID
475 func (store *MockWalletStore) GetUnconfirmedTransaction(txID string) (*query.AnnotatedTx, error) {
476 rawUnconfirmedTx := store.db.Get(calcUnconfirmedTxKey(txID))
477 if rawUnconfirmedTx == nil {
478 return nil, fmt.Errorf("failed get unconfirmed tx, txID: %s ", txID)
480 tx := new(query.AnnotatedTx)
481 if err := json.Unmarshal(rawUnconfirmedTx, tx); err != nil {
487 // GetRecoveryStatus delete recovery status
488 func (store *MockWalletStore) GetRecoveryStatus() (*RecoveryState, error) {
489 rawStatus := store.db.Get(RecoveryKey)
490 if rawStatus == nil {
491 return nil, ErrGetRecoveryStatus
493 state := new(RecoveryState)
494 if err := json.Unmarshal(rawStatus, state); err != nil {
500 // GetWalletInfo get wallet information
501 func (store *MockWalletStore) GetWalletInfo() (*StatusInfo, error) {
502 rawStatus := store.db.Get([]byte(WalletKey))
503 if rawStatus == nil {
504 return nil, fmt.Errorf("failed get wallet info")
506 status := new(StatusInfo)
507 if err := json.Unmarshal(rawStatus, status); err != nil {
513 // ListAccountUTXOs get all account unspent outputs
514 func (store *MockWalletStore) ListAccountUTXOs(id string, isSmartContract bool) ([]*acc.UTXO, error) {
520 idBytes, err := hex.DecodeString(id)
525 accountUtxoIter := store.db.IteratorPrefix(append(prefix, idBytes...))
526 defer accountUtxoIter.Release()
528 confirmedUTXOs := []*acc.UTXO{}
529 for accountUtxoIter.Next() {
530 utxo := new(acc.UTXO)
531 if err := json.Unmarshal(accountUtxoIter.Value(), utxo); err != nil {
535 confirmedUTXOs = append(confirmedUTXOs, utxo)
537 return confirmedUTXOs, nil
540 func (store *MockWalletStore) ListTransactions(accountID string, StartTxID string, count uint, unconfirmed bool) ([]*query.AnnotatedTx, error) {
541 annotatedTxs := []*query.AnnotatedTx{}
547 startKey = calcUnconfirmedTxKey(StartTxID)
549 formatKey := store.db.Get(calcTxIndexKey(StartTxID))
550 if formatKey == nil {
551 return nil, errAccntTxIDNotFound
553 startKey = calcAnnotatedKey(string(formatKey))
558 preFix = UnconfirmedTxPrefix
561 itr := store.db.IteratorPrefixWithStart([]byte(preFix), startKey, true)
564 for txNum := count; itr.Next() && txNum > 0; txNum-- {
565 annotatedTx := new(query.AnnotatedTx)
566 if err := json.Unmarshal(itr.Value(), &annotatedTx); err != nil {
569 annotatedTxs = append(annotatedTxs, annotatedTx)
572 return annotatedTxs, nil
575 // ListUnconfirmedTransactions get all unconfirmed txs
576 func (store *MockWalletStore) ListUnconfirmedTransactions() ([]*query.AnnotatedTx, error) {
577 annotatedTxs := []*query.AnnotatedTx{}
578 txIter := store.db.IteratorPrefix([]byte(UnconfirmedTxPrefix))
579 defer txIter.Release()
582 annotatedTx := &query.AnnotatedTx{}
583 if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
586 annotatedTxs = append(annotatedTxs, annotatedTx)
588 return annotatedTxs, nil
591 // SetAssetDefinition set assetID and definition
592 func (store *MockWalletStore) SetAssetDefinition(assetID *bc.AssetID, definition []byte) {
593 if store.batch == nil {
594 store.db.Set(asset.ExtAssetKey(assetID), definition)
596 store.batch.Set(asset.ExtAssetKey(assetID), definition)
600 // SetContractUTXO set standard utxo
601 func (store *MockWalletStore) SetContractUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
602 data, err := json.Marshal(utxo)
606 if store.batch == nil {
607 store.db.Set(ContractUTXOKey(outputID), data)
609 store.batch.Set(ContractUTXOKey(outputID), data)
614 // SetGlobalTransactionIndex set global tx index by blockhash and position
615 func (store *MockWalletStore) SetGlobalTransactionIndex(globalTxID string, blockHash *bc.Hash, position uint64) {
616 if store.batch == nil {
617 store.db.Set(CalcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
619 store.batch.Set(CalcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
623 // SetRecoveryStatus set recovery status
624 func (store *MockWalletStore) SetRecoveryStatus(recoveryState *RecoveryState) error {
625 rawStatus, err := json.Marshal(recoveryState)
629 if store.batch == nil {
630 store.db.Set(RecoveryKey, rawStatus)
632 store.batch.Set(RecoveryKey, rawStatus)
637 // SetTransaction set raw transaction by block height and tx position
638 func (store *MockWalletStore) SetTransaction(height uint64, tx *query.AnnotatedTx) error {
639 batch := store.db.NewBatch()
640 if store.batch != nil {
644 rawTx, err := json.Marshal(tx)
648 batch.Set(calcAnnotatedKey(formatKey(height, tx.Position)), rawTx)
649 batch.Set(calcTxIndexKey(tx.ID.String()), []byte(formatKey(height, tx.Position)))
651 if store.batch == nil {
657 // SetUnconfirmedTransaction set unconfirmed tx by txID
658 func (store *MockWalletStore) SetUnconfirmedTransaction(txID string, tx *query.AnnotatedTx) error {
659 rawTx, err := json.Marshal(tx)
663 if store.batch == nil {
664 store.db.Set(calcUnconfirmedTxKey(txID), rawTx)
666 store.batch.Set(calcUnconfirmedTxKey(txID), rawTx)
671 // SetWalletInfo get wallet information
672 func (store *MockWalletStore) SetWalletInfo(status *StatusInfo) error {
673 rawWallet, err := json.Marshal(status)
678 if store.batch == nil {
679 store.db.Set([]byte(WalletKey), rawWallet)
681 store.batch.Set([]byte(WalletKey), rawWallet)
686 type MockAccountStore struct {
691 // NewAccountStore create new MockAccountStore.
692 func NewMockAccountStore(db dbm.DB) *MockAccountStore {
693 return &MockAccountStore{
699 // InitStore initial batch
700 func (store *MockAccountStore) InitStore() acc.AccountStore {
701 newStore := NewMockAccountStore(store.db)
702 newStore.batch = newStore.db.NewBatch()
706 // CommitBatch commit batch
707 func (store *MockAccountStore) CommitBatch() error {
708 if store.batch == nil {
709 return errors.New("MockAccountStore commit fail, store batch is nil.")
716 // DeleteAccount set account account ID, account alias and raw account.
717 func (store *MockAccountStore) DeleteAccount(account *acc.Account) error {
718 batch := store.db.NewBatch()
719 if store.batch != nil {
723 // delete account utxos
724 store.deleteAccountUTXOs(account.ID, batch)
726 // delete account control program
727 if err := store.deleteAccountControlPrograms(account.ID, batch); err != nil {
731 // delete bip44 contract index
732 batch.Delete(Bip44ContractIndexKey(account.ID, false))
733 batch.Delete(Bip44ContractIndexKey(account.ID, true))
735 // delete contract index
736 batch.Delete(contractIndexKey(account.ID))
739 batch.Delete(AccountIDKey(account.ID))
740 batch.Delete(accountAliasKey(account.Alias))
741 if store.batch == nil {
747 // deleteAccountUTXOs delete account utxos by accountID
748 func (store *MockAccountStore) deleteAccountUTXOs(accountID string, batch dbm.Batch) error {
749 accountUtxoIter := store.db.IteratorPrefix([]byte(UTXOPrefix))
750 defer accountUtxoIter.Release()
752 for accountUtxoIter.Next() {
753 accountUtxo := new(acc.UTXO)
754 if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
758 if accountID == accountUtxo.AccountID {
759 batch.Delete(StandardUTXOKey(accountUtxo.OutputID))
766 // deleteAccountControlPrograms deletes account control program
767 func (store *MockAccountStore) deleteAccountControlPrograms(accountID string, batch dbm.Batch) error {
768 cps, err := store.ListControlPrograms()
774 for _, cp := range cps {
775 if cp.AccountID == accountID {
776 sha3pool.Sum256(hash[:], cp.ControlProgram)
777 batch.Delete(ContractKey(bc.NewHash(hash)))
783 // DeleteStandardUTXO delete utxo by outpu id
784 func (store *MockAccountStore) DeleteStandardUTXO(outputID bc.Hash) {
785 if store.batch == nil {
786 store.db.Delete(StandardUTXOKey(outputID))
788 store.batch.Delete(StandardUTXOKey(outputID))
792 // GetAccountByAlias get account by account alias
793 func (store *MockAccountStore) GetAccountByAlias(accountAlias string) (*acc.Account, error) {
794 accountID := store.db.Get(accountAliasKey(accountAlias))
795 if accountID == nil {
796 return nil, acc.ErrFindAccount
798 return store.GetAccountByID(string(accountID))
801 // GetAccountByID get account by accountID
802 func (store *MockAccountStore) GetAccountByID(accountID string) (*acc.Account, error) {
803 rawAccount := store.db.Get(AccountIDKey(accountID))
804 if rawAccount == nil {
805 return nil, acc.ErrFindAccount
807 account := new(acc.Account)
808 if err := json.Unmarshal(rawAccount, account); err != nil {
814 // GetAccountIndex get account index by account xpubs
815 func (store *MockAccountStore) GetAccountIndex(xpubs []chainkd.XPub) uint64 {
816 currentIndex := uint64(0)
817 if rawIndexBytes := store.db.Get(accountIndexKey(xpubs)); rawIndexBytes != nil {
818 currentIndex = common.BytesToUnit64(rawIndexBytes)
823 // GetBip44ContractIndex get bip44 contract index
824 func (store *MockAccountStore) GetBip44ContractIndex(accountID string, change bool) uint64 {
826 if rawIndexBytes := store.db.Get(Bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
827 index = common.BytesToUnit64(rawIndexBytes)
832 // GetCoinbaseArbitrary get coinbase arbitrary
833 func (store *MockAccountStore) GetCoinbaseArbitrary() []byte {
834 return store.db.Get([]byte(CoinbaseAbKey))
837 // GetContractIndex get contract index
838 func (store *MockAccountStore) GetContractIndex(accountID string) uint64 {
840 if rawIndexBytes := store.db.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
841 index = common.BytesToUnit64(rawIndexBytes)
846 // GetControlProgram get control program
847 func (store *MockAccountStore) GetControlProgram(hash bc.Hash) (*acc.CtrlProgram, error) {
848 rawProgram := store.db.Get(ContractKey(hash))
849 if rawProgram == nil {
850 return nil, acc.ErrFindCtrlProgram
852 cp := new(acc.CtrlProgram)
853 if err := json.Unmarshal(rawProgram, cp); err != nil {
859 // GetMiningAddress get mining address
860 func (store *MockAccountStore) GetMiningAddress() (*acc.CtrlProgram, error) {
861 rawCP := store.db.Get([]byte(MiningAddressKey))
863 return nil, acc.ErrFindMiningAddress
865 cp := new(acc.CtrlProgram)
866 if err := json.Unmarshal(rawCP, cp); err != nil {
872 // GetUTXO get standard utxo by id
873 func (store *MockAccountStore) GetUTXO(outid bc.Hash) (*acc.UTXO, error) {
875 if data := store.db.Get(StandardUTXOKey(outid)); data != nil {
876 return u, json.Unmarshal(data, u)
878 if data := store.db.Get(ContractUTXOKey(outid)); data != nil {
879 return u, json.Unmarshal(data, u)
881 return nil, acc.ErrMatchUTXO
884 // ListAccounts get all accounts which name prfix is id.
885 func (store *MockAccountStore) ListAccounts(id string) ([]*acc.Account, error) {
886 accounts := []*acc.Account{}
887 accountIter := store.db.IteratorPrefix(AccountIDKey(strings.TrimSpace(id)))
888 defer accountIter.Release()
890 for accountIter.Next() {
891 account := new(acc.Account)
892 if err := json.Unmarshal(accountIter.Value(), &account); err != nil {
895 accounts = append(accounts, account)
900 // ListControlPrograms get all local control programs
901 func (store *MockAccountStore) ListControlPrograms() ([]*acc.CtrlProgram, error) {
902 cps := []*acc.CtrlProgram{}
903 cpIter := store.db.IteratorPrefix([]byte(ContractPrefix))
904 defer cpIter.Release()
907 cp := new(acc.CtrlProgram)
908 if err := json.Unmarshal(cpIter.Value(), cp); err != nil {
911 cps = append(cps, cp)
916 // ListUTXOs get utxos by accountID
917 func (store *MockAccountStore) ListUTXOs() ([]*acc.UTXO, error) {
918 utxoIter := store.db.IteratorPrefix([]byte(UTXOPrefix))
919 defer utxoIter.Release()
921 utxos := []*acc.UTXO{}
922 for utxoIter.Next() {
923 utxo := new(acc.UTXO)
924 if err := json.Unmarshal(utxoIter.Value(), utxo); err != nil {
927 utxos = append(utxos, utxo)
932 // SetAccount set account account ID, account alias and raw account.
933 func (store *MockAccountStore) SetAccount(account *acc.Account) error {
934 rawAccount, err := json.Marshal(account)
936 return acc.ErrMarshalAccount
939 batch := store.db.NewBatch()
940 if store.batch != nil {
944 batch.Set(AccountIDKey(account.ID), rawAccount)
945 batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
947 if store.batch == nil {
953 // SetAccountIndex update account index
954 func (store *MockAccountStore) SetAccountIndex(account *acc.Account) {
955 currentIndex := store.GetAccountIndex(account.XPubs)
956 if account.KeyIndex > currentIndex {
957 if store.batch == nil {
958 store.db.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
960 store.batch.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
965 // SetBip44ContractIndex set contract index
966 func (store *MockAccountStore) SetBip44ContractIndex(accountID string, change bool, index uint64) {
967 if store.batch == nil {
968 store.db.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
970 store.batch.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
974 // SetCoinbaseArbitrary set coinbase arbitrary
975 func (store *MockAccountStore) SetCoinbaseArbitrary(arbitrary []byte) {
976 if store.batch == nil {
977 store.db.Set([]byte(CoinbaseAbKey), arbitrary)
979 store.batch.Set([]byte(CoinbaseAbKey), arbitrary)
983 // SetContractIndex set contract index
984 func (store *MockAccountStore) SetContractIndex(accountID string, index uint64) {
985 if store.batch == nil {
986 store.db.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
988 store.batch.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
992 // SetControlProgram set raw program
993 func (store *MockAccountStore) SetControlProgram(hash bc.Hash, program *acc.CtrlProgram) error {
994 accountCP, err := json.Marshal(program)
998 if store.batch == nil {
999 store.db.Set(ContractKey(hash), accountCP)
1001 store.batch.Set(ContractKey(hash), accountCP)
1006 // SetMiningAddress set mining address
1007 func (store *MockAccountStore) SetMiningAddress(program *acc.CtrlProgram) error {
1008 rawProgram, err := json.Marshal(program)
1013 if store.batch == nil {
1014 store.db.Set([]byte(MiningAddressKey), rawProgram)
1016 store.batch.Set([]byte(MiningAddressKey), rawProgram)
1021 // SetStandardUTXO set standard utxo
1022 func (store *MockAccountStore) SetStandardUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
1023 data, err := json.Marshal(utxo)
1027 if store.batch == nil {
1028 store.db.Set(StandardUTXOKey(outputID), data)
1030 store.batch.Set(StandardUTXOKey(outputID), data)