OSDN Git Service

rename (#465)
[bytom/vapor.git] / account / utxo_keeper_test.go
index bb9d010..4738c6c 100644 (file)
@@ -2,13 +2,17 @@ package account
 
 import (
        "encoding/json"
+       "io/ioutil"
        "os"
        "testing"
        "time"
 
-       dbm "github.com/vapor/database/leveldb"
-       "github.com/vapor/protocol/bc"
-       "github.com/vapor/testutil"
+       "github.com/golang/groupcache/lru"
+       "github.com/bytom/vapor/blockchain/txbuilder"
+       "github.com/bytom/vapor/crypto/ed25519/chainkd"
+       dbm "github.com/bytom/vapor/database/leveldb"
+       "github.com/bytom/vapor/protocol/bc"
+       "github.com/bytom/vapor/testutil"
 )
 
 func TestAddUnconfirmedUtxo(t *testing.T) {
@@ -273,7 +277,12 @@ func TestRemoveUnconfirmedUtxo(t *testing.T) {
 func TestReserve(t *testing.T) {
        currentHeight := func() uint64 { return 9527 }
        testDB := dbm.NewDB("testdb", "leveldb", "temp")
-       defer os.RemoveAll("temp")
+       defer func() {
+               testDB.Close()
+               os.RemoveAll("temp")
+       }()
+
+       accountStore := newMockAccountStore(testDB)
 
        cases := []struct {
                before        utxoKeeper
@@ -281,16 +290,17 @@ func TestReserve(t *testing.T) {
                err           error
                reserveAmount uint64
                exp           time.Time
+               vote          []byte
        }{
                {
                        before: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                reserved:      map[bc.Hash]uint64{},
                                reservations:  map[uint64]*reservation{},
                        },
                        after: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                reserved:      map[bc.Hash]uint64{},
                                reservations:  map[uint64]*reservation{},
@@ -300,7 +310,7 @@ func TestReserve(t *testing.T) {
                },
                {
                        before: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -313,7 +323,7 @@ func TestReserve(t *testing.T) {
                                reservations: map[uint64]*reservation{},
                        },
                        after: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -330,7 +340,7 @@ func TestReserve(t *testing.T) {
                },
                {
                        before: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -344,7 +354,7 @@ func TestReserve(t *testing.T) {
                                reservations: map[uint64]*reservation{},
                        },
                        after: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -362,7 +372,7 @@ func TestReserve(t *testing.T) {
                },
                {
                        before: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -377,7 +387,7 @@ func TestReserve(t *testing.T) {
                                reservations: map[uint64]*reservation{},
                        },
                        after: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -396,7 +406,7 @@ func TestReserve(t *testing.T) {
                },
                {
                        before: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -409,7 +419,7 @@ func TestReserve(t *testing.T) {
                                reservations: map[uint64]*reservation{},
                        },
                        after: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -442,7 +452,7 @@ func TestReserve(t *testing.T) {
                },
                {
                        before: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                nextIndex:     1,
                                unconfirmed: map[bc.Hash]*UTXO{
@@ -468,7 +478,7 @@ func TestReserve(t *testing.T) {
                                reservations: map[uint64]*reservation{},
                        },
                        after: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -516,10 +526,60 @@ func TestReserve(t *testing.T) {
                        err:           nil,
                        exp:           time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
                },
+               {
+                       before: utxoKeeper{
+                               store:         accountStore,
+                               currentHeight: currentHeight,
+                               unconfirmed: map[bc.Hash]*UTXO{
+                                       bc.NewHash([32]byte{0x01}): &UTXO{
+                                               OutputID:  bc.NewHash([32]byte{0x01}),
+                                               AccountID: "testAccount",
+                                               Amount:    3,
+                                               Vote:      []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
+                                       },
+                               },
+                               reserved:     map[bc.Hash]uint64{},
+                               reservations: map[uint64]*reservation{},
+                       },
+                       after: utxoKeeper{
+                               store:         accountStore,
+                               currentHeight: currentHeight,
+                               unconfirmed: map[bc.Hash]*UTXO{
+                                       bc.NewHash([32]byte{0x01}): &UTXO{
+                                               OutputID:  bc.NewHash([32]byte{0x01}),
+                                               AccountID: "testAccount",
+                                               Amount:    3,
+                                               Vote:      []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
+                                       },
+                               },
+                               reserved: map[bc.Hash]uint64{
+                                       bc.NewHash([32]byte{0x01}): 1,
+                               },
+                               reservations: map[uint64]*reservation{
+                                       1: &reservation{
+                                               id: 1,
+                                               utxos: []*UTXO{
+                                                       &UTXO{
+                                                               OutputID:  bc.NewHash([32]byte{0x01}),
+                                                               AccountID: "testAccount",
+                                                               Amount:    3,
+                                                               Vote:      []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
+                                                       },
+                                               },
+                                               change: 1,
+                                               expiry: time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
+                                       },
+                               },
+                       },
+                       reserveAmount: 2,
+                       err:           nil,
+                       exp:           time.Date(2016, 8, 10, 0, 0, 0, 0, time.UTC),
+                       vote:          []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
+               },
        }
 
        for i, c := range cases {
-               if _, err := c.before.Reserve("testAccount", &bc.AssetID{}, c.reserveAmount, true, c.exp); err != c.err {
+               if _, err := c.before.Reserve("testAccount", &bc.AssetID{}, c.reserveAmount, true, c.vote, c.exp); err != c.err {
                        t.Errorf("case %d: got error %v want error %v", i, err, c.err)
                }
                checkUtxoKeeperEqual(t, i, &c.before, &c.after)
@@ -531,6 +591,8 @@ func TestReserveParticular(t *testing.T) {
        testDB := dbm.NewDB("testdb", "leveldb", "temp")
        defer os.RemoveAll("temp")
 
+       accountStore := newMockAccountStore(testDB)
+
        cases := []struct {
                before      utxoKeeper
                after       utxoKeeper
@@ -540,7 +602,7 @@ func TestReserveParticular(t *testing.T) {
        }{
                {
                        before: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -555,7 +617,7 @@ func TestReserveParticular(t *testing.T) {
                                reservations: map[uint64]*reservation{},
                        },
                        after: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -574,7 +636,7 @@ func TestReserveParticular(t *testing.T) {
                },
                {
                        before: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -588,7 +650,7 @@ func TestReserveParticular(t *testing.T) {
                                reservations: map[uint64]*reservation{},
                        },
                        after: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -606,7 +668,7 @@ func TestReserveParticular(t *testing.T) {
                },
                {
                        before: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -619,7 +681,7 @@ func TestReserveParticular(t *testing.T) {
                                reservations: map[uint64]*reservation{},
                        },
                        after: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -684,7 +746,12 @@ func TestExpireReservation(t *testing.T) {
 func TestFindUtxos(t *testing.T) {
        currentHeight := func() uint64 { return 9527 }
        testDB := dbm.NewDB("testdb", "leveldb", "temp")
-       defer os.RemoveAll("temp")
+       defer func() {
+               testDB.Close()
+               os.RemoveAll("temp")
+       }()
+
+       accountStore := newMockAccountStore(testDB)
 
        cases := []struct {
                uk             utxoKeeper
@@ -692,10 +759,11 @@ func TestFindUtxos(t *testing.T) {
                useUnconfirmed bool
                wantUtxos      []*UTXO
                immatureAmount uint64
+               vote           []byte
        }{
                {
                        uk: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed:   map[bc.Hash]*UTXO{},
                        },
@@ -706,7 +774,7 @@ func TestFindUtxos(t *testing.T) {
                },
                {
                        uk: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed:   map[bc.Hash]*UTXO{},
                        },
@@ -735,7 +803,7 @@ func TestFindUtxos(t *testing.T) {
                },
                {
                        uk: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed:   map[bc.Hash]*UTXO{},
                        },
@@ -753,7 +821,7 @@ func TestFindUtxos(t *testing.T) {
                },
                {
                        uk: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -782,7 +850,7 @@ func TestFindUtxos(t *testing.T) {
                },
                {
                        uk: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x11}): &UTXO{
@@ -816,7 +884,7 @@ func TestFindUtxos(t *testing.T) {
                },
                {
                        uk: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{
@@ -858,18 +926,42 @@ func TestFindUtxos(t *testing.T) {
                        },
                        immatureAmount: 0,
                },
+               {
+                       uk: utxoKeeper{
+                               store:         accountStore,
+                               currentHeight: currentHeight,
+                               unconfirmed:   map[bc.Hash]*UTXO{},
+                       },
+                       dbUtxos: []*UTXO{
+                               &UTXO{
+                                       OutputID:  bc.NewHash([32]byte{0x01}),
+                                       AccountID: "testAccount",
+                                       Amount:    6,
+                                       Vote:      []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
+                               },
+                       },
+                       useUnconfirmed: false,
+                       wantUtxos: []*UTXO{
+                               &UTXO{
+                                       OutputID:  bc.NewHash([32]byte{0x01}),
+                                       AccountID: "testAccount",
+                                       Amount:    6,
+                                       Vote:      []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
+                               },
+                       },
+                       immatureAmount: 0,
+                       vote:           []byte("af594006a40837d9f028daabb6d589df0b9138daefad5683e5233c2646279217294a8d532e60863bcf196625a35fb8ceeffa3c09610eb92dcfb655a947f13269"),
+               },
        }
 
        for i, c := range cases {
                for _, u := range c.dbUtxos {
-                       data, err := json.Marshal(u)
-                       if err != nil {
+                       if err := c.uk.store.SetStandardUTXO(u.OutputID, u); err != nil {
                                t.Error(err)
                        }
-                       testDB.Set(StandardUTXOKey(u.OutputID), data)
                }
 
-               gotUtxos, immatureAmount := c.uk.findUtxos("testAccount", &bc.AssetID{}, c.useUnconfirmed)
+               gotUtxos, immatureAmount := c.uk.findUtxos("testAccount", &bc.AssetID{}, c.useUnconfirmed, c.vote)
                if !testutil.DeepEqual(gotUtxos, c.wantUtxos) {
                        t.Errorf("case %d: got %v want %v", i, gotUtxos, c.wantUtxos)
                }
@@ -878,16 +970,18 @@ func TestFindUtxos(t *testing.T) {
                }
 
                for _, u := range c.dbUtxos {
-                       testDB.Delete(StandardUTXOKey(u.OutputID))
+                       c.uk.store.DeleteStandardUTXO(u.OutputID)
                }
        }
 }
 
-func TestFindUtxo(t *testing.T) {
+func TestFindUTXO(t *testing.T) {
        currentHeight := func() uint64 { return 9527 }
        testDB := dbm.NewDB("testdb", "leveldb", "temp")
        defer os.RemoveAll("temp")
 
+       accountStore := newMockAccountStore(testDB)
+
        cases := []struct {
                uk             utxoKeeper
                dbUtxos        map[string]*UTXO
@@ -898,7 +992,7 @@ func TestFindUtxo(t *testing.T) {
        }{
                {
                        uk: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed:   map[bc.Hash]*UTXO{},
                        },
@@ -909,7 +1003,7 @@ func TestFindUtxo(t *testing.T) {
                },
                {
                        uk: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
@@ -923,7 +1017,7 @@ func TestFindUtxo(t *testing.T) {
                },
                {
                        uk: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed: map[bc.Hash]*UTXO{
                                        bc.NewHash([32]byte{0x01}): &UTXO{OutputID: bc.NewHash([32]byte{0x01})},
@@ -937,7 +1031,7 @@ func TestFindUtxo(t *testing.T) {
                },
                {
                        uk: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed:   map[bc.Hash]*UTXO{},
                        },
@@ -951,7 +1045,7 @@ func TestFindUtxo(t *testing.T) {
                },
                {
                        uk: utxoKeeper{
-                               db:            testDB,
+                               store:         accountStore,
                                currentHeight: currentHeight,
                                unconfirmed:   map[bc.Hash]*UTXO{},
                        },
@@ -983,7 +1077,7 @@ func TestFindUtxo(t *testing.T) {
                }
 
                for _, u := range c.dbUtxos {
-                       testDB.Delete(StandardUTXOKey(u.OutputID))
+                       c.uk.store.DeleteStandardUTXO(u.OutputID)
                }
        }
 }
@@ -1216,3 +1310,165 @@ func checkUtxoKeeperEqual(t *testing.T, i int, a, b *utxoKeeper) {
                t.Errorf("case %d: reservations got %v want %v", i, a.reservations, b.reservations)
        }
 }
+
+const (
+       utxoPrefix byte = iota //UTXOPrefix is StandardUTXOKey prefix
+       contractPrefix
+       contractIndexPrefix
+       accountPrefix // AccountPrefix is account ID prefix
+       accountIndexPrefix
+)
+
+// leveldb key prefix
+var (
+       colon               byte = 0x3a
+       accountStore             = []byte("AS:")
+       UTXOPrefix               = append(accountStore, utxoPrefix, colon)
+       ContractPrefix           = append(accountStore, contractPrefix, colon)
+       ContractIndexPrefix      = append(accountStore, contractIndexPrefix, colon)
+       AccountPrefix            = append(accountStore, accountPrefix, colon) // AccountPrefix is account ID prefix
+       AccountIndexPrefix       = append(accountStore, accountIndexPrefix, colon)
+)
+
+const (
+       sutxoPrefix byte = iota //SUTXOPrefix is ContractUTXOKey prefix
+       accountAliasPrefix
+       txPrefix            //TxPrefix is wallet database transactions prefix
+       txIndexPrefix       //TxIndexPrefix is wallet database tx index prefix
+       unconfirmedTxPrefix //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
+       globalTxIndexPrefix //GlobalTxIndexPrefix is wallet database global tx index prefix
+       walletKey
+       miningAddressKey
+       coinbaseAbKey
+       recoveryKey //recoveryKey key for db store recovery info.
+)
+
+var (
+       walletStore         = []byte("WS:")
+       SUTXOPrefix         = append(walletStore, sutxoPrefix, colon)
+       AccountAliasPrefix  = append(walletStore, accountAliasPrefix, colon)
+       TxPrefix            = append(walletStore, txPrefix, colon)            //TxPrefix is wallet database transactions prefix
+       TxIndexPrefix       = append(walletStore, txIndexPrefix, colon)       //TxIndexPrefix is wallet database tx index prefix
+       UnconfirmedTxPrefix = append(walletStore, unconfirmedTxPrefix, colon) //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
+       GlobalTxIndexPrefix = append(walletStore, globalTxIndexPrefix, colon) //GlobalTxIndexPrefix is wallet database global tx index prefix
+       WalletKey           = append(walletStore, walletKey)
+       MiningAddressKey    = append(walletStore, miningAddressKey)
+       CoinbaseAbKey       = append(walletStore, coinbaseAbKey)
+       RecoveryKey         = append(walletStore, recoveryKey)
+)
+
+type mockAccountStore struct {
+       db    dbm.DB
+       batch dbm.Batch
+}
+
+// NewAccountStore create new AccountStore.
+func newMockAccountStore(db dbm.DB) *mockAccountStore {
+       return &mockAccountStore{
+               db:    db,
+               batch: nil,
+       }
+}
+
+// StandardUTXOKey makes an account unspent outputs key to store
+func StandardUTXOKey(id bc.Hash) []byte {
+       return append(UTXOPrefix, id.Bytes()...)
+}
+
+// ContractUTXOKey makes a smart contract unspent outputs key to store
+func ContractUTXOKey(id bc.Hash) []byte {
+       return append(SUTXOPrefix, id.Bytes()...)
+}
+
+func (store *mockAccountStore) InitBatch() AccountStore                         { return nil }
+func (store *mockAccountStore) CommitBatch() error                              { return nil }
+func (store *mockAccountStore) DeleteAccount(*Account) error                    { return nil }
+func (store *mockAccountStore) GetAccountByAlias(string) (*Account, error)      { return nil, nil }
+func (store *mockAccountStore) GetAccountByID(string) (*Account, error)         { return nil, nil }
+func (store *mockAccountStore) GetAccountIndex([]chainkd.XPub) uint64           { return 0 }
+func (store *mockAccountStore) GetBip44ContractIndex(string, bool) uint64       { return 0 }
+func (store *mockAccountStore) GetCoinbaseArbitrary() []byte                    { return nil }
+func (store *mockAccountStore) GetContractIndex(string) uint64                  { return 0 }
+func (store *mockAccountStore) GetControlProgram(bc.Hash) (*CtrlProgram, error) { return nil, nil }
+func (store *mockAccountStore) GetMiningAddress() (*CtrlProgram, error)         { return nil, nil }
+func (store *mockAccountStore) ListAccounts(string) ([]*Account, error)         { return nil, nil }
+func (store *mockAccountStore) ListControlPrograms() ([]*CtrlProgram, error)    { return nil, nil }
+func (store *mockAccountStore) SetAccount(*Account) error                       { return nil }
+func (store *mockAccountStore) SetAccountIndex(*Account)                        { return }
+func (store *mockAccountStore) SetBip44ContractIndex(string, bool, uint64)      { return }
+func (store *mockAccountStore) SetCoinbaseArbitrary([]byte)                     { return }
+func (store *mockAccountStore) SetContractIndex(string, uint64)                 { return }
+func (store *mockAccountStore) SetControlProgram(bc.Hash, *CtrlProgram) error   { return nil }
+func (store *mockAccountStore) SetMiningAddress(*CtrlProgram) error             { return nil }
+
+// DeleteStandardUTXO delete utxo by outpu id
+func (store *mockAccountStore) DeleteStandardUTXO(outputID bc.Hash) {
+       if store.batch == nil {
+               store.db.Delete(StandardUTXOKey(outputID))
+       } else {
+               store.batch.Delete(StandardUTXOKey(outputID))
+       }
+}
+
+// GetUTXO get standard utxo by id
+func (store *mockAccountStore) GetUTXO(outid bc.Hash) (*UTXO, error) {
+       u := new(UTXO)
+       if data := store.db.Get(StandardUTXOKey(outid)); data != nil {
+               return u, json.Unmarshal(data, u)
+       }
+       if data := store.db.Get(ContractUTXOKey(outid)); data != nil {
+               return u, json.Unmarshal(data, u)
+       }
+       return nil, ErrMatchUTXO
+}
+
+// ListUTXOs get utxos by accountID
+func (store *mockAccountStore) ListUTXOs() ([]*UTXO, error) {
+       utxoIter := store.db.IteratorPrefix([]byte(UTXOPrefix))
+       defer utxoIter.Release()
+
+       utxos := []*UTXO{}
+       for utxoIter.Next() {
+               utxo := new(UTXO)
+               if err := json.Unmarshal(utxoIter.Value(), utxo); err != nil {
+                       return nil, err
+               }
+               utxos = append(utxos, utxo)
+       }
+       return utxos, nil
+}
+
+// SetStandardUTXO set standard utxo
+func (store *mockAccountStore) SetStandardUTXO(outputID bc.Hash, utxo *UTXO) error {
+       data, err := json.Marshal(utxo)
+       if err != nil {
+               return err
+       }
+       if store.batch == nil {
+               store.db.Set(StandardUTXOKey(outputID), data)
+       } else {
+               store.batch.Set(StandardUTXOKey(outputID), data)
+       }
+       return nil
+}
+
+func mockAccountManager(t *testing.T) *Manager {
+       dirPath, err := ioutil.TempDir(".", "")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer os.RemoveAll(dirPath)
+
+       testDB := dbm.NewDB("testdb", "memdb", dirPath)
+       accountStore := newMockAccountStore(testDB)
+       bestBlockHeight := func() uint64 { return 9527 }
+
+       return &Manager{
+               store:       accountStore,
+               chain:       nil,
+               utxoKeeper:  newUtxoKeeper(bestBlockHeight, accountStore),
+               cache:       lru.New(maxAccountCache),
+               aliasCache:  lru.New(maxAccountCache),
+               delayedACPs: make(map[*txbuilder.TemplateBuilder][]*CtrlProgram),
+       }
+}