1. 程式人生 > >Electrum 錢包原始碼解讀(二)

Electrum 錢包原始碼解讀(二)

前言

程式碼地址如下:

下面開始程式碼的執行。

在路徑electrum-master下找到 run_electrum 檔案,將檔案中的所有方法逐一打上斷點之後,使用Run->Toggle Line Breakpoint 後 debug 來逐行執行,可以看到程式碼的執行順序:

  1. if is_local or is_android
    a. 用於判斷是在本地執行或者是在安卓端執行,如果是其中的一項,則將 script_dir + 'packages’這個路徑加入 sys.path中
    b. 由於是在本地執行所以此時 is_local=true,is _android=false

在匯入這幾個依賴是有幾個需要注意的地方

  1. if not is_android:該方法的執行是基於第一步的判斷
    a. 隨後開始跳轉到 check_imports() 方法

  2. def check_imports():

    1. 程式會在這個方法中檢查try_catch 中的幾個依賴是否匯入,如果沒有匯入,程式會報錯
    2. 在匯入這幾個依賴是有幾個需要注意的地方
      1. 可以使用本機的終端會cmd工具來匯入,也可以使用PyCharm自帶的 Terminal終端工具進行命令列的執行
      2. 如果發現某個依賴找不到,可以使用pip search <model_name> 進行查詢
      3. 在匯入 dns 這個依賴時,應該使用 pip install dnsPython
        而不是 pip install dns
      4. 匯入 google.protobuf ,使用 pip install protobuf
    3. 之後程式會順序執行 Line67- Line324, 直至進入 Line-327
  3. if __name__ == '__main__':

    1. 該方法為程式的主入口方法,進入該方法後程序會檢查當前環境的各種配置如:wallet_path、testnet、cmd 等
    2. 此時程式會進入 if cmdname== 'gui':
    3. 而後執行
      • d.init_gui(config, plugins)
      • 進而跳轉到
      • daemon.py --> def init_gui(self, config, plugins):
        在此方法中進行 gui 的初始化操作
  4. daemon.py 檔案中的 def init_gui(self, config, plugins):

    1. 在此方法中會首先進行 ‘gui’ 物件的例項化

      • self.gui = gui.ElectrumGui(config, self, plugins)
      • 例項化方法在 _init_.py 中的
      • def __init__(self, config, daemon, plugins):
      • 而後程式會返回daemon.py 檔案中的 def init_gui(self, config, plugins):
      • 去執行 try: self.gui.main()
      • 即跳轉到_init_.py 中的 def main(self):方法中,程式碼如下:
      def main(self):
          try:
              self.init_network()
          except UserCancelled:
              return
          except GoBack:
              return
          except BaseException as e:
              traceback.print_exc(file=sys.stdout)
              return
          self.timer.start()
          self.config.open_last_wallet()
          path = self.config.get_wallet_path()
          if not self.start_new_window(path, self.config.get('url'), app_is_starting=True):
              return
          signal.signal(signal.SIGINT, lambda *args: self.app.quit())
      
          def quit_after_last_window():
              # on some platforms, not only does exec_ not return but not even
              # aboutToQuit is emitted (but following this, it should be emitted)
              if self.app.quitOnLastWindowClosed():
                  self.app.quit()
          self.app.lastWindowClosed.connect(quit_after_last_window)
      
          def clean_up():
              # Shut down the timer cleanly
              self.timer.stop()
              # clipboard persistence. see http://www.mail-archive.com/[email protected]/msg17328.html
              event = QtCore.QEvent(QtCore.QEvent.Clipboard)
              self.app.sendEvent(self.app.clipboard(), event)
              self.tray.hide()
          self.app.aboutToQuit.connect(clean_up)
      
          # main loop
          self.app.exec_()
          # on some platforms the exec_ call may not return, so use clea
      
    2. 在此方法中,程式會根據本地的路徑來判斷是否已存在錢包,如存在則開啟,不存在則建立新錢包

      1. 首先建立錢包的UI —
      path = self.config.get_wallet_path()
      if not self.start_new_window(path, self.config.get('url'), app_is_starting=True):
      
      1. 隨後程式會跳轉到_init_.py 中的
      def start_new_window(self, path, uri, app_is_starting=False):
      
      1. start_new_window方法中,程式會再次在本地路徑中判斷錢包是否存在,如果不存在,則執行
      storage = WalletStorage(path, manual_upgrades=True)
      wizard = InstallWizard(self.config, self.app, self.plugins, storage)
      
      1. 此時程式會跳轉到 installwizard.py 檔案中執行例項化方法def __init__(self, config, app, plugins, storage):

        1. 在這份程式碼中首先執行BaseWizard.__init__(self, config, plugins, storage)
          • 改方法存在於base_wizard.py
        2. 在此方法中我們可以修改部分UI,例如錢包的名稱:
        self.setWindowTitle('HxWallet  -  ' + _('Install Wizard'))
        
      2. def __init__(self, config, app, plugins, storage):方法中,程式會順序執行到self.show() 此時 gui畫面會開始展示。

      3. 此時程式會跳轉到 _init_.py 檔案中 執行

        try:
            wallet = wizard.run_and_get_wallet(self.daemon.get_wallet)
        

        在這裡來執行一些針對gui上點選事件的操作,例如:使用者點選了 ‘取消’ 、‘返回’ 等按鈕。
        繼而,跳轉到 installwizard.py 檔案中 的 def run_and_get_wallet(self, get_wallet_from_daemon):方法中。

      4. def run_and_get_wallet(self, get_wallet_from_daemon): 方法中會針對使用者的選擇例如使用者的錢包是否存在進行一些判斷。

      5. 在UI上點選了 Next 按鈕之後,程式會跳轉到

        • installwizard.py檔案中的 if self.storage.requires_split():
        • 而後繼續順序執行至:self.run(action)
      6. 此後,程式跳轉至base_wizard.py 中的 def new(self):方法,並在此方法中進行UI的初始化工作,初始化完成後,UI上回展示 讓使用者來選擇希望建立的錢包型別。

      7. 選擇了其中一項並點選next按鈕之後,程式會執行

        def on_wallet_type(self, choice):
           self.wallet_type = choice
           if choice == 'standard':
               action = 'choose_keystore'
           elif choice == 'multisig':
               action = 'choose_multisig'
           elif choice == '2fa':
               self.load_2fa()
               action = self.storage.get_action()
           elif choice == 'imported':
               action = 'import_addresses_or_keys'
           self.run(action)
        

        在這裡選擇第一項Standard wallet,而後點選 Next

      8. 隨後程式會執行 def choose_keystore(self):方法來讓使用者選擇建立種子或使用已有種子來恢復一個錢包,

        • 在彈出的選擇頁面上選擇Create a new seed ,而後點選 Next,
        • 程式會執行base_wizard.py 檔案中的def run(self, *args):
        • 在條件判斷
        elif hasattr(self, action):
           f = getattr(self, action)
           f(*args
        

        中執行跳轉至:def choose_seed_type(self):

      9. 此時程式跳轉到 installwizard.py 檔案中的 def wizard_dialog(func): ,隨後在執行

        try:
            out = func(*args, **kwargs)
        

        時跳轉到 Seed 型別的選擇頁面 Choose Seed type

        • 在這裡選擇: Standard 並點選Next 按鈕
        • 程式進入base_wizard.py 中的
        • def create_standard_seed(self): self.create_seed('standard') 方法
        • 然後再次進入 installwizard.py 檔案中的 def wizard_dialog(func):
        • 此時UI頁面會跳轉到 seed 的顯示及提示頁面。
        • 在此UI頁面上點選Next 按鈕,程式會跳轉到installwizard.py 中的
          if type(out) is not tuple:
              out = (out,)
          run_next(*out)
          

        進而執行base_wizard.py 中的

        • def request_passphrase(self, seed, opt_passphrase):
        • def confirm_seed(self, seed, passphrase):
        • 後 再次進入 installwizard.py 中的 def wizard_dialog(func)

        之後UI跳轉至Confirm Seed 頁面

      10. 在輸入框中輸入Seed 後點擊Next 後程序跳轉至base_wizard.py中的def confirm_passphrase(self, seed, passphrase):

      11. 隨後程式進入 def create_keystore(self, seed, passphrase): 建立祕鑰

        • 中進行一系列的判斷,如果條件滿足,則進行錢包的建立
        • base_wizard.py —> def create_wallet(self):
        • 在此方法中程式會先判斷錢包有無密碼,若沒有,則執行 self.request_password
        • 來跳轉到UI密碼設定頁面
        • 而後執行def on_password(self, password, *, encrypt_storage, storage_enc_version=STO_EV_USER_PW, encrypt_keystore):
        • 進行密碼的設定
      12. 然後程式順序執行到self.run('create_addresses') 來建立地址

      13. 此方法的定義在 base_wizard.pydef create_addresses(self):

      14. 程式再次回到_init_.py --> w = self.create_window_for_wallet(wallet)

      15. _init_.py --> def create_window_for_wallet(self, wallet):

      16. 程式再次執行 _init_.py --> if not self.start_new_window(path, self.config.get('url'), app_is_starting=True):

        • 而後繼續順序執行值 self.app.exec_()
  5. 至此,一個stantard 型別的錢包建立完畢,也可以看到完整的,包含History Send Receive的UI介面出現

相關推薦

Electrum 錢包原始碼解讀

前言 程式碼地址如下: 下面開始程式碼的執行。 在路徑electrum-master下找到 run_electrum 檔案,將檔案中的所有方法逐一打上斷點之後,使用Run->Toggle Line Breakpoint 後 debug 來逐行執行,可以

Netty原始碼解讀Netty中的buffer

感謝網友【黃億華】投遞本稿。 上一篇文章我們概要介紹了Netty的原理及結構,下面幾篇文章我們開始對Netty的各個模組進行比較詳細的分析。Netty的結構最底層是buffer模組,這部分也相對獨立,我們就先從buffer講起。 What: buffer二三事 buffer中文名又叫緩衝區,按

安卓andbase框架原始碼解讀

上一次分析了andbase框架的AbActivity 安卓andbase框架原始碼解讀(一),不知道有沒有讓大家對這個框架產生點興趣,這次我要分析的是一個平常比較常用也比較簡單但是還挺煩人的知識點:下載圖片,當然現在有很多框架比如ImageLoader,Volley裡的專門

Redux原始碼解讀

上篇文章我們分析了createStore和combineReducers檔案,這一篇我們分析剩下的檔案。 首先是bindActionCreators檔案,這個檔案十分簡單 function bindActionCreator(actionCreator, dispa

移動GPU全解讀

分表 標量 2.0 特效 one 高精 上一個 能夠 兩個 【編者按】:本文作者為愛搞機特約作者、技術達人“炮神”@ioncannon。 在上一篇移動GPU解讀中,對移動GPU的架構、相關參數進行了介紹,本部分介紹的則是移動GPU的Shader、GPU兼容

Flume NG原始碼分析支援執行時動態修改配置的配置模組

在上一篇中講了Flume NG配置模組基本的介面的類,PropertiesConfigurationProvider提供了基於properties配置檔案的靜態配置的能力,這篇細說一下PollingPropertiesFileConfigurationProvider提供的執行時動態修改配置並生效的

GCC原始碼分析——前端

原文連結:http://blog.csdn.net/sonicling/article/details/6706152   從這一篇開始,我們將從原始碼的角度來分析GCC如何完成對C語言原始檔的處理。GCC的內部構架在GCC Internals(搜“gccint.pdf”,或者見[

Spring原始碼解析——元件註冊2

    import com.ken.service.BookService; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.

Android Hook框架adbi原始碼淺析

二、libbase 其實上面載入完SO庫後,hook的功能我們完全可以自己在動態庫中實現。而adbi作者為了方便我們使用,編寫了一個通用的hook框架工具即libbase庫。libbase依然在解決兩個問題:1.獲取要hook的目標函式地址;2.給函式打二進位制補丁即inline hook。 關於獲取ho

Glide原始碼分析——從用法來看之load&into方法

上一篇,我們分析了with方法,文章連結: https://blog.csdn.net/qq_36391075/article/details/82833260 在with方法中,進行了Glide的初始化,建立了RequesManger,並且綁定了生命週期,最終返回了一個Reques

YOLOv2原始碼分析

文章全部YOLOv2原始碼分析 接著上一講沒有講完的make_convolutional_layer函式 0x01 make_convolutional_layer //make_convolutional_laye

elas原始碼賞析sobel運算元3*3行列分解快速卷積

sobel3*3運算元的計算過程 _mm_malloc() convolve_cols_3x3 列卷積 convolve_101_row_3x3 101的行卷積 convolve_121_row_3x3 121的行卷積

zigbee 之ZStack-2.5.1a原始碼分析 無線接收控制LED

本文描述ZStack-2.5.1a 模板及無線接收移植相關內容。 main HAL_BOARD_INIT // HAL_TURN_OFF_LED1 InitBoard HalDriverInit HalAdcInit

以太坊原始碼解讀5BlockChain類的解析及NewBlockChain()分析

一、blockchain的資料結構 type BlockChain struct { chainConfig *params.ChainConfig // 初始化配置 cacheConfig *CacheConfig // 快取配置 db ethdb.Databas

以太坊原始碼解讀4Block類及其儲存

一、Block類 type Block struct { /******header*******/ header *Header /******header*******/ /******body*********/ uncle

DispNet中Caffe自定義層解讀——DataAugmentation

DispNet中Caffe自定義層解讀(二)——DataAugmentation 這一系列博文記錄了博主在學習DispNet過程中遇到的自定義Caffe層的筆記。這一部分是DataAugmentation層,其主要功能是:根據要求對輸入的資料進行擴張,從而從資料的角度上儘量緩解過擬合

認真的 Netty 原始碼解析

Channel 的 register 操作 經過前面的鋪墊,我們已經具備一定的基礎了,我們開始來把前面學到的內容揉在一起。這節,我們會介紹 register 操作,這一步其實是非常關鍵的,對於我們原始碼分析非常重要。 register 我們從 EchoClient 中的 connect() 方法出發,或者 E

Vue原始碼學習——生命週期

官網對生命週期給出了一個比較完成的流程圖,如下所示: 從圖中我們可以看到我們的Vue建立的過程要經過以下的鉤子函式: beforeCreate =&gt; created =&gt; beforeMount =&gt; mounted =&gt; beforeUpda

jquery 1.7.2原始碼解析構造jquery物件

構造jquery物件 jQuery物件是一個類陣列物件。 一)建構函式jQuery() 建構函式的7種用法:   1.jQuery(selector [, context ]) 傳入字串引數:檢查該字串是選擇器表示式還是HTML程式碼。如果是選擇器表示式,則遍歷文件查詢匹配的DOM元

以太坊原始碼解讀6blockchain區塊插入和校驗分析

以太坊blockchain的管理事務: 1、blockchain模組初始化 2、blockchain模組插入校驗分析 3、blockchain模組區塊鏈分叉處理 4、blockchian模組規範鏈更新 上一節分析了blockchain的初始化,這一節來分析blockchain區塊的插入和校驗