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 := 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([]chainkd.XPub{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(testAccount.ID, "", 1, false)
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 testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub}, 1, "testAccount", signers.BIP0044)
299 controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
304 controlProg.KeyIndex = 1
306 reg := asset.NewRegistry(testDB, chain)
307 asset := bc.AssetID{V0: 5}
309 utxos := []*account.UTXO{}
310 btmUtxo := mockUTXO(controlProg, consensus.BTMAssetID)
311 utxos = append(utxos, btmUtxo)
312 OtherUtxo := mockUTXO(controlProg, &asset)
313 utxos = append(utxos, OtherUtxo)
315 _, txData, err := mockTxData(utxos, testAccount)
320 tx := types.NewTx(*txData)
321 //block := mockSingleBlock(tx)
322 txStatus := bc.NewTransactionStatus()
323 txStatus.SetStatus(0, false)
324 w, err := NewWallet(testDB, accountManager, reg, hsm, chain, dispatcher, false)
325 go w.memPoolTxQueryLoop()
326 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: protocol.MsgNewTx}})
327 time.Sleep(time.Millisecond * 10)
328 if _, err = w.GetUnconfirmedTxByTxID(tx.ID.String()); err != nil {
329 t.Fatal("disaptch new tx msg error:", err)
331 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: protocol.MsgRemoveTx}})
332 time.Sleep(time.Millisecond * 10)
333 txs, err := w.GetUnconfirmedTxs(testAccount.ID)
335 t.Fatal("get unconfirmed tx error:", err)
339 t.Fatal("disaptch remove tx msg error")
342 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: 2}})
345 func mockUTXO(controlProg *account.CtrlProgram, assetID *bc.AssetID) *account.UTXO {
346 utxo := &account.UTXO{}
347 utxo.OutputID = bc.Hash{V0: 1}
348 utxo.SourceID = bc.Hash{V0: 2}
349 utxo.AssetID = *assetID
350 utxo.Amount = 1000000000
352 utxo.ControlProgram = controlProg.ControlProgram
353 utxo.AccountID = controlProg.AccountID
354 utxo.Address = controlProg.Address
355 utxo.ControlProgramIndex = controlProg.KeyIndex
359 func mockTxData(utxos []*account.UTXO, testAccount *account.Account) (*txbuilder.Template, *types.TxData, error) {
360 tplBuilder := txbuilder.NewBuilder(time.Now())
362 for _, utxo := range utxos {
363 txInput, sigInst, err := account.UtxoToInputs(testAccount.Signer, utxo)
367 tplBuilder.AddInput(txInput, sigInst)
369 out := &types.TxOutput{}
370 if utxo.AssetID == *consensus.BTMAssetID {
371 out = types.NewIntraChainOutput(utxo.AssetID, 100, utxo.ControlProgram)
373 out = types.NewIntraChainOutput(utxo.AssetID, utxo.Amount, utxo.ControlProgram)
375 tplBuilder.AddOutput(out)
378 return tplBuilder.Build()
381 func mockWallet(walletDB dbm.DB, account *account.Manager, asset *asset.Registry, chain *protocol.Chain, dispatcher *event.Dispatcher, txIndexFlag bool) *Wallet {
387 RecoveryMgr: newRecoveryManager(walletDB, account),
388 eventDispatcher: dispatcher,
389 TxIndexFlag: txIndexFlag,
391 wallet.txMsgSub, _ = wallet.eventDispatcher.Subscribe(protocol.TxMsgEvent{})
395 func mockSingleBlock(tx *types.Tx) *types.Block {
397 BlockHeader: types.BlockHeader{
401 Transactions: []*types.Tx{config.GenesisTx(), tx},