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 vcrypto "github.com/vapor/crypto"
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 := 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")
61 dispatcher := event.NewDispatcher()
62 w := mockWallet(testDB, nil, nil, nil, dispatcher, false)
64 // legacy status test case
65 type legacyStatusInfo struct {
71 rawWallet, err := json.Marshal(legacyStatusInfo{})
73 t.Fatal("Marshal legacyStatusInfo")
76 w.DB.Set(walletKey, rawWallet)
77 rawWallet = w.DB.Get(walletKey)
79 t.Fatal("fail to load wallet StatusInfo")
82 if err := json.Unmarshal(rawWallet, &w.status); err != nil {
86 if err := w.checkWalletInfo(); err != errWalletVersionMismatch {
87 t.Fatal("fail to detect legacy wallet version")
90 // lower wallet version test case
91 lowerVersion := StatusInfo{Version: currentVersion - 1}
92 rawWallet, err = json.Marshal(lowerVersion)
94 t.Fatal("save wallet info")
97 w.DB.Set(walletKey, rawWallet)
98 rawWallet = w.DB.Get(walletKey)
100 t.Fatal("fail to load wallet StatusInfo")
103 if err := json.Unmarshal(rawWallet, &w.status); err != nil {
107 if err := w.checkWalletInfo(); err != errWalletVersionMismatch {
108 t.Fatal("fail to detect expired wallet version")
112 func TestWalletUpdate(t *testing.T) {
113 dirPath, err := ioutil.TempDir(".", "")
117 defer os.RemoveAll(dirPath)
119 config.CommonConfig = config.DefaultConfig()
120 testDB := dbm.NewDB("testdb", "leveldb", "temp")
126 store := database.NewStore(testDB)
127 dispatcher := event.NewDispatcher()
128 txPool := protocol.NewTxPool(store, dispatcher)
130 chain, err := protocol.NewChain(store, txPool, dispatcher)
135 accountManager := account.NewManager(testDB, chain)
136 hsm, err := pseudohsm.New(dirPath)
141 xpub1, _, err := hsm.XCreate("test_pub1", "password", "en")
146 testAccount, err := accountManager.Create([]vcrypto.XPubKeyer{xpub1.XPub}, 1, "testAccount", signers.BIP0044)
151 controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
156 controlProg.KeyIndex = 1
158 reg := asset.NewRegistry(testDB, chain)
159 asset := bc.AssetID{V0: 5}
161 utxos := []*account.UTXO{}
162 btmUtxo := mockUTXO(controlProg, consensus.BTMAssetID)
163 utxos = append(utxos, btmUtxo)
164 OtherUtxo := mockUTXO(controlProg, &asset)
165 utxos = append(utxos, OtherUtxo)
167 _, txData, err := mockTxData(utxos, testAccount)
172 tx := types.NewTx(*txData)
173 block := mockSingleBlock(tx)
174 txStatus := bc.NewTransactionStatus()
175 txStatus.SetStatus(0, false)
176 txStatus.SetStatus(1, false)
177 store.SaveBlock(block, txStatus)
179 w := mockWallet(testDB, accountManager, reg, chain, dispatcher, true)
180 err = w.AttachBlock(block)
185 if _, err := w.GetTransactionByTxID(tx.ID.String()); err != nil {
189 wants, err := w.GetTransactions("")
194 if wants[0].ID != tx.ID {
195 t.Fatal("account txID mismatch")
198 for position, tx := range block.Transactions {
199 get := w.DB.Get(calcGlobalTxIndexKey(tx.ID.String()))
200 bh := block.BlockHeader.Hash()
201 expect := calcGlobalTxIndex(&bh, uint64(position))
202 if !reflect.DeepEqual(get, expect) {
203 t.Fatalf("position#%d: compare retrieved globalTxIdx err", position)
208 func TestRescanWallet(t *testing.T) {
209 // prepare wallet & db
210 dirPath, err := ioutil.TempDir(".", "")
214 defer os.RemoveAll(dirPath)
216 config.CommonConfig = config.DefaultConfig()
217 testDB := dbm.NewDB("testdb", "leveldb", "temp")
223 store := database.NewStore(testDB)
224 dispatcher := event.NewDispatcher()
225 txPool := protocol.NewTxPool(store, dispatcher)
226 chain, err := protocol.NewChain(store, txPool, dispatcher)
231 statusInfo := StatusInfo{
232 Version: currentVersion,
233 WorkHash: bc.Hash{V0: 0xff},
235 rawWallet, err := json.Marshal(statusInfo)
237 t.Fatal("save wallet info")
240 w := mockWallet(testDB, nil, nil, chain, dispatcher, false)
241 w.DB.Set(walletKey, rawWallet)
242 rawWallet = w.DB.Get(walletKey)
243 if rawWallet == nil {
244 t.Fatal("fail to load wallet StatusInfo")
247 if err := json.Unmarshal(rawWallet, &w.status); err != nil {
252 if err := w.loadWalletInfo(); err != nil {
256 block := config.GenesisBlock()
257 if w.status.WorkHash != block.Hash() {
258 t.Fatal("reattach from genesis block")
262 func TestMemPoolTxQueryLoop(t *testing.T) {
263 dirPath, err := ioutil.TempDir(".", "")
267 config.CommonConfig = config.DefaultConfig()
268 testDB := dbm.NewDB("testdb", "leveldb", dirPath)
271 os.RemoveAll(dirPath)
274 store := database.NewStore(testDB)
275 dispatcher := event.NewDispatcher()
276 txPool := protocol.NewTxPool(store, dispatcher)
278 chain, err := protocol.NewChain(store, txPool, dispatcher)
283 accountManager := account.NewManager(testDB, chain)
284 hsm, err := pseudohsm.New(dirPath)
289 xpub1, _, err := hsm.XCreate("test_pub1", "password", "en")
294 xpubers := make([]vcrypto.XPubKeyer, 1)
295 xpubers[0] = xpub1.XPub
297 testAccount, err := accountManager.Create(xpubers, 1, "testAccount", signers.BIP0044)
302 controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
307 controlProg.KeyIndex = 1
309 reg := asset.NewRegistry(testDB, chain)
310 asset := bc.AssetID{V0: 5}
312 utxos := []*account.UTXO{}
313 btmUtxo := mockUTXO(controlProg, consensus.BTMAssetID)
314 utxos = append(utxos, btmUtxo)
315 OtherUtxo := mockUTXO(controlProg, &asset)
316 utxos = append(utxos, OtherUtxo)
318 _, txData, err := mockTxData(utxos, testAccount)
323 tx := types.NewTx(*txData)
324 //block := mockSingleBlock(tx)
325 txStatus := bc.NewTransactionStatus()
326 txStatus.SetStatus(0, false)
327 w, err := NewWallet(testDB, accountManager, reg, hsm, chain, dispatcher, false)
328 go w.memPoolTxQueryLoop()
329 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: protocol.MsgNewTx}})
330 time.Sleep(time.Millisecond * 10)
331 if _, err = w.GetUnconfirmedTxByTxID(tx.ID.String()); err != nil {
332 t.Fatal("disaptch new tx msg error:", err)
334 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: protocol.MsgRemoveTx}})
335 time.Sleep(time.Millisecond * 10)
336 txs, err := w.GetUnconfirmedTxs(testAccount.ID)
338 t.Fatal("get unconfirmed tx error:", err)
342 t.Fatal("disaptch remove tx msg error")
345 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: 2}})
348 func mockUTXO(controlProg *account.CtrlProgram, assetID *bc.AssetID) *account.UTXO {
349 utxo := &account.UTXO{}
350 utxo.OutputID = bc.Hash{V0: 1}
351 utxo.SourceID = bc.Hash{V0: 2}
352 utxo.AssetID = *assetID
353 utxo.Amount = 1000000000
355 utxo.ControlProgram = controlProg.ControlProgram
356 utxo.AccountID = controlProg.AccountID
357 utxo.Address = controlProg.Address
358 utxo.ControlProgramIndex = controlProg.KeyIndex
362 func mockTxData(utxos []*account.UTXO, testAccount *account.Account) (*txbuilder.Template, *types.TxData, error) {
363 tplBuilder := txbuilder.NewBuilder(time.Now())
365 for _, utxo := range utxos {
366 txInput, sigInst, err := account.UtxoToInputs(testAccount.Signer, utxo)
370 tplBuilder.AddInput(txInput, sigInst)
372 out := &types.TxOutput{}
373 if utxo.AssetID == *consensus.BTMAssetID {
374 out = types.NewIntraChainOutput(utxo.AssetID, 100, utxo.ControlProgram)
376 out = types.NewIntraChainOutput(utxo.AssetID, utxo.Amount, utxo.ControlProgram)
378 tplBuilder.AddOutput(out)
381 return tplBuilder.Build()
384 func mockWallet(walletDB dbm.DB, account *account.Manager, asset *asset.Registry, chain *protocol.Chain, dispatcher *event.Dispatcher, txIndexFlag bool) *Wallet {
390 RecoveryMgr: newRecoveryManager(walletDB, account),
391 eventDispatcher: dispatcher,
392 TxIndexFlag: txIndexFlag,
394 wallet.txMsgSub, _ = wallet.eventDispatcher.Subscribe(protocol.TxMsgEvent{})
398 func mockSingleBlock(tx *types.Tx) *types.Block {
400 BlockHeader: types.BlockHeader{
404 Transactions: []*types.Tx{config.GenesisTx(), tx},