在bitshares研究系列【水龙头(faucet)代码分析】这篇文章中提了一下python-faucet,但是当时没调通,这次重新理一下这个开源的"蟒-水龙头"!
由于bitshares的faucet是用Ruby写的,另外这个功能不多,但这边开发人员会Ruby的没有,想着把faucet改成python或者nodejs版本。看看网上有没有类似的版本,结果还真搜索到一个python faucet库,那就先用python库测试一下。
用python3.6,先安装flask相关的几个库,再安装pyyml,执行:
(env3) Chaim:python-faucet Chaim$ python manage.py install
Traceback (most recent call last):
File "manage.py", line 6, in <module>
from app import app, db
File "/Users/Chaim/Documents/workspace/python-faucet/app/__init__.py", line 82, in <module>
from . import views, models
File "/Users/Chaim/Documents/workspace/python-faucet/app/views.py", line 1, in <module>
from transnet.account import Account
ModuleNotFoundError: No module named 'transnet'
找不到transnet库,试图pip安装发现没有这个库,搜索作者建的仓库,找到一个transnet库,再下载这个仓库安装。
(env3) Chaim:python-utransnet Chaim$ python setup.py install
running install
running bdist_egg
running egg_info
creating python_utransnet.egg-info
...
creating 'dist/python_utransnet-0.1.10-py3.6.egg' and adding 'build/bdist.macosx-10.6-intel/egg' to it
removing 'build/bdist.macosx-10.6-intel/egg' (and everything under it)
Processing python_utransnet-0.1.10-py3.6.egg
Copying python_utransnet-0.1.10-py3.6.egg to /Users/Chaim/Documents/workspace/python/env3/lib/python3.6/site-packages
Adding python-utransnet 0.1.10 to easy-install.pth file
python程序是运行起来了,水龙头也配置到python faucet,但是真正注册帐户时还是出现问题:
2018-05-02 16:06:50,282 - flask.app - ERROR - Exception on /api/v1/accounts [POST]
Traceback (most recent call last):
File "/Users/Chaim/Documents/workspace/python/env3/lib/python3.6/site-packages/python_utransnet-0.1.10-py3.6.egg/transnetapi/transnetnoderpc.py", line 43, in rpcexec
return super(TransnetNodeRPC, self).rpcexec(payload)
File "/Users/Chaim/Documents/workspace/python/env3/lib/python3.6/site-packages/grapheneapi/graphenewsrpc.py", line 173, in rpcexec
raise RPCError(ret['error']['message'])
grapheneapi.exceptions.RPCError: Assert Exception: _local_apis.size() > api_id:
开始在faucet.yml中设的端口为11012,也就是faucet连接端口
INFO:werkzeug:127.0.0.1 - - [10/May/2018 13:55:32] "OPTIONS /api/v1/accounts HTTP/1.1" 200 -
DEBUG:grapheneapi.graphenewsrpc:Trying to connect to node ws://127.0.0.1:11012
{'method': 'call', 'params': [1, 'database', []], 'jsonrpc': '2.0', 'id': 1}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [1, "database", []], "jsonrpc": "2.0", "id": 1}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":1,\"jsonrpc\":\"2.0\",\"error\":{\"code\":1,\"message\":\"Assert Exception: _local_apis.size() > api_id: \",\"data\":{\"code\":10,\"name\":\"assert_exception\",\"message\":\"Assert Exception\",\"stack\":[{\"context\":{\"level\":\"error\",\"file\":\"api_connection.hpp\",\"line\":234,\"method\":\"receive_call\",\"hostname\":\"\",\"thread_name\":\"th_a\",\"timestamp\":\"2018-05-10T05:55:32\"},\"format\":\"_local_apis.size() > api_id: \",\"data\":{}},{\"context\":{\"level\":\"warn\",\"file\":\"websocket_api.cpp\",\"line\":125,\"method\":\"on_message\",\"hostname\":\"\",\"thread_name\":\"th_a\",\"timestamp\":\"2018-05-10T05:55:32\"},\"format\":\"\",\"data\":{\"call.method\":\"call\",\"call.params\":[1,\"database\",[]]}}]}}}"
返回 _local_apis.size() > api_id 错误,正常来说这个api_id只有在设成rpc服务器不支持时才出现,后来一想可能是端口弄错了,python-faucet根本不需要cli_wallet,直接连接节点,把端口改为11011
INFO:werkzeug:127.0.0.1 - - [10/May/2018 14:00:48] "OPTIONS /api/v1/accounts HTTP/1.1" 200 -
DEBUG:grapheneapi.graphenewsrpc:Trying to connect to node ws://127.0.0.1:11011
{'method': 'call', 'params': [1, 'database', []], 'jsonrpc': '2.0', 'id': 1}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [1, "database", []], "jsonrpc": "2.0", "id": 1}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":1,\"jsonrpc\":\"2.0\",\"result\":2}"
{'method': 'call', 'params': [1, 'history', []], 'jsonrpc': '2.0', 'id': 2}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [1, "history", []], "jsonrpc": "2.0", "id": 2}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":2,\"jsonrpc\":\"2.0\",\"result\":3}"
{'method': 'call', 'params': [1, 'network_broadcast', []], 'jsonrpc': '2.0', 'id': 3}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [1, "network_broadcast", []], "jsonrpc": "2.0", "id": 3}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":3,\"jsonrpc\":\"2.0\",\"result\":4}"
{'method': 'call', 'params': [0, 'get_chain_properties', []], 'jsonrpc': '2.0', 'id': 4}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "get_chain_properties", []], "jsonrpc": "2.0", "id": 4}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":4,\"jsonrpc\":\"2.0\",\"result\":{\"id\":\"2.11.0\",\"chain_id\":\"daa4773ef922acf907828b63c308eda9b0ee6d59133d890cac50e0d40f2b259d\",\"immutable_parameters\":{\"min_committee_member_count\":11,\"min_witness_count\":11,\"num_special_accounts\":0,\"num_special_assets\":0}}}"
...
self.chain_params = self.get_network()
File "/Users/Chaim/Documents/workspace/python/env3/lib/python3.6/site-packages/python_utransnet-0.1.10-py3.6.egg/transnetapi/transnetnoderpc.py", line 93, in get_network
raise("Connecting to unknown network!")
从日志看rpc调用正常了,但是出现"unknown network"错误,看来是连的私链引起的问题。
找到/python-utransnet/transnetbase/chains.py,在known_chains增加私有链信息:
"BND": {
"chain_id": "daa4773ef922acf907828b63c308eda9b0ee6d59133d890cac50e0d40f2b259d",
"core_symbol": "BTS",
"prefix": "BTS"}
重新安装python-utransnet。
注意这个chain_id在修改genenis.json时就会变,如果只测试可以把chain_id写死。
再次从bitshares-ui注册帐户:
INFO:werkzeug:127.0.0.1 - - [10/May/2018 14:53:03] "OPTIONS /api/v1/accounts HTTP/1.1" 200 -
DEBUG:grapheneapi.graphenewsrpc:Trying to connect to node ws://127.0.0.1:11011
{'method': 'call', 'params': [1, 'database', []], 'jsonrpc': '2.0', 'id': 1}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [1, "database", []], "jsonrpc": "2.0", "id": 1}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":1,\"jsonrpc\":\"2.0\",\"result\":2}"
{'method': 'call', 'params': [1, 'history', []], 'jsonrpc': '2.0', 'id': 2}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [1, "history", []], "jsonrpc": "2.0", "id": 2}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":2,\"jsonrpc\":\"2.0\",\"result\":3}"
{'method': 'call', 'params': [1, 'network_broadcast', []], 'jsonrpc': '2.0', 'id': 3}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [1, "network_broadcast", []], "jsonrpc": "2.0", "id": 3}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":3,\"jsonrpc\":\"2.0\",\"result\":4}"
{'method': 'call', 'params': [0, 'get_chain_properties', []], 'jsonrpc': '2.0', 'id': 4}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "get_chain_properties", []], "jsonrpc": "2.0", "id": 4}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":4,\"jsonrpc\":\"2.0\",\"result\":{\"id\":\"2.11.0\",\"chain_id\":\"daa4773ef922acf907828b63c308eda9b0ee6d59133d890cac50e0d40f2b259d\",\"immutable_parameters\":{\"min_committee_member_count\":11,\"min_witness_count\":11,\"num_special_accounts\":0,\"num_special_assets\":0}}}"
DEBUG:transnet.wallet:Force setting of private keys. Not using the wallet database!
{'method': 'call', 'params': [0, 'lookup_account_names', [['barnard003']]], 'jsonrpc': '2.0', 'id': 5}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "lookup_account_names", [["barnard003"]]], "jsonrpc": "2.0", "id": 5}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":5,\"jsonrpc\":\"2.0\",\"result\":[null]}"
{'method': 'call', 'params': [0, 'lookup_account_names', [['nathan']]], 'jsonrpc': '2.0', 'id': 6}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "lookup_account_names", [["nathan"]]], "jsonrpc": "2.0", "id": 6}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":6,\"jsonrpc\":\"2.0\",\"result\":[{\"id\":\"1.2.17\",\"membership_expiration_date\":\"1969-12-31T23:59:59\",\"registrar\":\"1.2.17\",\"referrer\":\"1.2.17\",\"lifetime_referrer\":\"1.2.17\",\"network_fee_percentage\":2000,\"lifetime_referrer_fee_percentage\":8000,\"referrer_rewards_percentage\":0,\"name\":\"nathan\",\"owner\":{\"weight_threshold\":1,\"account_auths\":[],\"key_auths\":[[\"BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV\",1]],\"address_auths\":[]},\"active\":{\"weight_threshold\":1,\"account_auths\":[],\"key_auths\":[[\"BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV\",1]],\"address_auths\":[]},\"options\":{\"memo_key\":\"BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV\",\"voting_account\":\"1.2.5\",\"num_witness\":0,\"num_committee\":0,\"votes\":[\"0:23\"],\"extensions\":[]},\"statistics\":\"2.6.17\",\"whitelisting_accounts\":[],\"blacklisting_accounts\":[],\"whitelisted_accounts\":[],\"blacklisted_accounts\":[],\"cashback_vb\":\"1.13.0\",\"owner_special_authority\":[0,{}],\"active_special_authority\":[0,{}],\"top_n_control_flags\":0}]}"
DEBUG:grapheneapi.graphenewsrpc:Trying to connect to node ws://127.0.0.1:11011
{'method': 'call', 'params': [1, 'database', []], 'jsonrpc': '2.0', 'id': 1}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [1, "database", []], "jsonrpc": "2.0", "id": 1}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":1,\"jsonrpc\":\"2.0\",\"result\":2}"
{'method': 'call', 'params': [1, 'history', []], 'jsonrpc': '2.0', 'id': 2}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [1, "history", []], "jsonrpc": "2.0", "id": 2}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":2,\"jsonrpc\":\"2.0\",\"result\":3}"
{'method': 'call', 'params': [1, 'network_broadcast', []], 'jsonrpc': '2.0', 'id': 3}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [1, "network_broadcast", []], "jsonrpc": "2.0", "id": 3}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":3,\"jsonrpc\":\"2.0\",\"result\":4}"
{'method': 'call', 'params': [0, 'get_chain_properties', []], 'jsonrpc': '2.0', 'id': 4}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "get_chain_properties", []], "jsonrpc": "2.0", "id": 4}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":4,\"jsonrpc\":\"2.0\",\"result\":{\"id\":\"2.11.0\",\"chain_id\":\"daa4773ef922acf907828b63c308eda9b0ee6d59133d890cac50e0d40f2b259d\",\"immutable_parameters\":{\"min_committee_member_count\":11,\"min_witness_count\":11,\"num_special_accounts\":0,\"num_special_assets\":0}}}"
{'method': 'call', 'params': [0, 'lookup_account_names', [['nathan']]], 'jsonrpc': '2.0', 'id': 7}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "lookup_account_names", [["nathan"]]], "jsonrpc": "2.0", "id": 7}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":7,\"jsonrpc\":\"2.0\",\"result\":[{\"id\":\"1.2.17\",\"membership_expiration_date\":\"1969-12-31T23:59:59\",\"registrar\":\"1.2.17\",\"referrer\":\"1.2.17\",\"lifetime_referrer\":\"1.2.17\",\"network_fee_percentage\":2000,\"lifetime_referrer_fee_percentage\":8000,\"referrer_rewards_percentage\":0,\"name\":\"nathan\",\"owner\":{\"weight_threshold\":1,\"account_auths\":[],\"key_auths\":[[\"BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV\",1]],\"address_auths\":[]},\"active\":{\"weight_threshold\":1,\"account_auths\":[],\"key_auths\":[[\"BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV\",1]],\"address_auths\":[]},\"options\":{\"memo_key\":\"BTS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV\",\"voting_account\":\"1.2.5\",\"num_witness\":0,\"num_committee\":0,\"votes\":[\"0:23\"],\"extensions\":[]},\"statistics\":\"2.6.17\",\"whitelisting_accounts\":[],\"blacklisting_accounts\":[],\"whitelisted_accounts\":[],\"blacklisted_accounts\":[],\"cashback_vb\":\"1.13.0\",\"owner_special_authority\":[0,{}],\"active_special_authority\":[0,{}],\"top_n_control_flags\":0}]}"
{'method': 'call', 'params': [0, 'lookup_account_names', [['barnard003']]], 'jsonrpc': '2.0', 'id': 8}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "lookup_account_names", [["barnard003"]]], "jsonrpc": "2.0", "id": 8}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":8,\"jsonrpc\":\"2.0\",\"result\":[null]}"
{'method': 'call', 'params': [0, 'lookup_account_names', [['proxy-to-self']]], 'jsonrpc': '2.0', 'id': 9}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "lookup_account_names", [["proxy-to-self"]]], "jsonrpc": "2.0", "id": 9}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":9,\"jsonrpc\":\"2.0\",\"result\":[{\"id\":\"1.2.5\",\"membership_expiration_date\":\"1969-12-31T23:59:59\",\"registrar\":\"1.2.3\",\"referrer\":\"1.2.3\",\"lifetime_referrer\":\"1.2.3\",\"network_fee_percentage\":0,\"lifetime_referrer_fee_percentage\":10000,\"referrer_rewards_percentage\":0,\"name\":\"proxy-to-self\",\"owner\":{\"weight_threshold\":1,\"account_auths\":[],\"key_auths\":[],\"address_auths\":[]},\"active\":{\"weight_threshold\":1,\"account_auths\":[],\"key_auths\":[],\"address_auths\":[]},\"options\":{\"memo_key\":\"BTS1111111111111111111111111111111114T1Anm\",\"voting_account\":\"1.2.5\",\"num_witness\":0,\"num_committee\":0,\"votes\":[],\"extensions\":[]},\"statistics\":\"2.6.5\",\"whitelisting_accounts\":[],\"blacklisting_accounts\":[],\"whitelisted_accounts\":[],\"blacklisted_accounts\":[],\"owner_special_authority\":[0,{}],\"active_special_authority\":[0,{}],\"top_n_control_flags\":0}]}"
{'method': 'call', 'params': [0, 'get_required_fees', [[[5, {'fee': {'amount': 0, 'asset_id': '1.3.0'}, 'registrar': '1.2.17', 'referrer': '1.2.17', 'referrer_percent': 5000, 'name': 'barnard003', 'owner': {'weight_threshold': 1, 'account_auths': [], 'key_auths': [['BTS8RjHwh2GAT2b6BJw1oqoChuCjudrSxUmwwRcpwhrqizjwDCYC6', '1']], 'extensions': []}, 'active': {'weight_threshold': 1, 'account_auths': [], 'key_auths': [['BTS5KDpcQKBqsyr4xBHcNrVoBhh5wsvNxBEjWewNeK4A2nZEpCWPR', '1']], 'extensions': []}, 'options': {'memo_key': 'BTS5KDpcQKBqsyr4xBHcNrVoBhh5wsvNxBEjWewNeK4A2nZEpCWPR', 'voting_account': '1.2.5', 'num_witness': 0, 'num_committee': 0, 'votes': [], 'extensions': []}, 'extensions': {}}]], '1.3.0']], 'jsonrpc': '2.0', 'id': 10}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "get_required_fees", [[[5, {"fee": {"amount": 0, "asset_id": "1.3.0"}, "registrar": "1.2.17", "referrer": "1.2.17", "referrer_percent": 5000, "name": "barnard003", "owner": {"weight_threshold": 1, "account_auths": [], "key_auths": [["BTS8RjHwh2GAT2b6BJw1oqoChuCjudrSxUmwwRcpwhrqizjwDCYC6", "1"]], "extensions": []}, "active": {"weight_threshold": 1, "account_auths": [], "key_auths": [["BTS5KDpcQKBqsyr4xBHcNrVoBhh5wsvNxBEjWewNeK4A2nZEpCWPR", "1"]], "extensions": []}, "options": {"memo_key": "BTS5KDpcQKBqsyr4xBHcNrVoBhh5wsvNxBEjWewNeK4A2nZEpCWPR", "voting_account": "1.2.5", "num_witness": 0, "num_committee": 0, "votes": [], "extensions": []}, "extensions": {}}]], "1.3.0"]], "jsonrpc": "2.0", "id": 10}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":10,\"jsonrpc\":\"2.0\",\"result\":[{\"amount\":514550,\"asset_id\":\"1.3.0\"}]}"
{'method': 'call', 'params': [0, 'get_dynamic_global_properties', []], 'jsonrpc': '2.0', 'id': 11}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "get_dynamic_global_properties", []], "jsonrpc": "2.0", "id": 11}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":11,\"jsonrpc\":\"2.0\",\"result\":{\"id\":\"2.1.0\",\"head_block_number\":27636,\"head_block_id\":\"00006bf4d4e130a645230d588d06122d48669f3c\",\"time\":\"2018-05-10T06:53:00\",\"current_witness\":\"1.6.3\",\"next_maintenance_time\":\"2018-05-11T00:00:00\",\"last_budget_time\":\"2018-05-10T05:23:15\",\"witness_budget\":0,\"accounts_registered_this_interval\":0,\"recently_missed_count\":636328,\"current_aslot\":207068,\"recent_slots_filled\":\"340282366920938463463374607431768211455\",\"dynamic_flags\":0,\"last_irreversible_block_num\":27626}}"
/Users/Chaim/Documents/workspace/python/env3/lib/python3.6/site-packages/graphenebase/ecdsa.py:187: CryptographyDeprecationWarning: signer and verifier have been deprecated. Please use sign and verify instead.
signer = private_key.signer(ec.ECDSA(hashes.SHA256()))
WARNING:transnet.transactionbuilder:Not broadcasting anything!
{'method': 'call', 'params': [0, 'get_account_balances', ['1.2.17', []]], 'jsonrpc': '2.0', 'id': 5}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "get_account_balances", ["1.2.17", []]], "jsonrpc": "2.0", "id": 5}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":5,\"jsonrpc\":\"2.0\",\"result\":[{\"amount\":\"799988790187020\",\"asset_id\":\"1.3.0\"}]}"
{'method': 'call', 'params': [0, 'get_objects', [['1.3.0']]], 'jsonrpc': '2.0', 'id': 6}
DEBUG:grapheneapi.graphenewsrpc:{"method": "call", "params": [0, "get_objects", [["1.3.0"]]], "jsonrpc": "2.0", "id": 6}
DEBUG:grapheneapi.graphenewsrpc:"{\"id\":6,\"jsonrpc\":\"2.0\",\"result\":[{\"id\":\"1.3.0\",\"symbol\":\"BTS\",\"precision\":5,\"issuer\":\"1.2.3\",\"options\":{\"max_supply\":\"1000000000000000\",\"market_fee_percent\":0,\"max_market_fee\":\"1000000000000000\",\"issuer_permissions\":0,\"flags\":0,\"core_exchange_rate\":{\"base\":{\"amount\":1,\"asset_id\":\"1.3.0\"},\"quote\":{\"amount\":1,\"asset_id\":\"1.3.0\"}},\"whitelist_authorities\":[],\"blacklist_authorities\":[],\"whitelist_markets\":[],\"blacklist_markets\":[],\"description\":\"\",\"extensions\":[]},\"dynamic_asset_data_id\":\"2.3.0\"}]}"
INFO:werkzeug:127.0.0.1 - - [10/May/2018 14:53:04] "POST /api/v1/accounts HTTP/1.1" 200 -
整个日志有创建帐户的rpc调用流程,这个帐户"proxy-to-self"是干啥的?
googel了一下,只在python-bitshares文档中找到"proxy-to-self"做为缺省参数:
create_account(account_name, registrar=None, referrer=’1.2.35641’,referrer_percent=50,owner_key=None, active_key=None, memo_key=None, password=None,additional_owner_keys=[],additional_active_keys=[],additional_owner_accounts=[], additional_active_accounts=[],proxy_account=’proxy-to-self ’, storekeys=True, **kwargs)
python-faucet调用python-utransnet,而python-utransnet又调用python-bitshares,bitshares再直接调用节点,使用bitshares的官方版本能比较好的协作。
由于我们在Bitshares基础上创建的新链,按这种方式的话,有问题还需要修改python版本,会带来不必要的工作量,还不如faucet(Ruby)调用cli_wallet的方式,因为cli_wallet是会随着版本修改的。
查看相关开源代码是MIT协议,可以自由修改,决定在python-faucet上改一个版本,需要达到以下要求:
说白了就是把原来对节点的调用改为对cli_wallet的调用,通过测试才发现cli_wallet接收的rpc格式基本是一样的,只是指定apid为0即可。如下:
{"method": "call", "params": [0, "get_object", ["2.1.0"]], "jsonrpc": "2.0", "id": 1}
不过开始走了些弯路,看到Ruby用了Promise,我也想在python中使用Promise,还真找到python promise库,只是用起来似乎并不合适,后来看python-faucet还是用的rpc阻塞接收的,这样应该也没问题,只是flask到时用“猴子魔法(monkey.patch_all())”设成支持异步非阻塞操作就行。
为了不再安装依赖库,直接把graphenewsrpc.py放到项目中,支持rpc调用,python比较有特色的一个地方就是可以不声明方法,用 getattr 拦截点号运算,如下方式:
# End of Deprecated methods
####################################################################
def __getattr__(self, name):
""" Map all methods to RPC calls and pass through the arguments
"""
def method(*args, **kwargs):
# Sepcify the api to talk to
if "api_id" not in kwargs:
if ("api" in kwargs):
if (kwargs["api"] in self.api_id and
self.api_id[kwargs["api"]]):
api_id = self.api_id[kwargs["api"]]
else:
# Try the query by providing the argument
# right away
api_id = kwargs["api"]
"""
raise ValueError(
"Unknown API! "
"Verify that you have registered to %s"
% kwargs["api"]
)
"""
else:
api_id = 0
else:
api_id = kwargs["api_id"]
# let's be able to define the num_retries per query
self.num_retries = kwargs.get("num_retries", self.num_retries)
query = {"method": "call",
"params": [api_id, name, list(args)],
"jsonrpc": "2.0",
"id": self.get_request_id()}
r = self.rpcexec(query)
return r
return method
这样可以实现一个get_object方法,服务端实现也很简单,可以直接调用get_object转为rpc调用,如下:
@app.route('/get_object')
def get_object():
rpc = CliWalletRPC(config.witness_url)
obj = rpc.get_object(request.args.get('object','2.0.0'))
return jsonify(obj)
同样道理可以实现/api/v1/accounts的帐号注册功能,只是对注册rpc调用改为cli_wallet的方法:
# Create new account
try:
rpc.register_account(
account["name"],
account["owner_key"],
account["active_key"],
registrar["id"],
referrer["id"],
referrer_percent,
True)
except Exception as e:
log.error(traceback.format_exc())
return api_error(str(e))
代码全部完善后再开源到github。
http://docs.jinkan.org/docs/flask/
python-graphenelib
https://github.com/xeroc/python-graphenelib
python-bitshares
https://github.com/xeroc/python-bitshares/