Electrum 錢包原始碼解讀(二)
前言
程式碼地址如下:
下面開始程式碼的執行。
在路徑electrum-master下找到 run_electrum 檔案,將檔案中的所有方法逐一打上斷點之後,使用Run->Toggle Line Breakpoint 後 debug 來逐行執行,可以看到程式碼的執行順序:
if is_local or is_android
a. 用於判斷是在本地執行或者是在安卓端執行,如果是其中的一項,則將 script_dir + 'packages’這個路徑加入 sys.path中
b. 由於是在本地執行所以此時is_local=true,is _android=false
在匯入這幾個依賴是有幾個需要注意的地方
-
if not is_android:
該方法的執行是基於第一步的判斷
a. 隨後開始跳轉到 check_imports() 方法 -
def check_imports():
- 程式會在這個方法中檢查
try_catch
中的幾個依賴是否匯入,如果沒有匯入,程式會報錯 - 在匯入這幾個依賴是有幾個需要注意的地方
- 可以使用本機的終端會cmd工具來匯入,也可以使用PyCharm自帶的 Terminal終端工具進行命令列的執行
- 如果發現某個依賴找不到,可以使用
pip search <model_name>
進行查詢 - 在匯入 dns 這個依賴時,應該使用
pip install dnsPython
pip install dns
- 匯入
google.protobuf
,使用pip install protobuf
- 之後程式會順序執行 Line67- Line324, 直至進入 Line-327
- 程式會在這個方法中檢查
-
if __name__ == '__main__':
- 該方法為程式的主入口方法,進入該方法後程序會檢查當前環境的各種配置如:wallet_path、testnet、cmd 等
- 此時程式會進入 i
f cmdname== 'gui':
- 而後執行
d.init_gui(config, plugins)
- 進而跳轉到
daemon.py --> def init_gui(self, config, plugins):
-
daemon.py
檔案中的def init_gui(self, config, plugins):
-
在此方法中會首先進行 ‘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
-
在此方法中,程式會根據本地的路徑來判斷是否已存在錢包,如存在則開啟,不存在則建立新錢包
- 首先建立錢包的UI —
path = self.config.get_wallet_path() if not self.start_new_window(path, self.config.get('url'), app_is_starting=True):
- 隨後程式會跳轉到
_init_.py
中的
def start_new_window(self, path, uri, app_is_starting=False):
- 在
start_new_window
方法中,程式會再次在本地路徑中判斷錢包是否存在,如果不存在,則執行
storage = WalletStorage(path, manual_upgrades=True) wizard = InstallWizard(self.config, self.app, self.plugins, storage)
-
此時程式會跳轉到
installwizard.py
檔案中執行例項化方法def __init__(self, config, app, plugins, storage):
- 在這份程式碼中首先執行
BaseWizard.__init__(self, config, plugins, storage)
- 改方法存在於
base_wizard.py
中
- 改方法存在於
- 在此方法中我們可以修改部分UI,例如錢包的名稱:
self.setWindowTitle('HxWallet - ' + _('Install Wizard'))
- 在這份程式碼中首先執行
-
在
def __init__(self, config, app, plugins, storage):
方法中,程式會順序執行到self.show()
此時gui
畫面會開始展示。 -
此時程式會跳轉到
_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):
方法中。 -
在
def run_and_get_wallet(self, get_wallet_from_daemon):
方法中會針對使用者的選擇例如使用者的錢包是否存在進行一些判斷。 -
在UI上點選了
Next
按鈕之後,程式會跳轉到installwizard.py
檔案中的if self.storage.requires_split():
- 而後繼續順序執行至:
self.run(action)
-
此後,程式跳轉至
base_wizard.py
中的def new(self):
方法,並在此方法中進行UI的初始化工作,初始化完成後,UI上回展示 讓使用者來選擇希望建立的錢包型別。 -
選擇了其中一項並點選
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
-
隨後程式會執行
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):
- 在彈出的選擇頁面上選擇
-
此時程式跳轉到
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
頁面 - 在這裡選擇:
-
在輸入框中輸入Seed 後點擊
Next
後程序跳轉至base_wizard.py
中的def confirm_passphrase(self, seed, passphrase):
-
隨後程式進入
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):
- 進行密碼的設定
-
然後程式順序執行到
self.run('create_addresses')
來建立地址 -
此方法的定義在
base_wizard.py
中def create_addresses(self):
-
程式再次回到
_init_.py
-->w = self.create_window_for_wallet(wallet)
-
_init_.py
-->def create_window_for_wallet(self, wallet):
-
程式再次執行
_init_.py
-->if not self.start_new_window(path, self.config.get('url'), app_is_starting=True):
- 而後繼續順序執行值
self.app.exec_()
- 而後繼續順序執行值
-
-
至此,一個
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
以太坊原始碼解讀(5)BlockChain類的解析及NewBlockChain()分析
一、blockchain的資料結構 type BlockChain struct { chainConfig *params.ChainConfig // 初始化配置 cacheConfig *CacheConfig // 快取配置 db ethdb.Databas
以太坊原始碼解讀(4)Block類及其儲存
一、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 => created => beforeMount => mounted => beforeUpda
jquery 1.7.2原始碼解析(二)構造jquery物件
構造jquery物件 jQuery物件是一個類陣列物件。 一)建構函式jQuery() 建構函式的7種用法: 1.jQuery(selector [, context ]) 傳入字串引數:檢查該字串是選擇器表示式還是HTML程式碼。如果是選擇器表示式,則遍歷文件查詢匹配的DOM元
以太坊原始碼解讀(6)blockchain區塊插入和校驗分析
以太坊blockchain的管理事務: 1、blockchain模組初始化 2、blockchain模組插入校驗分析 3、blockchain模組區塊鏈分叉處理 4、blockchian模組規範鏈更新 上一節分析了blockchain的初始化,這一節來分析blockchain區塊的插入和校驗