在ubuntu上安装了PyCharm,并使用其打开下载的Electrum代码,安装及使用方式如下:
(https://blog.csdn.net/zhuanshu666/article/details/73554885)
代码地址如下:
(https://github.com/spesmilo/electrum)
在路径electrum-master下找到 run_electrum 文件,将文件中的所有方法逐一打上断点之后,使用Run->Toggle Line Breakpoint 后 debug 来逐行运行,可以看到代码的运行顺序:
if is_local or is_android
is_local=true,is _android=false
在导入这几个依赖是有几个需要注意的地方
if not is_android:
该方法的运行是基于第一步的判断
a. 随后开始跳转到 check_imports() 方法
def check_imports():
try_catch
中的几个依赖是否导入,如果没有导入,程序会报错pip search <model_name>
进行查询pip install dnsPython
而不是 pip install dns
google.protobuf
,使用 pip install protobuf
if __name__ == '__main__':
f cmdname== 'gui':
d.init_gui(config, plugins)
daemon.py --> def init_gui(self, config, plugins):
在此方法中进行 gui 的初始化操作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/pyqt@riverbankcomputing.com/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
在此方法中,程序会根据本地的路径来判断是否已存在钱包,如存在则打开,不存在则创建新钱包
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
中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):
seed
的显示及提示页面。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
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界面出现