11 "github.com/vapor/account"
12 "github.com/vapor/asset"
13 "github.com/vapor/blockchain/pseudohsm"
14 "github.com/vapor/blockchain/signers"
15 "github.com/vapor/blockchain/txbuilder"
16 "github.com/vapor/config"
17 "github.com/vapor/consensus"
18 "github.com/vapor/crypto/ed25519/chainkd"
19 "github.com/vapor/database"
20 dbm "github.com/vapor/database/leveldb"
21 "github.com/vapor/event"
22 "github.com/vapor/protocol"
23 "github.com/vapor/protocol/bc"
24 "github.com/vapor/protocol/bc/types"
27 func TestEncodeDecodeGlobalTxIndex(t *testing.T) {
32 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}),
36 globalTxIdx := database.CalcGlobalTxIndex(&want.BlockHash, want.Position)
37 blockHashGot, positionGot := parseGlobalTxIdx(globalTxIdx)
38 if *blockHashGot != want.BlockHash {
39 t.Errorf("blockHash mismatch. Get: %v. Expect: %v", *blockHashGot, want.BlockHash)
42 if positionGot != want.Position {
43 t.Errorf("position mismatch. Get: %v. Expect: %v", positionGot, want.Position)
47 func TestWalletVersion(t *testing.T) {
49 dirPath, err := ioutil.TempDir(".", "")
53 defer os.RemoveAll(dirPath)
55 testDB := dbm.NewDB("testdb", "leveldb", "temp")
56 testStore := database.NewWalletStore(testDB)
62 dispatcher := event.NewDispatcher()
63 w := mockWallet(testStore, nil, nil, nil, dispatcher, false)
65 // legacy status test case
66 type legacyStatusInfo struct {
72 rawWallet, err := json.Marshal(legacyStatusInfo{})
74 t.Fatal("Marshal legacyStatusInfo")
77 w.store.SetWalletInfo(rawWallet)
78 rawWallet = w.store.GetWalletInfo()
80 t.Fatal("fail to load wallet StatusInfo")
83 if err := json.Unmarshal(rawWallet, &w.status); err != nil {
87 if err := w.checkWalletInfo(); err != errWalletVersionMismatch {
88 t.Fatal("fail to detect legacy wallet version")
91 // lower wallet version test case
92 lowerVersion := StatusInfo{Version: currentVersion - 1}
93 rawWallet, err = json.Marshal(lowerVersion)
95 t.Fatal("save wallet info")
98 w.store.SetWalletInfo(rawWallet)
99 rawWallet = w.store.GetWalletInfo()
100 if rawWallet == nil {
101 t.Fatal("fail to load wallet StatusInfo")
104 if err := json.Unmarshal(rawWallet, &w.status); err != nil {
108 if err := w.checkWalletInfo(); err != errWalletVersionMismatch {
109 t.Fatal("fail to detect expired wallet version")
113 func TestWalletUpdate(t *testing.T) {
114 dirPath, err := ioutil.TempDir(".", "")
118 defer os.RemoveAll(dirPath)
120 config.CommonConfig = config.DefaultConfig()
121 testDB := dbm.NewDB("testdb", "leveldb", "temp")
127 store := database.NewStore(testDB)
128 testStore := database.NewWalletStore(testDB)
129 dispatcher := event.NewDispatcher()
130 txPool := protocol.NewTxPool(store, dispatcher)
132 chain, err := protocol.NewChain(store, txPool, dispatcher)
137 accountStore := database.NewAccountStore(testDB)
138 accountManager := account.NewManager(accountStore, chain)
139 hsm, err := pseudohsm.New(dirPath)
144 xpub1, _, err := hsm.XCreate("test_pub1", "password", "en")
149 testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub}, 1, "testAccount", signers.BIP0044)
154 controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
159 controlProg.KeyIndex = 1
161 reg := asset.NewRegistry(testDB, chain)
162 asset := bc.AssetID{V0: 5}
164 utxos := []*account.UTXO{}
165 btmUtxo := mockUTXO(controlProg, consensus.BTMAssetID)
166 utxos = append(utxos, btmUtxo)
167 OtherUtxo := mockUTXO(controlProg, &asset)
168 utxos = append(utxos, OtherUtxo)
170 _, txData, err := mockTxData(utxos, testAccount)
175 tx := types.NewTx(*txData)
176 block := mockSingleBlock(tx)
177 txStatus := bc.NewTransactionStatus()
178 txStatus.SetStatus(0, false)
179 txStatus.SetStatus(1, false)
180 store.SaveBlock(block, txStatus)
182 w := mockWallet(testStore, accountManager, reg, chain, dispatcher, true)
183 err = w.AttachBlock(block)
188 if _, err := w.GetTransactionByTxID(tx.ID.String()); err != nil {
192 wants, err := w.GetTransactions("")
197 if wants[0].ID != tx.ID {
198 t.Fatal("account txID mismatch")
201 for position, tx := range block.Transactions {
202 get := w.store.GetGlobalTransaction(tx.ID.String())
203 bh := block.BlockHeader.Hash()
204 expect := database.CalcGlobalTxIndex(&bh, uint64(position))
205 if !reflect.DeepEqual(get, expect) {
206 t.Fatalf("position#%d: compare retrieved globalTxIdx err", position)
211 func TestRescanWallet(t *testing.T) {
212 // prepare wallet & db
213 dirPath, err := ioutil.TempDir(".", "")
217 defer os.RemoveAll(dirPath)
219 config.CommonConfig = config.DefaultConfig()
220 testDB := dbm.NewDB("testdb", "leveldb", "temp")
221 testStore := database.NewWalletStore(testDB)
227 store := database.NewStore(testDB)
228 dispatcher := event.NewDispatcher()
229 txPool := protocol.NewTxPool(store, dispatcher)
230 chain, err := protocol.NewChain(store, txPool, dispatcher)
235 statusInfo := StatusInfo{
236 Version: currentVersion,
237 WorkHash: bc.Hash{V0: 0xff},
239 rawWallet, err := json.Marshal(statusInfo)
241 t.Fatal("save wallet info")
244 w := mockWallet(testStore, nil, nil, chain, dispatcher, false)
245 w.store.SetWalletInfo(rawWallet)
246 rawWallet = w.store.GetWalletInfo()
247 if rawWallet == nil {
248 t.Fatal("fail to load wallet StatusInfo")
251 if err := json.Unmarshal(rawWallet, &w.status); err != nil {
256 if err := w.loadWalletInfo(); err != nil {
260 block := config.GenesisBlock()
261 if w.status.WorkHash != block.Hash() {
262 t.Fatal("reattach from genesis block")
266 func TestMemPoolTxQueryLoop(t *testing.T) {
267 dirPath, err := ioutil.TempDir(".", "")
271 config.CommonConfig = config.DefaultConfig()
272 testDB := dbm.NewDB("testdb", "leveldb", dirPath)
275 os.RemoveAll(dirPath)
278 store := database.NewStore(testDB)
279 dispatcher := event.NewDispatcher()
280 txPool := protocol.NewTxPool(store, dispatcher)
282 chain, err := protocol.NewChain(store, txPool, dispatcher)
287 accountStore := database.NewAccountStore(testDB)
288 accountManager := account.NewManager(accountStore, chain)
289 hsm, err := pseudohsm.New(dirPath)
294 xpub1, _, err := hsm.XCreate("test_pub1", "password", "en")
299 testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub}, 1, "testAccount", signers.BIP0044)
304 controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
309 controlProg.KeyIndex = 1
311 reg := asset.NewRegistry(testDB, chain)
312 asset := bc.AssetID{V0: 5}
314 utxos := []*account.UTXO{}
315 btmUtxo := mockUTXO(controlProg, consensus.BTMAssetID)
316 utxos = append(utxos, btmUtxo)
317 OtherUtxo := mockUTXO(controlProg, &asset)
318 utxos = append(utxos, OtherUtxo)
320 _, txData, err := mockTxData(utxos, testAccount)
325 tx := types.NewTx(*txData)
326 //block := mockSingleBlock(tx)
327 txStatus := bc.NewTransactionStatus()
328 txStatus.SetStatus(0, false)
329 walletStore := database.NewWalletStore(testDB)
330 w, err := NewWallet(walletStore, accountManager, reg, hsm, chain, dispatcher, false)
331 go w.memPoolTxQueryLoop()
332 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: protocol.MsgNewTx}})
333 time.Sleep(time.Millisecond * 10)
334 if _, err := w.GetUnconfirmedTxByTxID(tx.ID.String()); err != nil {
335 t.Fatal("dispatch new tx msg error:", err)
337 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: protocol.MsgRemoveTx}})
338 time.Sleep(time.Millisecond * 10)
339 txs, err := w.GetUnconfirmedTxs(testAccount.ID)
341 t.Fatal("get unconfirmed tx error:", err)
345 t.Fatal("dispatch remove tx msg error")
348 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: 2}})
351 func mockUTXO(controlProg *account.CtrlProgram, assetID *bc.AssetID) *account.UTXO {
352 utxo := &account.UTXO{}
353 utxo.OutputID = bc.Hash{V0: 1}
354 utxo.SourceID = bc.Hash{V0: 2}
355 utxo.AssetID = *assetID
356 utxo.Amount = 1000000000
358 utxo.ControlProgram = controlProg.ControlProgram
359 utxo.AccountID = controlProg.AccountID
360 utxo.Address = controlProg.Address
361 utxo.ControlProgramIndex = controlProg.KeyIndex
365 func mockTxData(utxos []*account.UTXO, testAccount *account.Account) (*txbuilder.Template, *types.TxData, error) {
366 tplBuilder := txbuilder.NewBuilder(time.Now())
368 for _, utxo := range utxos {
369 txInput, sigInst, err := account.UtxoToInputs(testAccount.Signer, utxo)
373 tplBuilder.AddInput(txInput, sigInst)
375 out := &types.TxOutput{}
376 if utxo.AssetID == *consensus.BTMAssetID {
377 out = types.NewIntraChainOutput(utxo.AssetID, 100, utxo.ControlProgram)
379 out = types.NewIntraChainOutput(utxo.AssetID, utxo.Amount, utxo.ControlProgram)
381 tplBuilder.AddOutput(out)
384 return tplBuilder.Build()
387 func mockWallet(store WalletStorer, account *account.Manager, asset *asset.Registry, chain *protocol.Chain, dispatcher *event.Dispatcher, txIndexFlag bool) *Wallet {
393 RecoveryMgr: newRecoveryManager(store, account),
394 eventDispatcher: dispatcher,
395 TxIndexFlag: txIndexFlag,
397 wallet.txMsgSub, _ = wallet.eventDispatcher.Subscribe(protocol.TxMsgEvent{})
401 func mockSingleBlock(tx *types.Tx) *types.Block {
403 BlockHeader: types.BlockHeader{
407 Transactions: []*types.Tx{config.GenesisTx(), tx},