OSDN Git Service

Merge pull request #1721 from Bytom/politic-dashboard
[bytom/bytom.git] / wallet / wallet_test.go
index 4ba4ce7..44349d0 100644 (file)
@@ -1,28 +1,90 @@
 package wallet
 
 import (
-       "context"
+       "encoding/json"
        "io/ioutil"
        "os"
        "testing"
        "time"
 
-       "github.com/tendermint/go-wire/data/base58"
-       dbm "github.com/tendermint/tmlibs/db"
-
        "github.com/bytom/account"
        "github.com/bytom/asset"
        "github.com/bytom/blockchain/pseudohsm"
+       "github.com/bytom/blockchain/signers"
        "github.com/bytom/blockchain/txbuilder"
+       "github.com/bytom/config"
        "github.com/bytom/consensus"
        "github.com/bytom/crypto/ed25519/chainkd"
-       "github.com/bytom/crypto/sha3pool"
-       "github.com/bytom/database/leveldb"
+       "github.com/bytom/database"
+       dbm "github.com/bytom/database/leveldb"
+       "github.com/bytom/event"
        "github.com/bytom/protocol"
        "github.com/bytom/protocol/bc"
        "github.com/bytom/protocol/bc/types"
 )
 
+func TestWalletVersion(t *testing.T) {
+       // prepare wallet
+       dirPath, err := ioutil.TempDir(".", "")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer os.RemoveAll(dirPath)
+
+       testDB := dbm.NewDB("testdb", "leveldb", "temp")
+       defer os.RemoveAll("temp")
+
+       dispatcher := event.NewDispatcher()
+       w := mockWallet(testDB, nil, nil, nil, dispatcher, false)
+
+       // legacy status test case
+       type legacyStatusInfo struct {
+               WorkHeight uint64
+               WorkHash   bc.Hash
+               BestHeight uint64
+               BestHash   bc.Hash
+       }
+       rawWallet, err := json.Marshal(legacyStatusInfo{})
+       if err != nil {
+               t.Fatal("Marshal legacyStatusInfo")
+       }
+
+       w.DB.Set(walletKey, rawWallet)
+       rawWallet = w.DB.Get(walletKey)
+       if rawWallet == nil {
+               t.Fatal("fail to load wallet StatusInfo")
+       }
+
+       if err := json.Unmarshal(rawWallet, &w.status); err != nil {
+               t.Fatal(err)
+       }
+
+       if err := w.checkWalletInfo(); err != errWalletVersionMismatch {
+               t.Fatal("fail to detect legacy wallet version")
+       }
+
+       // lower wallet version test case
+       lowerVersion := StatusInfo{Version: currentVersion - 1}
+       rawWallet, err = json.Marshal(lowerVersion)
+       if err != nil {
+               t.Fatal("save wallet info")
+       }
+
+       w.DB.Set(walletKey, rawWallet)
+       rawWallet = w.DB.Get(walletKey)
+       if rawWallet == nil {
+               t.Fatal("fail to load wallet StatusInfo")
+       }
+
+       if err := json.Unmarshal(rawWallet, &w.status); err != nil {
+               t.Fatal(err)
+       }
+
+       if err := w.checkWalletInfo(); err != errWalletVersionMismatch {
+               t.Fatal("fail to detect expired wallet version")
+       }
+}
+
 func TestWalletUpdate(t *testing.T) {
        dirPath, err := ioutil.TempDir(".", "")
        if err != nil {
@@ -33,8 +95,9 @@ func TestWalletUpdate(t *testing.T) {
        testDB := dbm.NewDB("testdb", "leveldb", "temp")
        defer os.RemoveAll("temp")
 
-       store := leveldb.NewStore(testDB)
-       txPool := protocol.NewTxPool()
+       store := database.NewStore(testDB)
+       dispatcher := event.NewDispatcher()
+       txPool := protocol.NewTxPool(store, dispatcher)
 
        chain, err := protocol.NewChain(store, txPool)
        if err != nil {
@@ -47,17 +110,17 @@ func TestWalletUpdate(t *testing.T) {
                t.Fatal(err)
        }
 
-       xpub1, err := hsm.XCreate("test_pub1", "password")
+       xpub1, _, err := hsm.XCreate("test_pub1", "password", "en")
        if err != nil {
                t.Fatal(err)
        }
 
-       testAccount, err := accountManager.Create(nil, []chainkd.XPub{xpub1.XPub}, 1, "testAccount")
+       testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub}, 1, "testAccount", signers.BIP0044)
        if err != nil {
                t.Fatal(err)
        }
 
-       controlProg, err := accountManager.CreateAddress(nil, testAccount.ID, false)
+       controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
        if err != nil {
                t.Fatal(err)
        }
@@ -65,7 +128,7 @@ func TestWalletUpdate(t *testing.T) {
        controlProg.KeyIndex = 1
 
        reg := asset.NewRegistry(testDB, chain)
-       asset, err := reg.Define([]chainkd.XPub{xpub1.XPub}, 1, nil, "TESTASSET")
+       asset, err := reg.Define([]chainkd.XPub{xpub1.XPub}, 1, nil, 0, "TESTASSET", nil)
        if err != nil {
                t.Fatal(err)
        }
@@ -84,118 +147,111 @@ func TestWalletUpdate(t *testing.T) {
        tx := types.NewTx(*txData)
        block := mockSingleBlock(tx)
        txStatus := bc.NewTransactionStatus()
+       txStatus.SetStatus(0, false)
+       txStatus.SetStatus(1, false)
        store.SaveBlock(block, txStatus)
 
-       w := mockWallet(testDB, accountManager, reg, chain)
+       w := mockWallet(testDB, accountManager, reg, chain, dispatcher, true)
        err = w.AttachBlock(block)
        if err != nil {
                t.Fatal(err)
        }
 
-       want, err := w.GetTransactionsByTxID(tx.ID.String())
-       if len(want) != 1 {
+       if _, err := w.GetTransactionByTxID(tx.ID.String()); err != nil {
                t.Fatal(err)
        }
 
-       wants, err := w.GetTransactionsByTxID("")
+       wants, err := w.GetTransactions("")
        if len(wants) != 1 {
                t.Fatal(err)
        }
+
+       if wants[0].ID != tx.ID {
+               t.Fatal("account txID mismatch")
+       }
 }
 
-func TestExportAndImportPrivKey(t *testing.T) {
+func TestMemPoolTxQueryLoop(t *testing.T) {
        dirPath, err := ioutil.TempDir(".", "")
        if err != nil {
                t.Fatal(err)
        }
        defer os.RemoveAll(dirPath)
 
-       testDB := dbm.NewDB("testdb", "leveldb", "temp")
-       defer os.RemoveAll("temp")
+       testDB := dbm.NewDB("testdb", "leveldb", dirPath)
 
-       store := leveldb.NewStore(testDB)
-       txPool := protocol.NewTxPool()
+       store := database.NewStore(testDB)
+       dispatcher := event.NewDispatcher()
+       txPool := protocol.NewTxPool(store, dispatcher)
 
        chain, err := protocol.NewChain(store, txPool)
        if err != nil {
                t.Fatal(err)
        }
 
-       acntManager := account.NewManager(testDB, chain)
-       reg := asset.NewRegistry(testDB, chain)
-
+       accountManager := account.NewManager(testDB, chain)
        hsm, err := pseudohsm.New(dirPath)
        if err != nil {
                t.Fatal(err)
        }
 
-       pwd := "password"
-       xpub, err := hsm.XCreate("alias", pwd)
+       xpub1, _, err := hsm.XCreate("test_pub1", "password", "en")
        if err != nil {
                t.Fatal(err)
        }
 
-       w, err := NewWallet(testDB, acntManager, reg, hsm, chain)
+       testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub}, 1, "testAccount", signers.BIP0044)
        if err != nil {
                t.Fatal(err)
        }
 
-       ctx := context.Background()
-       acnt1, err := w.AccountMgr.Create(ctx, []chainkd.XPub{xpub.XPub}, 1, "account-alias")
+       controlProg, err := accountManager.CreateAddress(testAccount.ID, false)
        if err != nil {
                t.Fatal(err)
        }
 
-       priv, err := w.ExportAccountPrivKey(xpub.XPub, pwd)
+       controlProg.KeyIndex = 1
 
-       wantPriv, err := hsm.LoadChainKDKey(xpub.XPub, pwd)
+       reg := asset.NewRegistry(testDB, chain)
+       asset, err := reg.Define([]chainkd.XPub{xpub1.XPub}, 1, nil, 0, "TESTASSET", nil)
        if err != nil {
                t.Fatal(err)
        }
-       var hashed [32]byte
-       sha3pool.Sum256(hashed[:], wantPriv[:])
-
-       tmp := append(wantPriv[:], hashed[:4]...)
-       res := base58.Encode(tmp)
 
-       if res != *priv {
-               t.Fatalf("XPrivs should be identical.\nBefore: %v\n After: %v\n", *priv, res)
-       }
+       utxos := []*account.UTXO{}
+       btmUtxo := mockUTXO(controlProg, consensus.BTMAssetID)
+       utxos = append(utxos, btmUtxo)
+       OtherUtxo := mockUTXO(controlProg, &asset.AssetID)
+       utxos = append(utxos, OtherUtxo)
 
-       rawPriv, err := base58.Decode(*priv)
+       _, txData, err := mockTxData(utxos, testAccount)
        if err != nil {
                t.Fatal(err)
        }
 
-       if len(rawPriv) != 68 {
-               t.Fatal("invalid private key hash length")
-       }
-
-       var xprv [64]byte
-       copy(xprv[:], rawPriv[:64])
-
-       _, err = w.ImportAccountPrivKey(xprv, xpub.Alias, pwd, 0, acnt1.Alias)
-       if err != pseudohsm.ErrDuplicateKeyAlias {
-               t.Fatal(err)
-       }
-
-       hsm.XDelete(xpub.XPub, pwd)
-
-       _, err = w.ImportAccountPrivKey(xprv, xpub.Alias, pwd, 0, acnt1.Alias)
-       if err != account.ErrDuplicateAlias {
-               t.Fatal(err)
+       tx := types.NewTx(*txData)
+       //block := mockSingleBlock(tx)
+       txStatus := bc.NewTransactionStatus()
+       txStatus.SetStatus(0, false)
+       w, err := NewWallet(testDB, accountManager, reg, hsm, chain, dispatcher, false)
+       go w.memPoolTxQueryLoop()
+       w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: protocol.MsgNewTx}})
+       time.Sleep(time.Millisecond * 10)
+       if _, err = w.GetUnconfirmedTxByTxID(tx.ID.String()); err != nil {
+               t.Fatal("disaptch new tx msg error:", err)
        }
-
-       w.AccountMgr.DeleteAccount(acnt1.Alias)
-
-       acnt2, err := w.ImportAccountPrivKey(xprv, xpub.Alias, pwd, 0, acnt1.Alias)
+       w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: protocol.MsgRemoveTx}})
+       time.Sleep(time.Millisecond * 10)
+       txs, err := w.GetUnconfirmedTxs(testAccount.ID)
        if err != nil {
-               t.Fatal(err)
+               t.Fatal("get unconfirmed tx error:", err)
        }
 
-       if acnt2.XPub != acnt1.XPubs[0] {
-               t.Fatalf("XPubs should be identical.\nBefore: %v\n After: %v\n", acnt1.XPubs[0], acnt2.XPub)
+       if len(txs) != 0 {
+               t.Fatal("disaptch remove tx msg error")
        }
+
+       w.eventDispatcher.Post(protocol.TxMsgEvent{TxMsg: &protocol.TxPoolMsg{TxDesc: &protocol.TxDesc{Tx: tx}, MsgType: 2}})
 }
 
 func mockUTXO(controlProg *account.CtrlProgram, assetID *bc.AssetID) *account.UTXO {
@@ -234,17 +290,17 @@ func mockTxData(utxos []*account.UTXO, testAccount *account.Account) (*txbuilder
        return tplBuilder.Build()
 }
 
-func mockWallet(walletDB dbm.DB, account *account.Manager, asset *asset.Registry, chain *protocol.Chain) *Wallet {
+func mockWallet(walletDB dbm.DB, account *account.Manager, asset *asset.Registry, chain *protocol.Chain, dispatcher *event.Dispatcher, txIndexFlag bool) *Wallet {
        wallet := &Wallet{
-               DB:                  walletDB,
-               AccountMgr:          account,
-               AssetReg:            asset,
-               chain:               chain,
-               rescanProgress:      make(chan struct{}, 1),
-       }
-       wallet.status = StatusInfo{
-               OnChainAddresses: NewAddressSet(),
+               DB:              walletDB,
+               AccountMgr:      account,
+               AssetReg:        asset,
+               chain:           chain,
+               RecoveryMgr:     newRecoveryManager(walletDB, account),
+               eventDispatcher: dispatcher,
+               TxIndexFlag:     txIndexFlag,
        }
+       wallet.txMsgSub, _ = wallet.eventDispatcher.Subscribe(protocol.TxMsgEvent{})
        return wallet
 }
 
@@ -255,6 +311,6 @@ func mockSingleBlock(tx *types.Tx) *types.Block {
                        Height:  1,
                        Bits:    2305843009230471167,
                },
-               Transactions: []*types.Tx{tx},
+               Transactions: []*types.Tx{config.GenesisTx(), tx},
        }
 }