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 {
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 {
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)
}
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)
}
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 {
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
}
Height: 1,
Bits: 2305843009230471167,
},
- Transactions: []*types.Tx{tx},
+ Transactions: []*types.Tx{config.GenesisTx(), tx},
}
}