【问题标题】:How to recover an Algorand Wallet with Python AlgoSDK?如何使用 Python AlgoSDK 恢复 Algorand 钱包?
【发布时间】:2021-02-06 22:59:52
【问题描述】:

虽然官方 algosdk(Algorand 的 Python SDK)文档建议可以通过简单地调用以下函数 (link) 来恢复钱包:

create_wallet(name, pswd, driver_name='sqlite', master_deriv_key=None)

第四个参数:

master_deriv_key (str, optional) – if recovering a wallet, include

钱包恢复在我的代码中不起作用,也会导致出现异常。 Algorand 官方文档还展示了如何使用上述功能恢复钱包 (link):

# recover the wallet by passing mdk when creating a wallet
new_wallet = kcl.create_wallet("MyTestWallet2", "testpassword", master_deriv_key=mdk)

您可以在下面查看我的代码,这是我编写的一个非常简单的 sn-p,用于使用 Algorand SDK 进行一些测试:

from algosdk import kmd
from algosdk import mnemonic

kmd_clt = kmd.KMDClient('855d39510cce40caf11de4c941b37632d1529ec970156214528a33a0ae8473b4', 'http://127.0.0.1:6969')
if kmd_clt:
    kmd_wlt_mdk = None
    kmd_wlt_list = kmd_clt.list_wallets()
    for kmd_wlt in kmd_wlt_list:
        kmd_name = kmd_wlt['name']
        kmd_id = kmd_wlt['id']
        if kmd_name == 'wallet_name':
            kmd_wlt_hdl = kmd_clt.init_wallet_handle(kmd_id, 'wallet_password')
            if kmd_wlt_hdl:
                kmd_wlt_mdk = kmd_clt.export_master_derivation_key(kmd_wlt_hdl, 'wallet_password')
            break
    if kmd_wlt_mdk:
        kmd_wlt = kmd_clt.create_wallet('wallet_name', 'wallet_password', master_deriv_key=kmd_wlt_mdk)
        kmd_wlt_hdl = kmd_clt.init_wallet_handle(kmd_wlt['id'], 'wallet_password')
        acc_addr_list = kmd_clt.list_keys(kmd_wlt_hdl)
        for acc_addr in acc_addr_list:
            account_address = acc_addr
            print(account_address)
            account_key = kmd_clt.export_key(kmd_wlt_hdl, 'wallet_password', account_address)
            print(account_key)
            account_mnemonic = mnemonic.from_private_key(account_key)
            print(account_mnemonic)

下面,您可以查看 Traceback 以及运行时返回的错误消息:

Traceback (most recent call last):
  File "/home/emiliano/anaconda3/lib/python3.7/site-packages/algosdk/kmd.py", line 63, in kmd_request
    resp = urlopen(req)
  File "/home/emiliano/anaconda3/lib/python3.7/urllib/request.py", line 222, in urlopen
    return opener.open(url, data, timeout)
  File "/home/emiliano/anaconda3/lib/python3.7/urllib/request.py", line 531, in open
    response = meth(req, response)
  File "/home/emiliano/anaconda3/lib/python3.7/urllib/request.py", line 641, in http_response
    'http', request, response, code, msg, hdrs)
  File "/home/emiliano/anaconda3/lib/python3.7/urllib/request.py", line 569, in error
    return self._call_chain(*args)
  File "/home/emiliano/anaconda3/lib/python3.7/urllib/request.py", line 503, in _call_chain
    result = func(*args)
  File "/home/emiliano/anaconda3/lib/python3.7/urllib/request.py", line 649, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 400: Bad Request

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/emiliano/anaconda3/lib/python3.7/site-packages/algosdk/kmd.py", line 67, in kmd_request
    raise error.KMDHTTPError(json.loads(e)["message"])
algosdk.error.KMDHTTPError: wallet with same name already exists

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "algorand_test.py", line 49, in <module>
    kmd_wlt = kmd_clt.create_wallet('emiliano', 'emiliano', master_deriv_key=kmd_wlt_mdk)
  File "/home/emiliano/anaconda3/lib/python3.7/site-packages/algosdk/kmd.py", line 118, in create_wallet
    return self.kmd_request("POST", req, data=query)["wallet"]
  File "/home/emiliano/anaconda3/lib/python3.7/site-packages/algosdk/kmd.py", line 69, in kmd_request
    raise error.KMDHTTPError(e)
algosdk.error.KMDHTTPError: {
  "error": true,
  "message": "wallet with same name already exists"
}

似乎很清楚create_wallet 函数是这种行为的罪魁祸首,导致返回错误“同名钱包已经存在”。 Algorand SDK 的内部非常简单,API 是 REST 方法的包装器。函数create_wallet 做的很简单(link):

def create_wallet(self, name, pswd, driver_name="sqlite",
                  master_deriv_key=None):
    """
    Create a new wallet.
    Args:
        name (str): wallet name
        pswd (str): wallet password
        driver_name (str, optional): name of the driver
        master_deriv_key (str, optional): if recovering a wallet, include
    Returns:
        dict: dictionary containing wallet information
    """
    req = "/wallet"
    query = {
        "wallet_driver_name": driver_name,
        "wallet_name": name,
        "wallet_password": pswd
    }
    if master_deriv_key:
        query["master_derivation_key"] = master_deriv_key
    return self.kmd_request("POST", req, data=query)["wallet"]

我确定传入输入的主派生密钥是正确的,因为我已经使用控制台中的goal 命令检查了它。

以前有没有其他人遇到过此类问题?

【问题讨论】:

  • 您的错误状态为400: Bad Request,这意味着您的SDK 向服务器发出了错误的请求。这通常意味着 SDK 已过时。你检查过这个 sdk 是不是上个月最近开发的吗?
  • 最新版本。我认为错误请求与在服务器端解析“查询”时完全忽略参数“master_derivation_key”这一事实有关,因此导致尝试创建一个新钱包而不是按照文档的建议恢复它。跨度>
  • 您是否也尝试过通过执行低级 HTTP 请求手动执行任何非工作 SDK 命令?例如。使用requests 库。可能是关于 API 的在线文档是错误的。那么解决问题的唯一方法就是联系 API 开发人员支持。
  • 尚未完成。比方说,这项工作现在不是那么重要,没有临近的最后期限,所以我更愿意先查询 stack-overflow 社区,以验证是否有其他人遇到同样的问题,并在 primis 中确定它是否是一个错误在 SDK 中。无论如何,我一定会在稍后尝试这样做,以便能够回复您并联系 API 开发人员。
  • 如果您完全按照 REST API 文档制作所有参数,那么在他们的文档或 API 代码实现中肯定存在错误。通常加密货币开发人员会积极支持并经常回复。

标签: python blockchain wallet


【解决方案1】:

总而言之,REST API 的 Algorand 文档并未明确建议在创建 POST /v1/wallet (link) 时使用 Master-Derivation-Key 来检索钱包。相反,Python SDK 的 Algorand 文档建议可以将 Master-Derivation-Key 传递给 create_wallet 函数,然后该函数会进行前面所述的 HTTP POST,以恢复现有的钱包 (link)。

正如我在上面的问题中所解释的,create_wallet 无法恢复钱包,因为底层的POST /v1/wallet 失败了。在@Arty 的建议下,证明如下:

curl -X POST -H "X-KMD-API-Token: <kmd-token>" -H "Content-Type: application/json" -d '{"wallet_driver_name": "sqlite", "wallet_name": <wallet-name>, "wallet_password": <wallet-password>, "master_derivation_key": <master-derivation-key>}' <kmd-address-and-port>/v1/wallet

返回的

{ "error": true, "message": "wallet with same name already exists" }

我已将此问题通知给 Algorand 支持,目前正在等待回复。无论如何,为了让问题的标题更有意义,我想分享另一种可能的解决方案,仍然依靠 Python SDK 来恢复钱包:

from algosdk import kmd
from algosdk import wallet
from algosdk import mnemonic

kmd_clt = kmd.KMDClient(<kmd-token>, <kmd-address-and-port>)
if kmd_clt:
    kmd_wlt_mdk = None
    kmd_wlt_list = kmd_clt.list_wallets()
    for kmd_wlt in kmd_wlt_list:
        kmd_name = kmd_wlt['name']
        kmd_id = kmd_wlt['id']
        if kmd_name == <wallet-name>:
            kmd_wlt_hdl = kmd_clt.init_wallet_handle(kmd_id, <wallet-password>)
            if kmd_wlt_hdl:
                kmd_wlt_mdk = kmd_clt.export_master_derivation_key(kmd_wlt_hdl, <wallet-password>)
            break
    if kmd_wlt_mdk:
        wlt = wallet.Wallet(<wallet-name>, <wallet-password>, kmd_clt, mdk=kmd_wlt_mdk)
        if wlt:
            acc_addr_list = wlt.list_keys()
            for acc_addr in acc_addr_list:
                account_address = acc_addr
                print(account_address)
                account_key = wlt.export_key(acc_addr)
                print(account_key)
                account_mnemonic = mnemonic.from_private_key(account_key)
                print(account_mnemonic)

希望以后对其他人有用。

【讨论】:

    猜你喜欢
    • 2022-06-09
    • 2022-07-12
    • 2022-06-17
    • 1970-01-01
    • 2022-07-17
    • 2020-11-07
    • 1970-01-01
    • 1970-01-01
    • 2018-11-06
    相关资源
    最近更新 更多