#python #blockchain #wallet
#python #блокчейн #кошелек
Вопрос:
Хотя официальная документация algosdk (Python SDK для Algorand) предполагает, что кошелек можно восстановить, просто вызвав следующую функцию (ссылка):
create_wallet(name, pswd, driver_name='sqlite', master_deriv_key=None)
с четвертым аргументом:
master_deriv_key (str, optional) – if recovering a wallet, include
восстановление кошелька не работает в моем коде и также приводит к возникновению исключения. Также в официальной документации Algorand показано, как использовать вышеупомянутую функцию для восстановления кошелька (ссылка):
# recover the wallet by passing mdk when creating a wallet
new_wallet = kcl.create_wallet("MyTestWallet2", "testpassword", master_deriv_key=mdk)
Ниже вы можете посмотреть мой код, очень простой фрагмент, который я закодировал для проведения некоторых тестов с помощью 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 (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
выполняет просто (ссылка):
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
помощью команды из консоли.
Кто-нибудь еще сталкивался с подобной проблемой раньше?
Комментарии:
1. В вашей ошибке указано
400: Bad Request
, что ваш SDK выполняет какой-то неправильный запрос к серверу. Обычно это означает, что SDK устарел. Вы проверили, был ли этот sdk недавно разработан в прошлом месяце?2. Последняя версия. Я думаю, что неправильный запрос в гораздо большей степени связан с тем фактом, что аргумент «master_derivation_key» полностью игнорируется при разборе «запроса» на стороне сервера, что приводит к попытке создать новый кошелек вместо его восстановления, как предложено в документации.
3. Вы также пытались выполнить какую-либо нерабочую команду SDK вручную, выполнив низкоуровневый HTTP-запрос? Например, с помощью
requests
библиотеки. Может случиться так, что онлайн-документация об API неверна. Тогда единственный способ устранить проблему — обратиться в службу поддержки разработчиков API.4. Еще не сделано. Допустим, эта работа сейчас не так критична, крайний срок не приближается, поэтому я предпочел сначала запросить сообщество stack-overflow, чтобы убедиться, что есть кто-то еще, кто столкнулся с такой же проблемой, и определить в primis, является ли это ошибкой в SDK. В любом случае, я обязательно сделаю эту попытку позже, чтобы я мог ответить вам и связаться с разработчиками API.
5. Если вы создали все параметры в точном соответствии с документом REST API, то, безусловно, есть ошибка либо в их документации, либо в реализации кода API. Обычно разработчики криптовалют имеют активную поддержку и часто отвечают.
Ответ №1:
Подводя итог, документация Algorand API REST не предлагает явно использовать Master-Derivation-Key для извлечения кошелька при создании POST /v1/wallet
(ссылка). И наоборот, документация Algorand для Python SDK предполагает, что ключ Master-Derivation может быть передан create_wallet
функции, которая затем выполняет HTTP-сообщение, указанное ранее, для восстановления существующего кошелька (ссылка).
Как объяснялось в моем вопросе выше, 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)
Я надеюсь, что это будет полезно кому-то еще в будущем.