copay錢包(5.助記詞導(dǎo)出導(dǎo)入代碼閱讀)

傳送門
copay錢包(1.windows環(huán)境編譯運(yùn)行)
copay錢包(2.RestfulAPI初步分析)
copay錢包(3.轉(zhuǎn)賬功能報(bào)文分析)
copay錢包(4.bitcore-lib與bitcore-wallet-client類庫(kù)修改)
copay錢包(5.助記詞導(dǎo)出導(dǎo)入代碼閱讀)


導(dǎo)出入口點(diǎn)

程序中,有4個(gè)地方可以導(dǎo)出助記詞:

  1. 在最開始創(chuàng)建錢包時(shí)(BackupRequestPage)
onboarding-backup.png
  1. 在主頁(yè)查看交易明細(xì)中(WalletDetailsPage)
txdetail-backup.png
  1. 在設(shè)置頁(yè)面的錢包詳情中(WalletSettingsPage)


    setting-backup.png
  2. 在接收到Bitcoin時(shí)(ReceivePage)

其中,除了setting的備份外,其他的<div>都有用 *ngIf="wallet.needsBackup" 判斷,只要備份過一次就不會(huì)再出現(xiàn)了.

調(diào)用的形式如下:

this.navCtrl.push(BackupWarningPage, { walletId: this.walletId, fromOnboarding: true });

向BackupWarningPage傳遞錢包的id和是否從啟動(dòng)頁(yè)進(jìn)入(僅第1種為true).

導(dǎo)出BackupGamePage處理流程

導(dǎo)出流程的核心是BackupGamePage,Backup目錄的其他頁(yè)面都是提示性的,
1.頁(yè)面構(gòu)造函數(shù)

    // 從navCtrl讀取walletId參數(shù) 
    this.walletId = this.navParams.get('walletId');
    // 從navCtrl讀取fromOnboarding參數(shù) 
    this.fromOnboarding = this.navParams.get('fromOnboarding');
    // 根據(jù)walletId,獲取到當(dāng)前需要備份的wallet對(duì)象-實(shí)際可用直接把wallet傳進(jìn)來,無需在獲取一次.
    this.wallet = this.profileProvider.getWallet(this.walletId);
    // 判斷該credential是否有加密過
    this.credentialsEncrypted = this.wallet.isPrivKeyEncrypted();
    // 判斷是否手工清除過助記詞?profile編輯?
    this.deleted = this.isDeletedSeed();
    if (this.deleted) {
      this.logger.debug('no mnemonics');
      return;
    }
    // 調(diào)用walletProvider服務(wù)獲取到助記詞列表(本身profile里面就有,但是這里還是用了異步方法.)
    this.walletProvider.getKeys(this.wallet).then((keys) => {
      if (_.isEmpty(keys)) {
        this.logger.error('Empty keys');
      }
      // 能獲取到說明沒有加密
      this.credentialsEncrypted = false;
      // keys包含2部分,助記詞和privateKey
      this.keys = keys;
      // 流程控制.
      this.setFlow();
    }).catch((err) => {
      this.logger.error('Could not get keys: ', err);
      this.navCtrl.pop();
    });
  1. 流程控制函數(shù)
    // 流程控制函數(shù) 
    private setFlow(): void {
    if (!this.keys) return;
    // words為助記詞
    let words = this.keys.mnemonic;
    // profile的助記詞是用\u3000(unicode的空格)分割的.split后就變?yōu)閿?shù)組了.
    this.mnemonicWords = words.split(/[\u3000\s]+/);
    // 打亂一下順序.
    this.shuffledMnemonicWords = this.shuffledWords(this.mnemonicWords);
    // 始終為false
    this.mnemonicHasPassphrase = this.wallet.mnemonicHasPassphrase();
    this.useIdeograms = words.indexOf("\u3000") >= 0;
    this.password = '';
    this.customWords = [];
    this.selectComplete = false;
    this.error = false;
    // 把words擦掉,避免泄露
    words = _.repeat('x', 300);
    // 如果是第二頁(yè),就回退(說明輸錯(cuò)了)
    if (this.currentIndex == 2) this.slidePrev();
  }
  1. 判斷助記詞游戲是否輸入正確
    // 判斷助記詞游戲結(jié)果,返回值是一個(gè)promise
    private confirm(): Promise<any> {
    return new Promise((resolve, reject) => {
      this.error = false;
      // 把輸入框的字配在一起.
      let customWordList = _.map(this.customWords, 'word');
      // 判斷是否和記錄的助記詞一致,
      if (!_.isEqual(this.mnemonicWords, customWordList)) {
        // 調(diào)用reject()
        return reject('Mnemonic string mismatch');
      }
      // 把備份信息登記到profile中
      this.profileProvider.setBackupFlag(this.wallet.credentials.walletId);
      return resolve();
    });
  }

如圖這個(gè)備份信息并不是保存在credentials中,而是在profile的外面,根據(jù)backup-(錢包ID)鍵值保存.:


backup-profile.png

confirm()和setFlow()是由finalStep統(tǒng)一控制進(jìn)行的,如果confirm成功,就轉(zhuǎn)到BackupReadyModalPage完成備份;如果confirm不成功,就轉(zhuǎn)到setFlow(),重新開始游戲.

總的來說,copay的助記詞導(dǎo)出,還是比較方便的,有適當(dāng)?shù)奶崾?然后還有一個(gè)隨機(jī)校驗(yàn)去驗(yàn)證是否真的抄下來了,并且能有效的提示和記錄導(dǎo)出數(shù)據(jù)的結(jié)果,確實(shí)值得借鑒的,

導(dǎo)入入口點(diǎn)

程序中,有2個(gè)地方可以導(dǎo)入助記詞,使用已有錢包:

  1. 在最開始創(chuàng)建錢包時(shí)(此時(shí)還是更多導(dǎo)入形式,如多簽錢包)
onboarding-import.png
  1. 在主頁(yè)錢包列表右上角
home-import.png

調(diào)用的形式如下:

this.navCtrl.push(ImportWalletPage, { fromOnboarding: true });

向BackupWarningPage是否從啟動(dòng)頁(yè)進(jìn)入(僅第1種為true).

導(dǎo)入ImportWalletPage處理流程

實(shí)際上,有words和file兩張導(dǎo)入方式,但是導(dǎo)出并沒有file呢,那這個(gè)應(yīng)該是導(dǎo)入其他設(shè)備(如TREZOR)生成的文件.如果只是copay的使用,關(guān)注word方式即可.而代碼中,因?yàn)樾枰嫒?種方式,增加了大量的判斷分支,閱讀起來就比較累了.

  1. 從助記詞導(dǎo)入
    // 從助記詞導(dǎo)入.
    public importFromMnemonic(): void {
    // 判斷是否合法
    if (!this.importForm.valid) {
      let title = this.translate.instant('Error');
      let subtitle = this.translate.instant('There is an error in the form');
      this.popupProvider.ionicAlert(title, subtitle);
      return;
    }

    let opts: any = {};
    // 從頁(yè)面中讀取bwsURL信息,保存到opts中.
    if (this.importForm.value.bwsURL)
      opts.bwsurl = this.importForm.value.bwsURL;
    // 從頁(yè)面中讀取pathData信息,livenet為m/44'/0'/0',testnet為m/44'/1'/0',并調(diào)用derivationPathHelperProvider進(jìn)行解析.
    let pathData: any = this.derivationPathHelperProvider.parse(this.importForm.value.derivationPath);
    // 判斷解析后的衍生路徑,其值是必須的,如果沒有值,就報(bào)錯(cuò)
    if (!pathData) {
      let title = this.translate.instant('Error');
      let subtitle = this.translate.instant('Invalid derivation path');
      this.popupProvider.ionicAlert(title, subtitle);
      return;
    }
    // 從衍生路徑中獲取賬號(hào),網(wǎng)絡(luò),策略等信息
    opts.account = pathData.account;
    opts.networkName = pathData.networkName;
    opts.derivationStrategy = pathData.derivationStrategy;
    // 幣種
    opts.coin = this.importForm.value.coin;
    // 解析輸入的助記詞
    let words: string = this.importForm.value.words || null;

    if (!words) {
      let title = this.translate.instant('Error');
      let subtitle = this.translate.instant('Please enter the recovery phrase');
      this.popupProvider.ionicAlert(title, subtitle);
      return;
      // 可以直接導(dǎo)入私鑰xprv開頭(livnet),tprv開頭(testnet).
    } else if (words.indexOf('xprv') == 0 || words.indexOf('tprv') == 0) {
      return this.importExtendedPrivateKey(words, opts);
    } else {
      let wordList: any[] = words.split(/[\u3000\s]+/);
      // 初步判斷一下是否長(zhǎng)度符合.
      if ((wordList.length % 3) != 0) {
        let title = this.translate.instant('Error');
        let subtitle = this.translate.instant('Wrong number of recovery words:');
        this.popupProvider.ionicAlert(title, subtitle + ' ' + wordList.length);
        return;
      }
    }

    opts.passphrase = this.importForm.value.passphrase || null;
    // 再次調(diào)用importMnemonic完成導(dǎo)入
    this.importMnemonic(words, opts);
  }

2.具體調(diào)入代碼

    // 具體調(diào)入代碼
    private importMnemonic(words: string, opts: any): void {
    // 顯示等待框
    this.onGoingProcessProvider.set('importingWallet');
    // 用異步任務(wù)完成
    setTimeout(() => {
      // 實(shí)際是調(diào)用了profileProvider的importMnemonic()進(jìn)行具體導(dǎo)入,其內(nèi)部是通過walletClient客戶端與bws服務(wù)通訊完成的導(dǎo)入.
      this.profileProvider.importMnemonic(words, opts).then((wallet: any) => {
        this.onGoingProcessProvider.clear();
        // 調(diào)用finish()函數(shù)
        this.finish(wallet);
      }).catch((err: any) => {
        // 捕捉異常狀況
        if (err instanceof this.errors.NOT_AUTHORIZED) {
          this.importErr = true;
        } else {
          let title = this.translate.instant('Error');
          this.popupProvider.ionicAlert(title, err);
        }
        // 異常情況要清理等待框,
        this.onGoingProcessProvider.clear();
        return;
      });
    }, 100);
  }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锌介,隨后出現(xiàn)的幾起案子雨让,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡簇爆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門倾贰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冕碟,“玉大人,你說我怎么就攤上這事匆浙。” “怎么了厕妖?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵首尼,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我言秸,道長(zhǎng)软能,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任举畸,我火速辦了婚禮查排,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抄沮。我一直安慰自己跋核,他們只是感情好岖瑰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著砂代,像睡著了一般蹋订。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刻伊,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天露戒,我揣著相機(jī)與錄音,去河邊找鬼捶箱。 笑死智什,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的丁屎。 我是一名探鬼主播撩鹿,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼悦屏!你這毒婦竟也來了节沦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤础爬,失蹤者是張志新(化名)和其女友劉穎甫贯,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體看蚜,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叫搁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了供炎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渴逻。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖音诫,靈堂內(nèi)的尸體忽然破棺而出惨奕,到底是詐尸還是另有隱情,我是刑警寧澤竭钝,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布梨撞,位于F島的核電站,受9級(jí)特大地震影響香罐,放射性物質(zhì)發(fā)生泄漏卧波。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一庇茫、第九天 我趴在偏房一處隱蔽的房頂上張望港粱。 院中可真熱鬧,春花似錦旦签、人聲如沸查坪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咪惠。三九已至击吱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間遥昧,已是汗流浹背覆醇。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留炭臭,地道東北人永脓。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鞋仍,于是被迫代替她去往敵國(guó)和親常摧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 作業(yè)完成情況: 本組共有10人 應(yīng)交作業(yè)人數(shù)10人威创,實(shí)交作業(yè)人數(shù)8人落午,2人圍觀,肚豺。 應(yīng)點(diǎn)評(píng)人數(shù)8人溃斋,準(zhǔn)時(shí)點(diǎn)評(píng)人數(shù)8...
    靳仲芳1070閱讀 237評(píng)論 0 0
  • 清明雨,寒食酒吸申, 滿川荒草墳前柳梗劫。 紙錢飛,素顏泣截碴。 風(fēng)吹曠野梳侨,草沒荒冢。 慟!慟!慟! 燕又回日丹,人不再走哺。 常嘆世...
    tulipjia閱讀 378評(píng)論 0 6
  • 昨晚輾轉(zhuǎn)反側(cè),終于決定出來走一走聚凹。 早上起床割坠,我看著窗外下起了漂泊大雨。一個(gè)月都沒有下雨了妒牙,沒有想到的是此時(shí)此刻竟...
    陪月亮摘星星閱讀 343評(píng)論 12 19
  • 《待你長(zhǎng)發(fā)及腰》回一筆墨 文/青鳥白澤 待你長(zhǎng)發(fā)及腰 與卿共度良宵 西窗燭下聞窈窕 東廂案前齊眉笑 素脂...
    青春巴人閱讀 176評(píng)論 0 0