14 "github.com/vapor/account"
15 acc "github.com/vapor/account"
16 "github.com/vapor/asset"
17 "github.com/vapor/blockchain/query"
18 "github.com/vapor/blockchain/signers"
19 "github.com/vapor/blockchain/txbuilder"
20 "github.com/vapor/common"
21 "github.com/vapor/config"
22 "github.com/vapor/consensus"
23 "github.com/vapor/crypto/ed25519/chainkd"
24 "github.com/vapor/crypto/sha3pool"
25 dbm "github.com/vapor/database/leveldb"
26 "github.com/vapor/database/storage"
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"
32 "github.com/vapor/protocol/state"
35 func TestEncodeDecodeGlobalTxIndex(t *testing.T) {
40 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}),
44 globalTxIdx := CalcGlobalTxIndex(&want.BlockHash, want.Position)
45 blockHashGot, positionGot := parseGlobalTxIdx(globalTxIdx)
46 if *blockHashGot != want.BlockHash {
47 t.Errorf("blockHash mismatch. Get: %v. Expect: %v", *blockHashGot, want.BlockHash)
50 if positionGot != want.Position {
51 t.Errorf("position mismatch. Get: %v. Expect: %v", positionGot, want.Position)
55 func TestWalletVersion(t *testing.T) {
57 dirPath, err := ioutil.TempDir(".", "")
61 defer os.RemoveAll(dirPath)
63 testDB := dbm.NewDB("testdb", "leveldb", "temp")
64 walletStore := NewMockWalletStore(testDB)
70 dispatcher := event.NewDispatcher()
71 w := mockWallet(walletStore, nil, nil, nil, dispatcher, false)
73 walletStatus := new(StatusInfo)
74 if err := w.store.SetWalletInfo(walletStatus); err != nil {
78 status, err := w.store.GetWalletInfo()
84 if err := w.checkWalletInfo(); err != errWalletVersionMismatch {
85 t.Fatal("fail to detect legacy wallet version")
88 // lower wallet version test case
89 lowerVersion := StatusInfo{Version: currentVersion - 1}
90 if err := w.store.SetWalletInfo(&lowerVersion); err != nil {
94 status, err = w.store.GetWalletInfo()
100 if err := w.checkWalletInfo(); err != errWalletVersionMismatch {
101 t.Fatal("fail to detect expired wallet version")
105 func mockUTXO(controlProg *account.CtrlProgram, assetID *bc.AssetID) *account.UTXO {
106 utxo := &account.UTXO{}
107 utxo.OutputID = bc.Hash{V0: 1}
108 utxo.SourceID = bc.Hash{V0: 2}
109 utxo.AssetID = *assetID
110 utxo.Amount = 1000000000
112 utxo.ControlProgram = controlProg.ControlProgram
113 utxo.AccountID = controlProg.AccountID
114 utxo.Address = controlProg.Address
115 utxo.ControlProgramIndex = controlProg.KeyIndex
119 func mockTxData(utxos []*account.UTXO, testAccount *account.Account) (*txbuilder.Template, *types.TxData, error) {
120 tplBuilder := txbuilder.NewBuilder(time.Now())
122 for _, utxo := range utxos {
123 txInput, sigInst, err := account.UtxoToInputs(testAccount.Signer, utxo)
127 tplBuilder.AddInput(txInput, sigInst)
129 out := &types.TxOutput{}
130 if utxo.AssetID == *consensus.BTMAssetID {
131 out = types.NewIntraChainOutput(utxo.AssetID, 100, utxo.ControlProgram)
133 out = types.NewIntraChainOutput(utxo.AssetID, utxo.Amount, utxo.ControlProgram)
135 tplBuilder.AddOutput(out)
138 return tplBuilder.Build()
141 func mockWallet(store WalletStore, account *account.Manager, asset *asset.Registry, chain *protocol.Chain, dispatcher *event.Dispatcher, txIndexFlag bool) *Wallet {
147 RecoveryMgr: newRecoveryManager(store, account),
148 EventDispatcher: dispatcher,
149 TxIndexFlag: txIndexFlag,
151 wallet.txMsgSub, _ = wallet.EventDispatcher.Subscribe(protocol.TxMsgEvent{})
155 func mockSingleBlock(tx *types.Tx) *types.Block {
157 BlockHeader: types.BlockHeader{
161 Transactions: []*types.Tx{config.GenesisTx(), tx},
165 type mockStore struct {
170 func newMockStore(db dbm.DB) *mockStore {
176 func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
177 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
178 func (s *mockStore) GetBlockHeader(*bc.Hash) (*types.BlockHeader, error) { return nil, nil }
179 func (s *mockStore) GetStoreStatus() *protocol.BlockStoreState { return nil }
180 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
181 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
182 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
183 func (s *mockStore) GetVoteResult(uint64) (*state.VoteResult, error) { return nil, nil }
184 func (s *mockStore) GetMainChainHash(uint64) (*bc.Hash, error) { return nil, nil }
185 func (s *mockStore) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error) { return nil, nil }
186 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
187 func (s *mockStore) SaveBlockHeader(*types.BlockHeader) error { return nil }
188 func (s *mockStore) SaveChainStatus(*types.BlockHeader, *types.BlockHeader, []*types.BlockHeader, *state.UtxoViewpoint, []*state.VoteResult) error {
193 blockHeaders map[bc.Hash]*types.BlockHeader
196 func (s *mStore) BlockExist(hash *bc.Hash) bool { return false }
197 func (s *mStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
198 func (s *mStore) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) {
199 return s.blockHeaders[*hash], nil
201 func (s *mStore) GetStoreStatus() *protocol.BlockStoreState { return nil }
202 func (s *mStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
203 func (s *mStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
204 func (s *mStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
205 func (s *mStore) GetVoteResult(uint64) (*state.VoteResult, error) { return nil, nil }
206 func (s *mStore) GetMainChainHash(uint64) (*bc.Hash, error) { return nil, nil }
207 func (s *mStore) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error) { return nil, nil }
208 func (s *mStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
209 func (s *mStore) SaveBlockHeader(blockHeader *types.BlockHeader) error {
210 s.blockHeaders[blockHeader.Hash()] = blockHeader
213 func (s *mStore) SaveChainStatus(*types.BlockHeader, *types.BlockHeader, []*types.BlockHeader, *state.UtxoViewpoint, []*state.VoteResult) error {
217 //---------------------
220 ContractPrefix = "Contract:"
225 // ErrFindAccount = errors.New("Failed to find account")
226 errAccntTxIDNotFound = errors.New("account TXID not found")
227 errGetAsset = errors.New("Failed to find asset definition")
230 func accountIndexKey(xpubs []chainkd.XPub) []byte {
233 cpy := append([]chainkd.XPub{}, xpubs[:]...)
234 sort.Sort(signers.SortKeys(cpy))
235 for _, xpub := range cpy {
236 xPubs = append(xPubs, xpub[:]...)
238 sha3pool.Sum256(hash[:], xPubs)
239 return append([]byte(dbm.AccountIndexPrefix), hash[:]...)
242 func Bip44ContractIndexKey(accountID string, change bool) []byte {
243 key := append([]byte(dbm.ContractIndexPrefix), accountID...)
245 return append(key, []byte{1}...)
247 return append(key, []byte{0}...)
250 // ContractKey account control promgram store prefix
251 func ContractKey(hash bc.Hash) []byte {
252 return append([]byte(ContractPrefix), hash.Bytes()...)
255 // AccountIDKey account id store prefix
256 func AccountIDKey(accountID string) []byte {
257 return append([]byte(dbm.AccountPrefix), []byte(accountID)...)
260 // StandardUTXOKey makes an account unspent outputs key to store
261 func StandardUTXOKey(id bc.Hash) []byte {
262 return append(dbm.UTXOPrefix, id.Bytes()...)
265 // ContractUTXOKey makes a smart contract unspent outputs key to store
266 func ContractUTXOKey(id bc.Hash) []byte {
267 return append(dbm.SUTXOPrefix, id.Bytes()...)
270 func calcDeleteKey(blockHeight uint64) []byte {
271 return []byte(fmt.Sprintf("%s%016x", dbm.TxPrefix, blockHeight))
274 func calcTxIndexKey(txID string) []byte {
275 return append(dbm.TxIndexPrefix, []byte(txID)...)
278 func calcAnnotatedKey(formatKey string) []byte {
279 return append(dbm.TxPrefix, []byte(formatKey)...)
282 func calcUnconfirmedTxKey(formatKey string) []byte {
283 return append(dbm.UnconfirmedTxPrefix, []byte(formatKey)...)
286 func CalcGlobalTxIndexKey(txID string) []byte {
287 return append(dbm.GlobalTxIndexPrefix, []byte(txID)...)
290 func CalcGlobalTxIndex(blockHash *bc.Hash, position uint64) []byte {
291 txIdx := make([]byte, 40)
292 copy(txIdx[:32], blockHash.Bytes())
293 binary.BigEndian.PutUint64(txIdx[32:], position)
297 func formatKey(blockHeight uint64, position uint32) string {
298 return fmt.Sprintf("%016x%08x", blockHeight, position)
301 func contractIndexKey(accountID string) []byte {
302 return append([]byte(dbm.ContractIndexPrefix), []byte(accountID)...)
305 func accountAliasKey(name string) []byte {
306 return append([]byte(dbm.AccountAliasPrefix), []byte(name)...)
309 // MockWalletStore store wallet using leveldb
310 type MockWalletStore struct {
315 // NewMockWalletStore create new MockWalletStore struct
316 func NewMockWalletStore(db dbm.DB) *MockWalletStore {
317 return &MockWalletStore{
323 // InitBatch initial batch
324 func (store *MockWalletStore) InitBatch() error {
325 if store.batch != nil {
326 return errors.New("MockWalletStore initail fail, store batch is not nil.")
328 store.batch = store.walletDB.NewBatch()
332 // CommitBatch commit batch
333 func (store *MockWalletStore) CommitBatch() error {
334 if store.batch == nil {
335 return errors.New("MockWalletStore commit fail, store batch is nil.")
342 // DeleteContractUTXO delete contract utxo by outputID
343 func (store *MockWalletStore) DeleteContractUTXO(outputID bc.Hash) {
344 if store.batch == nil {
345 store.walletDB.Delete(ContractUTXOKey(outputID))
347 store.batch.Delete(ContractUTXOKey(outputID))
351 // DeleteRecoveryStatus delete recovery status
352 func (store *MockWalletStore) DeleteRecoveryStatus() {
353 if store.batch == nil {
354 store.walletDB.Delete(dbm.RecoveryKey)
356 store.batch.Delete(dbm.RecoveryKey)
360 // DeleteTransactions delete transactions when orphan block rollback
361 func (store *MockWalletStore) DeleteTransactions(height uint64) {
362 batch := store.walletDB.NewBatch()
363 if store.batch != nil {
366 txIter := store.walletDB.IteratorPrefix(calcDeleteKey(height))
367 defer txIter.Release()
369 tmpTx := query.AnnotatedTx{}
371 if err := json.Unmarshal(txIter.Value(), &tmpTx); err == nil {
372 batch.Delete(calcTxIndexKey(tmpTx.ID.String()))
374 batch.Delete(txIter.Key())
376 if store.batch == nil {
381 // DeleteUnconfirmedTransaction delete unconfirmed tx by txID
382 func (store *MockWalletStore) DeleteUnconfirmedTransaction(txID string) {
383 if store.batch == nil {
384 store.walletDB.Delete(calcUnconfirmedTxKey(txID))
386 store.batch.Delete(calcUnconfirmedTxKey(txID))
390 // DeleteWalletTransactions delete all txs in wallet
391 func (store *MockWalletStore) DeleteWalletTransactions() {
392 batch := store.walletDB.NewBatch()
393 if store.batch != nil {
396 txIter := store.walletDB.IteratorPrefix([]byte(dbm.TxPrefix))
397 defer txIter.Release()
400 batch.Delete(txIter.Key())
403 txIndexIter := store.walletDB.IteratorPrefix([]byte(dbm.TxIndexPrefix))
404 defer txIndexIter.Release()
406 for txIndexIter.Next() {
407 batch.Delete(txIndexIter.Key())
409 if store.batch == nil {
414 // DeleteWalletUTXOs delete all txs in wallet
415 func (store *MockWalletStore) DeleteWalletUTXOs() {
416 batch := store.walletDB.NewBatch()
417 if store.batch != nil {
420 ruIter := store.walletDB.IteratorPrefix([]byte(dbm.UTXOPrefix))
421 defer ruIter.Release()
423 batch.Delete(ruIter.Key())
426 suIter := store.walletDB.IteratorPrefix([]byte(dbm.SUTXOPrefix))
427 defer suIter.Release()
429 batch.Delete(suIter.Key())
431 if store.batch == nil {
436 // GetAsset get asset by assetID
437 func (store *MockWalletStore) GetAsset(assetID *bc.AssetID) (*asset.Asset, error) {
438 definitionByte := store.walletDB.Get(asset.ExtAssetKey(assetID))
439 if definitionByte == nil {
440 return nil, errGetAsset
442 definitionMap := make(map[string]interface{})
443 if err := json.Unmarshal(definitionByte, &definitionMap); err != nil {
446 alias := assetID.String()
447 externalAsset := &asset.Asset{
450 DefinitionMap: definitionMap,
451 RawDefinitionByte: definitionByte,
453 return externalAsset, nil
456 // GetControlProgram get raw program by hash
457 func (store *MockWalletStore) GetControlProgram(hash bc.Hash) (*acc.CtrlProgram, error) {
458 rawProgram := store.walletDB.Get(ContractKey(hash))
459 if rawProgram == nil {
460 return nil, acc.ErrFindCtrlProgram
462 accountCP := new(acc.CtrlProgram)
463 if err := json.Unmarshal(rawProgram, &accountCP); err != nil {
466 return accountCP, nil
469 // GetGlobalTransactionIndex get global tx by txID
470 func (store *MockWalletStore) GetGlobalTransactionIndex(txID string) []byte {
471 return store.walletDB.Get(CalcGlobalTxIndexKey(txID))
474 // GetStandardUTXO get standard utxo by id
475 func (store *MockWalletStore) GetStandardUTXO(outid bc.Hash) (*acc.UTXO, error) {
476 rawUTXO := store.walletDB.Get(StandardUTXOKey(outid))
478 return nil, fmt.Errorf("failed get standard UTXO, outputID: %s ", outid.String())
480 UTXO := new(acc.UTXO)
481 if err := json.Unmarshal(rawUTXO, UTXO); err != nil {
487 // GetTransaction get tx by txid
488 func (store *MockWalletStore) GetTransaction(txID string) (*query.AnnotatedTx, error) {
489 formatKey := store.walletDB.Get(calcTxIndexKey(txID))
490 if formatKey == nil {
491 return nil, errAccntTxIDNotFound
493 rawTx := store.walletDB.Get(calcAnnotatedKey(string(formatKey)))
494 tx := new(query.AnnotatedTx)
495 if err := json.Unmarshal(rawTx, tx); err != nil {
501 // GetUnconfirmedTransaction get unconfirmed tx by txID
502 func (store *MockWalletStore) GetUnconfirmedTransaction(txID string) (*query.AnnotatedTx, error) {
503 rawUnconfirmedTx := store.walletDB.Get(calcUnconfirmedTxKey(txID))
504 if rawUnconfirmedTx == nil {
505 return nil, fmt.Errorf("failed get unconfirmed tx, txID: %s ", txID)
507 tx := new(query.AnnotatedTx)
508 if err := json.Unmarshal(rawUnconfirmedTx, tx); err != nil {
514 // GetRecoveryStatus delete recovery status
515 func (store *MockWalletStore) GetRecoveryStatus() (*RecoveryState, error) {
516 rawStatus := store.walletDB.Get(dbm.RecoveryKey)
517 if rawStatus == nil {
518 return nil, ErrGetRecoveryStatus
520 state := new(RecoveryState)
521 if err := json.Unmarshal(rawStatus, state); err != nil {
527 // GetWalletInfo get wallet information
528 func (store *MockWalletStore) GetWalletInfo() (*StatusInfo, error) {
529 rawStatus := store.walletDB.Get([]byte(dbm.WalletKey))
530 if rawStatus == nil {
531 return nil, fmt.Errorf("failed get wallet info")
533 status := new(StatusInfo)
534 if err := json.Unmarshal(rawStatus, status); err != nil {
540 // ListAccountUTXOs get all account unspent outputs
541 func (store *MockWalletStore) ListAccountUTXOs(key string) ([]*acc.UTXO, error) {
542 accountUtxoIter := store.walletDB.IteratorPrefix([]byte(key))
543 defer accountUtxoIter.Release()
545 confirmedUTXOs := []*acc.UTXO{}
546 for accountUtxoIter.Next() {
547 utxo := new(acc.UTXO)
548 if err := json.Unmarshal(accountUtxoIter.Value(), utxo); err != nil {
551 confirmedUTXOs = append(confirmedUTXOs, utxo)
553 return confirmedUTXOs, nil
556 func (store *MockWalletStore) ListTransactions(accountID string, StartTxID string, count uint, unconfirmed bool) ([]*query.AnnotatedTx, error) {
557 annotatedTxs := []*query.AnnotatedTx{}
559 preFix := dbm.TxPrefix
563 startKey = calcUnconfirmedTxKey(StartTxID)
565 formatKey := store.walletDB.Get(calcTxIndexKey(StartTxID))
566 if formatKey == nil {
567 return nil, errAccntTxIDNotFound
569 startKey = calcAnnotatedKey(string(formatKey))
574 preFix = dbm.UnconfirmedTxPrefix
577 itr := store.walletDB.IteratorPrefixWithStart([]byte(preFix), startKey, true)
580 for txNum := count; itr.Next() && txNum > 0; txNum-- {
581 annotatedTx := new(query.AnnotatedTx)
582 if err := json.Unmarshal(itr.Value(), &annotatedTx); err != nil {
585 annotatedTxs = append(annotatedTxs, annotatedTx)
588 return annotatedTxs, nil
591 // ListUnconfirmedTransactions get all unconfirmed txs
592 func (store *MockWalletStore) ListUnconfirmedTransactions() ([]*query.AnnotatedTx, error) {
593 annotatedTxs := []*query.AnnotatedTx{}
594 txIter := store.walletDB.IteratorPrefix([]byte(dbm.UnconfirmedTxPrefix))
595 defer txIter.Release()
598 annotatedTx := &query.AnnotatedTx{}
599 if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
602 annotatedTxs = append(annotatedTxs, annotatedTx)
604 return annotatedTxs, nil
607 // SetAssetDefinition set assetID and definition
608 func (store *MockWalletStore) SetAssetDefinition(assetID *bc.AssetID, definition []byte) {
609 if store.batch == nil {
610 store.walletDB.Set(asset.ExtAssetKey(assetID), definition)
612 store.batch.Set(asset.ExtAssetKey(assetID), definition)
616 // SetContractUTXO set standard utxo
617 func (store *MockWalletStore) SetContractUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
618 data, err := json.Marshal(utxo)
622 if store.batch == nil {
623 store.walletDB.Set(ContractUTXOKey(outputID), data)
625 store.batch.Set(ContractUTXOKey(outputID), data)
630 // SetGlobalTransactionIndex set global tx index by blockhash and position
631 func (store *MockWalletStore) SetGlobalTransactionIndex(globalTxID string, blockHash *bc.Hash, position uint64) {
632 if store.batch == nil {
633 store.walletDB.Set(CalcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
635 store.batch.Set(CalcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
639 // SetRecoveryStatus set recovery status
640 func (store *MockWalletStore) SetRecoveryStatus(recoveryState *RecoveryState) error {
641 rawStatus, err := json.Marshal(recoveryState)
645 if store.batch == nil {
646 store.walletDB.Set(dbm.RecoveryKey, rawStatus)
648 store.batch.Set(dbm.RecoveryKey, rawStatus)
653 // SetTransaction set raw transaction by block height and tx position
654 func (store *MockWalletStore) SetTransaction(height uint64, tx *query.AnnotatedTx) error {
655 batch := store.walletDB.NewBatch()
656 if store.batch != nil {
660 rawTx, err := json.Marshal(tx)
664 batch.Set(calcAnnotatedKey(formatKey(height, tx.Position)), rawTx)
665 batch.Set(calcTxIndexKey(tx.ID.String()), []byte(formatKey(height, tx.Position)))
667 if store.batch == nil {
673 // SetUnconfirmedTransaction set unconfirmed tx by txID
674 func (store *MockWalletStore) SetUnconfirmedTransaction(txID string, tx *query.AnnotatedTx) error {
675 rawTx, err := json.Marshal(tx)
679 if store.batch == nil {
680 store.walletDB.Set(calcUnconfirmedTxKey(txID), rawTx)
682 store.batch.Set(calcUnconfirmedTxKey(txID), rawTx)
687 // SetWalletInfo get wallet information
688 func (store *MockWalletStore) SetWalletInfo(status *StatusInfo) error {
689 rawWallet, err := json.Marshal(status)
694 if store.batch == nil {
695 store.walletDB.Set([]byte(dbm.WalletKey), rawWallet)
697 store.batch.Set([]byte(dbm.WalletKey), rawWallet)
704 type MockAccountStore struct {
709 // NewAccountStore create new MockAccountStore.
710 func NewMockAccountStore(db dbm.DB) *MockAccountStore {
711 return &MockAccountStore{
717 // InitBatch initial batch
718 func (store *MockAccountStore) InitBatch() error {
719 if store.batch != nil {
720 return errors.New("MockAccountStore initail fail, store batch is not nil.")
722 store.batch = store.accountDB.NewBatch()
726 // CommitBatch commit batch
727 func (store *MockAccountStore) CommitBatch() error {
728 if store.batch == nil {
729 return errors.New("MockAccountStore commit fail, store batch is nil.")
736 // DeleteAccount set account account ID, account alias and raw account.
737 func (store *MockAccountStore) DeleteAccount(account *acc.Account) error {
738 batch := store.accountDB.NewBatch()
739 if store.batch != nil {
743 // delete account utxos
744 store.deleteAccountUTXOs(account.ID)
746 // delete account control program
747 cps, err := store.ListControlPrograms()
752 for _, cp := range cps {
753 if cp.AccountID == account.ID {
754 sha3pool.Sum256(hash[:], cp.ControlProgram)
755 batch.Delete(ContractKey(bc.NewHash(hash)))
759 // delete bip44 contract index
760 batch.Delete(Bip44ContractIndexKey(account.ID, false))
761 batch.Delete(Bip44ContractIndexKey(account.ID, true))
763 // delete contract index
764 batch.Delete(contractIndexKey(account.ID))
767 batch.Delete(AccountIDKey(account.ID))
768 batch.Delete(accountAliasKey(account.Alias))
769 if store.batch == nil {
775 // deleteAccountUTXOs delete account utxos by accountID
776 func (store *MockAccountStore) deleteAccountUTXOs(accountID string) error {
777 batch := store.accountDB.NewBatch()
778 if store.batch != nil {
782 accountUtxoIter := store.accountDB.IteratorPrefix([]byte(dbm.UTXOPrefix))
783 defer accountUtxoIter.Release()
785 for accountUtxoIter.Next() {
786 accountUtxo := &acc.UTXO{}
787 if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
790 if accountID == accountUtxo.AccountID {
791 batch.Delete(StandardUTXOKey(accountUtxo.OutputID))
795 if store.batch == nil {
801 // DeleteStandardUTXO delete utxo by outpu id
802 func (store *MockAccountStore) DeleteStandardUTXO(outputID bc.Hash) {
803 if store.batch == nil {
804 store.accountDB.Delete(StandardUTXOKey(outputID))
806 store.batch.Delete(StandardUTXOKey(outputID))
810 // GetAccountByAlias get account by account alias
811 func (store *MockAccountStore) GetAccountByAlias(accountAlias string) (*acc.Account, error) {
812 accountID := store.accountDB.Get(accountAliasKey(accountAlias))
813 if accountID == nil {
814 return nil, acc.ErrFindAccount
816 return store.GetAccountByID(string(accountID))
819 // GetAccountByID get account by accountID
820 func (store *MockAccountStore) GetAccountByID(accountID string) (*acc.Account, error) {
821 rawAccount := store.accountDB.Get(AccountIDKey(accountID))
822 if rawAccount == nil {
823 return nil, acc.ErrFindAccount
825 account := new(acc.Account)
826 if err := json.Unmarshal(rawAccount, account); err != nil {
832 // GetAccountIndex get account index by account xpubs
833 func (store *MockAccountStore) GetAccountIndex(xpubs []chainkd.XPub) uint64 {
834 currentIndex := uint64(0)
835 if rawIndexBytes := store.accountDB.Get(accountIndexKey(xpubs)); rawIndexBytes != nil {
836 currentIndex = common.BytesToUnit64(rawIndexBytes)
841 // GetBip44ContractIndex get bip44 contract index
842 func (store *MockAccountStore) GetBip44ContractIndex(accountID string, change bool) uint64 {
844 if rawIndexBytes := store.accountDB.Get(Bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
845 index = common.BytesToUnit64(rawIndexBytes)
850 // GetCoinbaseArbitrary get coinbase arbitrary
851 func (store *MockAccountStore) GetCoinbaseArbitrary() []byte {
852 return store.accountDB.Get([]byte(dbm.CoinbaseAbKey))
855 // GetContractIndex get contract index
856 func (store *MockAccountStore) GetContractIndex(accountID string) uint64 {
858 if rawIndexBytes := store.accountDB.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
859 index = common.BytesToUnit64(rawIndexBytes)
864 // GetControlProgram get control program
865 func (store *MockAccountStore) GetControlProgram(hash bc.Hash) (*acc.CtrlProgram, error) {
866 rawProgram := store.accountDB.Get(ContractKey(hash))
867 if rawProgram == nil {
868 return nil, acc.ErrFindCtrlProgram
870 cp := new(acc.CtrlProgram)
871 if err := json.Unmarshal(rawProgram, cp); err != nil {
877 // GetMiningAddress get mining address
878 func (store *MockAccountStore) GetMiningAddress() (*acc.CtrlProgram, error) {
879 rawCP := store.accountDB.Get([]byte(dbm.MiningAddressKey))
881 return nil, acc.ErrFindMiningAddress
883 cp := new(acc.CtrlProgram)
884 if err := json.Unmarshal(rawCP, cp); err != nil {
890 // GetUTXO get standard utxo by id
891 func (store *MockAccountStore) GetUTXO(outid bc.Hash) (*acc.UTXO, error) {
893 if data := store.accountDB.Get(StandardUTXOKey(outid)); data != nil {
894 return u, json.Unmarshal(data, u)
896 if data := store.accountDB.Get(ContractUTXOKey(outid)); data != nil {
897 return u, json.Unmarshal(data, u)
899 return nil, acc.ErrMatchUTXO
902 // ListAccounts get all accounts which name prfix is id.
903 func (store *MockAccountStore) ListAccounts(id string) ([]*acc.Account, error) {
904 accounts := []*acc.Account{}
905 accountIter := store.accountDB.IteratorPrefix(AccountIDKey(strings.TrimSpace(id)))
906 defer accountIter.Release()
908 for accountIter.Next() {
909 account := new(acc.Account)
910 if err := json.Unmarshal(accountIter.Value(), &account); err != nil {
913 accounts = append(accounts, account)
918 // ListControlPrograms get all local control programs
919 func (store *MockAccountStore) ListControlPrograms() ([]*acc.CtrlProgram, error) {
920 cps := []*acc.CtrlProgram{}
921 cpIter := store.accountDB.IteratorPrefix([]byte(ContractPrefix))
922 defer cpIter.Release()
925 cp := new(acc.CtrlProgram)
926 if err := json.Unmarshal(cpIter.Value(), cp); err != nil {
929 cps = append(cps, cp)
934 // ListUTXOs get utxos by accountID
935 func (store *MockAccountStore) ListUTXOs() ([]*acc.UTXO, error) {
936 utxoIter := store.accountDB.IteratorPrefix([]byte(dbm.UTXOPrefix))
937 defer utxoIter.Release()
939 utxos := []*acc.UTXO{}
940 for utxoIter.Next() {
941 utxo := new(acc.UTXO)
942 if err := json.Unmarshal(utxoIter.Value(), utxo); err != nil {
945 utxos = append(utxos, utxo)
950 // SetAccount set account account ID, account alias and raw account.
951 func (store *MockAccountStore) SetAccount(account *acc.Account) error {
952 rawAccount, err := json.Marshal(account)
954 return acc.ErrMarshalAccount
957 batch := store.accountDB.NewBatch()
958 if store.batch != nil {
962 batch.Set(AccountIDKey(account.ID), rawAccount)
963 batch.Set(accountAliasKey(account.Alias), []byte(account.ID))
965 if store.batch == nil {
971 // SetAccountIndex update account index
972 func (store *MockAccountStore) SetAccountIndex(account *acc.Account) {
973 currentIndex := store.GetAccountIndex(account.XPubs)
974 if account.KeyIndex > currentIndex {
975 if store.batch == nil {
976 store.accountDB.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
978 store.batch.Set(accountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
983 // SetBip44ContractIndex set contract index
984 func (store *MockAccountStore) SetBip44ContractIndex(accountID string, change bool, index uint64) {
985 if store.batch == nil {
986 store.accountDB.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
988 store.batch.Set(Bip44ContractIndexKey(accountID, change), common.Unit64ToBytes(index))
992 // SetCoinbaseArbitrary set coinbase arbitrary
993 func (store *MockAccountStore) SetCoinbaseArbitrary(arbitrary []byte) {
994 if store.batch == nil {
995 store.accountDB.Set([]byte(dbm.CoinbaseAbKey), arbitrary)
997 store.batch.Set([]byte(dbm.CoinbaseAbKey), arbitrary)
1001 // SetContractIndex set contract index
1002 func (store *MockAccountStore) SetContractIndex(accountID string, index uint64) {
1003 if store.batch == nil {
1004 store.accountDB.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
1006 store.batch.Set(contractIndexKey(accountID), common.Unit64ToBytes(index))
1010 // SetControlProgram set raw program
1011 func (store *MockAccountStore) SetControlProgram(hash bc.Hash, program *acc.CtrlProgram) error {
1012 accountCP, err := json.Marshal(program)
1016 if store.batch == nil {
1017 store.accountDB.Set(ContractKey(hash), accountCP)
1019 store.batch.Set(ContractKey(hash), accountCP)
1024 // SetMiningAddress set mining address
1025 func (store *MockAccountStore) SetMiningAddress(program *acc.CtrlProgram) error {
1026 rawProgram, err := json.Marshal(program)
1031 if store.batch == nil {
1032 store.accountDB.Set([]byte(dbm.MiningAddressKey), rawProgram)
1034 store.batch.Set([]byte(dbm.MiningAddressKey), rawProgram)
1039 // SetStandardUTXO set standard utxo
1040 func (store *MockAccountStore) SetStandardUTXO(outputID bc.Hash, utxo *acc.UTXO) error {
1041 data, err := json.Marshal(utxo)
1045 if store.batch == nil {
1046 store.accountDB.Set(StandardUTXOKey(outputID), data)
1048 store.batch.Set(StandardUTXOKey(outputID), data)