11 "github.com/bytom/bytom/account"
12 "github.com/bytom/bytom/asset"
13 "github.com/bytom/bytom/blockchain/pseudohsm"
14 "github.com/bytom/bytom/blockchain/signers"
15 "github.com/bytom/bytom/blockchain/txbuilder"
16 "github.com/bytom/bytom/config"
17 "github.com/bytom/bytom/consensus"
18 "github.com/bytom/bytom/contract"
19 "github.com/bytom/bytom/crypto/ed25519/chainkd"
20 "github.com/bytom/bytom/database"
21 dbm "github.com/bytom/bytom/database/leveldb"
22 "github.com/bytom/bytom/event"
23 "github.com/bytom/bytom/protocol"
24 "github.com/bytom/bytom/protocol/bc"
25 "github.com/bytom/bytom/protocol/bc/types"
28 func TestEncodeDecodeGlobalTxIndex(t *testing.T) {
33 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}),
37 globalTxIdx := calcGlobalTxIndex(&want.BlockHash, want.Position)
38 blockHashGot, positionGot := parseGlobalTxIdx(globalTxIdx)
39 if *blockHashGot != want.BlockHash {
40 t.Errorf("blockHash mismatch. Get: %v. Expect: %v", *blockHashGot, want.BlockHash)
43 if positionGot != want.Position {
44 t.Errorf("position mismatch. Get: %v. Expect: %v", positionGot, want.Position)
48 func TestWalletVersion(t *testing.T) {
50 dirPath, err := ioutil.TempDir(".", "")
54 defer os.RemoveAll(dirPath)
56 testDB := dbm.NewDB("testdb", "leveldb", "temp")
57 defer os.RemoveAll("temp")
59 dispatcher := event.NewDispatcher()
60 w := mockWallet(testDB, nil, nil, nil, dispatcher, false)
62 // legacy status test case
63 type legacyStatusInfo struct {
69 rawWallet, err := json.Marshal(legacyStatusInfo{})
71 t.Fatal("Marshal legacyStatusInfo")
74 w.DB.Set(walletKey, rawWallet)
75 rawWallet = w.DB.Get(walletKey)
77 t.Fatal("fail to load wallet StatusInfo")
80 if err := json.Unmarshal(rawWallet, &w.status); err != nil {
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 rawWallet, err = json.Marshal(lowerVersion)
92 t.Fatal("save wallet info")
95 w.DB.Set(walletKey, rawWallet)
96 rawWallet = w.DB.Get(walletKey)
98 t.Fatal("fail to load wallet StatusInfo")
101 if err := json.Unmarshal(rawWallet, &w.status); err != nil {
105 if err := w.checkWalletInfo(); err != errWalletVersionMismatch {
106 t.Fatal("fail to detect expired wallet version")
110 func TestWalletUpdate(t *testing.T) {
111 dirPath, err := ioutil.TempDir(".", "")
115 defer os.RemoveAll(dirPath)
117 testDB := dbm.NewDB("testdb", "leveldb", "temp")
118 defer os.RemoveAll("temp")
120 store := database.NewStore(testDB)
121 dispatcher := event.NewDispatcher()
122 txPool := protocol.NewTxPool(store, dispatcher)
124 chain, err := protocol.NewChain(store, txPool, dispatcher)
129 accountManager := account.NewManager(testDB, chain)
130 hsm, err := pseudohsm.New(dirPath)
135 xpub1, _, err := hsm.XCreate("test_pub1", "password", "en")
140 testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub}, 1, "testAccount", signers.BIP0044)
145 controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
150 controlProg.KeyIndex = 1
152 reg := asset.NewRegistry(testDB, chain)
153 asset, err := reg.Define([]chainkd.XPub{xpub1.XPub}, 1, nil, 0, "TESTASSET", nil)
158 utxos := []*account.UTXO{}
159 btmUtxo := mockUTXO(controlProg, consensus.BTMAssetID)
160 utxos = append(utxos, btmUtxo)
161 OtherUtxo := mockUTXO(controlProg, &asset.AssetID)
162 utxos = append(utxos, OtherUtxo)
164 _, txData, err := mockTxData(utxos, testAccount)
169 tx := types.NewTx(*txData)
170 block := mockSingleBlock(tx)
171 store.SaveBlock(block)
173 w := mockWallet(testDB, accountManager, reg, chain, dispatcher, true)
174 err = w.AttachBlock(block)
179 if _, err := w.GetTransactionByTxID(tx.ID.String()); err != nil {
183 wants, err := w.GetTransactions("")
188 if wants[0].ID != tx.ID {
189 t.Fatal("account txID mismatch")
192 for position, tx := range block.Transactions {
193 get := w.DB.Get(calcGlobalTxIndexKey(tx.ID.String()))
194 bh := block.BlockHeader.Hash()
195 expect := calcGlobalTxIndex(&bh, uint64(position))
196 if !reflect.DeepEqual(get, expect) {
197 t.Fatalf("position#%d: compare retrieved globalTxIdx err", position)
202 func TestRescanWallet(t *testing.T) {
203 // prepare wallet & db
204 dirPath, err := ioutil.TempDir(".", "")
208 defer os.RemoveAll(dirPath)
210 testDB := dbm.NewDB("testdb", "leveldb", "temp")
211 defer os.RemoveAll("temp")
213 store := database.NewStore(testDB)
214 dispatcher := event.NewDispatcher()
215 txPool := protocol.NewTxPool(store, dispatcher)
216 chain, err := protocol.NewChain(store, txPool, dispatcher)
221 statusInfo := StatusInfo{
222 Version: currentVersion,
223 WorkHash: bc.Hash{V0: 0xff},
225 rawWallet, err := json.Marshal(statusInfo)
227 t.Fatal("save wallet info")
230 w := mockWallet(testDB, nil, nil, chain, dispatcher, false)
231 w.DB.Set(walletKey, rawWallet)
232 rawWallet = w.DB.Get(walletKey)
233 if rawWallet == nil {
234 t.Fatal("fail to load wallet StatusInfo")
237 if err := json.Unmarshal(rawWallet, &w.status); err != nil {
242 if err := w.loadWalletInfo(); err != nil {
246 block := config.GenesisBlock()
247 if w.status.WorkHash != block.Hash() {
248 t.Fatal("reattach from genesis block")
252 func TestMemPoolTxQueryLoop(t *testing.T) {
253 dirPath, err := ioutil.TempDir(".", "")
257 defer os.RemoveAll(dirPath)
259 testDB := dbm.NewDB("testdb", "leveldb", dirPath)
261 store := database.NewStore(testDB)
262 dispatcher := event.NewDispatcher()
263 txPool := protocol.NewTxPool(store, dispatcher)
265 chain, err := protocol.NewChain(store, txPool, dispatcher)
270 accountManager := account.NewManager(testDB, chain)
271 hsm, err := pseudohsm.New(dirPath)
276 xpub1, _, err := hsm.XCreate("test_pub1", "password", "en")
281 testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub}, 1, "testAccount", signers.BIP0044)
286 controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
291 controlProg.KeyIndex = 1
293 reg := asset.NewRegistry(testDB, chain)
294 contractReg := contract.NewRegistry(testDB)
295 asset, err := reg.Define([]chainkd.XPub{xpub1.XPub}, 1, nil, 0, "TESTASSET", nil)
300 utxos := []*account.UTXO{}
301 btmUtxo := mockUTXO(controlProg, consensus.BTMAssetID)
302 utxos = append(utxos, btmUtxo)
303 OtherUtxo := mockUTXO(controlProg, &asset.AssetID)
304 utxos = append(utxos, OtherUtxo)
306 _, txData, err := mockTxData(utxos, testAccount)
311 tx := types.NewTx(*txData)
312 //block := mockSingleBlock(tx)
313 w, err := NewWallet(testDB, accountManager, reg, contractReg, hsm, chain, dispatcher, false)
314 go w.memPoolTxQueryLoop()
315 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: protocol.MsgNewTx}})
316 time.Sleep(time.Millisecond * 10)
317 if _, err = w.GetUnconfirmedTxByTxID(tx.ID.String()); err != nil {
318 t.Fatal("disaptch new tx msg error:", err)
320 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: protocol.MsgRemoveTx}})
321 time.Sleep(time.Millisecond * 10)
322 txs, err := w.GetUnconfirmedTxs(testAccount.ID)
324 t.Fatal("get unconfirmed tx error:", err)
328 t.Fatal("disaptch remove tx msg error")
331 w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: 2}})
334 func mockUTXO(controlProg *account.CtrlProgram, assetID *bc.AssetID) *account.UTXO {
335 utxo := &account.UTXO{}
336 utxo.OutputID = bc.Hash{V0: 1}
337 utxo.SourceID = bc.Hash{V0: 2}
338 utxo.AssetID = *assetID
339 utxo.Amount = 1000000000
341 utxo.ControlProgram = controlProg.ControlProgram
342 utxo.AccountID = controlProg.AccountID
343 utxo.Address = controlProg.Address
344 utxo.ControlProgramIndex = controlProg.KeyIndex
348 func mockTxData(utxos []*account.UTXO, testAccount *account.Account) (*txbuilder.Template, *types.TxData, error) {
349 tplBuilder := txbuilder.NewBuilder(time.Now())
351 for _, utxo := range utxos {
352 txInput, sigInst, err := account.UtxoToInputs(testAccount.Signer, utxo)
356 tplBuilder.AddInput(txInput, sigInst)
358 out := &types.TxOutput{}
359 if utxo.AssetID == *consensus.BTMAssetID {
360 out = types.NewOriginalTxOutput(utxo.AssetID, 100, utxo.ControlProgram, nil)
362 out = types.NewOriginalTxOutput(utxo.AssetID, utxo.Amount, utxo.ControlProgram, nil)
364 tplBuilder.AddOutput(out)
367 return tplBuilder.Build()
370 func mockWallet(walletDB dbm.DB, account *account.Manager, asset *asset.Registry, chain *protocol.Chain, dispatcher *event.Dispatcher, txIndexFlag bool) *Wallet {
376 RecoveryMgr: newRecoveryManager(walletDB, account),
377 eventDispatcher: dispatcher,
378 TxIndexFlag: txIndexFlag,
380 wallet.txMsgSub, _ = wallet.eventDispatcher.Subscribe(protocol.TxMsgEvent{})
384 func mockSingleBlock(tx *types.Tx) *types.Block {
386 BlockHeader: types.BlockHeader{
390 Transactions: append(config.GenesisTxs(), tx),