+func TestReportFound(t *testing.T) {
+ dirPath, err := ioutil.TempDir(".", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dirPath)
+
+ testDB := dbm.NewDB("testdb", "leveldb", dirPath)
+ hsm, err := pseudohsm.New(dirPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ xpub1, _, err := hsm.XCreate("test_pub1", "password", "en")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ xpub2, _, err := hsm.XCreate("test_pub2", "password", "en")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ acctMgr := account.NewManager(testDB, nil)
+ recoveryMgr := newRecoveryManager(testDB, acctMgr)
+ acc1 := &account.Account{ID: "testA", Alias: "test1", Signer: &signers.Signer{XPubs: []chainkd.XPub{xpub1.XPub}, KeyIndex: 1, DeriveRule: signers.BIP0044}}
+ acc2 := &account.Account{ID: "testB", Alias: "test2", Signer: &signers.Signer{XPubs: []chainkd.XPub{xpub2.XPub}, KeyIndex: 1, DeriveRule: signers.BIP0032}}
+ acc3 := &account.Account{ID: "testC", Alias: "test3", Signer: &signers.Signer{XPubs: []chainkd.XPub{xpub2.XPub}, KeyIndex: 2, DeriveRule: signers.BIP0044}}
+
+ cp1 := &account.CtrlProgram{AccountID: acc1.ID, Address: "address1", KeyIndex: 10, Change: false}
+ cp2 := &account.CtrlProgram{AccountID: acc1.ID, Address: "address1", KeyIndex: 20, Change: true}
+ cp3 := &account.CtrlProgram{AccountID: acc2.ID, Address: "address1", KeyIndex: 30, Change: false}
+ cp4 := &account.CtrlProgram{AccountID: acc2.ID, Address: "address1", KeyIndex: 40, Change: true}
+ cp5 := &account.CtrlProgram{AccountID: acc3.ID, Address: "address1", KeyIndex: 50, Change: false}
+ cp6 := &account.CtrlProgram{AccountID: acc3.ID, Address: "address1", KeyIndex: 60, Change: true}
+
+ if err := acctMgr.SaveAccount(acc2); err != nil {
+ t.Fatal("ReportFound test err:", err)
+ }
+
+ if err := acctMgr.SaveAccount(acc3); err != nil {
+ t.Fatal("ReportFound test err:", err)
+ }
+
+ recoveryMgr.state.XPubsStatus = newBranchRecoveryState(acctRecoveryWindow)
+ recoveryMgr.state.XPubs = []chainkd.XPub{xpub1.XPub}
+ recoveryMgr.state.stateForScope(acc1)
+ recoveryMgr.state.stateForScope(acc2)
+ recoveryMgr.state.stateForScope(acc3)
+
+ cases := []struct {
+ acct *account.Account
+ cp *account.CtrlProgram
+ err error
+ status *addressRecoveryState
+ }{
+ {acc1, cp1, nil,
+ &addressRecoveryState{InternalBranch: &branchRecoveryState{addrRecoveryWindow, 1, 1}, ExternalBranch: &branchRecoveryState{addrRecoveryWindow, 139, 11}, Account: acc1}},
+ {acc2, cp3, nil,
+ &addressRecoveryState{InternalBranch: &branchRecoveryState{addrRecoveryWindow, 1, 1}, ExternalBranch: &branchRecoveryState{addrRecoveryWindow, 159, 31}, Account: acc2}},
+ {acc1, cp2, nil,
+ &addressRecoveryState{InternalBranch: &branchRecoveryState{addrRecoveryWindow, 149, 21}, ExternalBranch: &branchRecoveryState{addrRecoveryWindow, 139, 11}, Account: acc1}},
+ {acc2, cp4, nil,
+ &addressRecoveryState{InternalBranch: &branchRecoveryState{addrRecoveryWindow, 169, 41}, ExternalBranch: &branchRecoveryState{addrRecoveryWindow, 159, 31}, Account: acc2}},
+ {acc3, cp5, nil,
+ &addressRecoveryState{InternalBranch: &branchRecoveryState{addrRecoveryWindow, 1, 1}, ExternalBranch: &branchRecoveryState{addrRecoveryWindow, 179, 51}, Account: acc3}},
+ {acc3, cp6, nil,
+ &addressRecoveryState{InternalBranch: &branchRecoveryState{addrRecoveryWindow, 189, 61}, ExternalBranch: &branchRecoveryState{addrRecoveryWindow, 179, 51}, Account: acc3}},
+ }
+
+ for _, c := range cases {
+ if err := recoveryMgr.reportFound(c.acct, c.cp); err != c.err {
+ t.Fatal("ReportFound test err:", err, c.acct.ID)