bitshares研究系列【python-faucet】

in #bitshares6 years ago (edited)

bitshares研究系列【水龙头(faucet)代码分析】这篇文章中提了一下python-faucet,但是当时没调通,这次重新理一下这个开源的"蟒-水龙头"!

7723946C-EC0F-4052-AAC2-592F7EF42729.jpeg

原由

由于bitshares的faucet是用Ruby写的,另外这个功能不多,但这边开发人员会Ruby的没有,想着把faucet改成python或者nodejs版本。看看网上有没有类似的版本,结果还真搜索到一个python faucet库,那就先用python库测试一下。

安装

python-utransnet & python-faucet

用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是会随着版本修改的。

python-faucet定制版

查看相关开源代码是MIT协议,可以自由修改,决定在python-faucet上改一个版本,需要达到以下要求:

  1. python语言编写,方便开发人员接手;
  2. 连接cli_wallet,减少重复开发(不排除会在faucet上增加其它功能)
  3. 尽量少用第三方库,减少依赖

说白了就是把原来对节点的调用改为对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://flask.pocoo.org/

http://docs.jinkan.org/docs/flask/

python-graphenelib
https://github.com/xeroc/python-graphenelib

python-bitshares
https://github.com/xeroc/python-bitshares/

Sort:  

Congratulations @chaimyu! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of upvotes
Award for the total payout received

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

Upvote this notification to help all Steemit users. Learn why here!

Coin Marketplace

STEEM 0.36
TRX 0.12
JST 0.039
BTC 70112.96
ETH 3549.99
USDT 1.00
SBD 4.71