From 13e2fd6da2312f819bda152773d83431af57041f Mon Sep 17 00:00:00 2001 From: kentzhang <20529321+coderkentzhang@users.noreply.github.com> Date: Fri, 3 Mar 2023 16:49:55 +0800 Subject: [PATCH 1/5] update requirements --- requirements.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 30f01c8..c14ea76 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,6 @@ exceptiongroup==1.1.0 hypothesis==6.68.2 lru_dict==1.1.8 parsimonious==0.8.1 -pip==21.1.2 promise==2.3 pyasn1==0.4.8 pycparser==2.21 @@ -24,9 +23,8 @@ pymitter==0.4.0 pyOpenSSL==20.0.0 requests==2.28.2 rsa==4.9 -setuptools==66.1.1 six==1.16.0 sortedcontainers==2.4.0 toolz==0.12.0 urllib3==1.26.14 -wheel==0.36.2 + -- Gitee From 855ffd928ef06af2de63bcd9763dfbe001ef24a0 Mon Sep 17 00:00:00 2001 From: kentzhang <20529321+coderkentzhang@users.noreply.github.com> Date: Wed, 8 Mar 2023 11:55:35 +0800 Subject: [PATCH 2/5] Compatible with python 3.10 --- README.md | 10 +++++++--- client/common/common.py | 6 +++--- client/format_param_by_abi.py | 2 +- client/signer_impl.py | 5 +++-- client/signtransaction.py | 2 +- console.py | 26 ++++++++++++++++++++++++++ console_utils/cmd_account.py | 2 +- eth_account/account.py | 2 +- eth_utils/types.py | 4 ++-- 9 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 console.py diff --git a/README.md b/README.md index 572fdc9..7a446a0 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,9 @@ Python SDK为[FISCO BCOS](https://github.com/FISCO-BCOS/FISCO-BCOS/tree/master) ## 部署Python SDK ### 环境要求 -- Python环境:python 3.6.3, 3.7.x + +- Python环境:python 3.6.3, 3.7.x ,3.8.x ,3.9.x (python 3.10+的语法对依赖库的要求有较大差异,尚未适配) + - FISCO BCOS节点:请参考 [FISCO BCOS 2.x节点安装](https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/installation.html#fisco-bcos)搭建 @@ -299,10 +301,12 @@ params: contractname address event_name indexed **查看SDK使用方法** -* 注:以下示例不区分2.x和3.x的控制台,如要使用3.x的控制台,把console.py换成console3.py即可。 +* 注:以下示例不区分2.x和3.x的控制台, +* 如要使用2.x的控制台,把console.py换成console2.py。 +* 如要使用3.x的控制台,把console.py换成console3.py。 * 屏幕上的少量输入输出差异和版本有关,不做详细分解 -> **windows环境下执行console.py请使用`.\console.py`或者`python console.py`** +> **windows环境下执行console2/3.py请使用`.\console2/3.py`或者`python console2/3.py`** ```bash # 查看SDK使用方法 diff --git a/client/common/common.py b/client/common/common.py index 75c94e3..ba7825a 100644 --- a/client/common/common.py +++ b/client/common/common.py @@ -18,14 +18,14 @@ import json import subprocess import re from client.datatype_parser import DatatypeParser -from eth_utils.hexadecimal import decode_hex +from eth_utils.hexadecimal import decode_hex,encode_hex from client_config import client_config from eth_utils import to_checksum_address from utils.contracts import get_function_info from utils.abi import get_fn_abi_types_single from client.bcoserror import ArgumentsError, BcosException from eth_abi import decode_single -from eth_utils.hexadecimal import bytesToHex +#from eth_utils.hexadecimal import bytesToHex g_common_config = client_config @@ -286,7 +286,7 @@ def print_tx_result(outputresults): """ for result in outputresults: if isinstance(result, bytes): - print("{}, ".format(bytesToHex(result))) + print("{}, ".format(encode_hex(result))) continue print("reuslt: {}, ".format(result)) diff --git a/client/format_param_by_abi.py b/client/format_param_by_abi.py index 318fc0e..c8c09bc 100644 --- a/client/format_param_by_abi.py +++ b/client/format_param_by_abi.py @@ -14,7 +14,7 @@ -from collections import Iterable +from collections.abc import Iterable from client.bcoserror import ArgumentsError from eth_utils import to_checksum_address diff --git a/client/signer_impl.py b/client/signer_impl.py index 3ac4f80..414d246 100644 --- a/client/signer_impl.py +++ b/client/signer_impl.py @@ -99,8 +99,9 @@ class Signer_ECDSA(Signer_Impl): def set_account(self, account: LocalAccount): self.ecdsa_account = account self.keypair = BcosKeyPair() - self.keypair.private_key = account.privateKey - self.keypair.public_key = account.publickey + + self.keypair.private_key = encode_hex(account.key) + #self.keypair.public_key = account.publickey self.keypair.address = account.address def to_eth_v(self, v_raw, chain_id=None): diff --git a/client/signtransaction.py b/client/signtransaction.py index 17e436f..7323a1b 100644 --- a/client/signtransaction.py +++ b/client/signtransaction.py @@ -12,7 +12,7 @@ @date: 2020-01 ''' -from collections import ( +from collections.abc import ( Mapping, ) diff --git a/console.py b/console.py new file mode 100644 index 0000000..c9a55bb --- /dev/null +++ b/console.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# PYTHON_ARGCOMPLETE_OK +# -*- coding: utf-8 -*- +""" + FISCO BCOS/Python-SDK is a python client for FISCO BCOS2.0 (https://github.com/FISCO-BCOS/) + FISCO BCOS/Python-SDK is free software: you can redistribute it and/or modify it under the + terms of the MIT License as published by the Free Software Foundation. This project is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Thanks for + authors and contributors of eth-abi, eth-account, eth-hash,eth-keys, eth-typing, eth-utils, + rlp, eth-rlp , hexbytes ... and relative projects + @author: kentzhang + @date: 2019-06 + +""" +hint = ''' +python sdk 适配FISCO BCOS 2.x/3.x版本,控制台的实现文件做了分离。 + +README文档的命令行示例未做版本区分,仅供演示参考, 如python consle.py getBlockNumber + +* 如使用FISCO BCOS2.x的控制台,把console.py换成console2.py。如: python consle2.py getBlockNumber + +* 如使用FISCO BCOS3.x的控制台,把console.py换成console3.py。如: python consle3.py getBlockNumber +''' + +print(hint) \ No newline at end of file diff --git a/console_utils/cmd_account.py b/console_utils/cmd_account.py index c8e0374..a5447a1 100644 --- a/console_utils/cmd_account.py +++ b/console_utils/cmd_account.py @@ -27,7 +27,7 @@ from client.stattool import StatTool from client_config import client_config from console_utils.console_common import list_files from eth_account.account import Account -from eth_utils.crypto import CRYPTO_TYPE_GM +from client_config import CRYPTO_TYPE_GM from eth_utils.hexadecimal import encode_hex diff --git a/eth_account/account.py b/eth_account/account.py index 1a5d8ff..93ee256 100644 --- a/eth_account/account.py +++ b/eth_account/account.py @@ -1,4 +1,4 @@ -from collections import ( +from collections.abc import ( Mapping, ) import json diff --git a/eth_utils/types.py b/eth_utils/types.py index 59eeadd..57a387b 100644 --- a/eth_utils/types.py +++ b/eth_utils/types.py @@ -31,11 +31,11 @@ def is_boolean(value: Any) -> bool: def is_dict(obj: Any) -> bool: - return isinstance(obj, collections.Mapping) + return isinstance(obj, collections.abc.Mapping) def is_list_like(obj: Any) -> bool: - return not is_string(obj) and isinstance(obj, collections.Sequence) + return not is_string(obj) and isinstance(obj, collections.abc.Sequence) def is_list(obj: Any) -> bool: -- Gitee From a856817af9aa533646f0ed60ff453ab775bd1b18 Mon Sep 17 00:00:00 2001 From: kentzhang <20529321+coderkentzhang@users.noreply.github.com> Date: Wed, 8 Mar 2023 12:27:54 +0800 Subject: [PATCH 3/5] test demo_transaction.py --- contracts/SimpleInfo.sol | 24 ++++++++++++------------ demo_transaction.py | 4 ++-- requirements.txt | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/contracts/SimpleInfo.sol b/contracts/SimpleInfo.sol index 80268d9..ca20116 100644 --- a/contracts/SimpleInfo.sol +++ b/contracts/SimpleInfo.sol @@ -1,9 +1,8 @@ -pragma solidity ^0.4.24; - +pragma solidity ^0.6.10; contract SimpleInfo{ string name = ""; uint256 balance = 0; - address addr =0x0; + address addr = address(0); uint256 counter=0; event on_set(int retcode,string name,uint256 balance,address addr,string memo); event on_change(int retcode,string indexed name,uint256 balance,address indexed addr,string memo); @@ -16,24 +15,24 @@ contract SimpleInfo{ { } - function getname() constant public returns(string){ + function getname() view public returns(string memory){ return name; } - function getbalance() constant public returns(uint256){ + function getbalance() view public returns(uint256){ return balance; } - function getbalance1(uint256 plus) constant public returns(uint256){ + function getbalance1(uint256 plus) view public returns(uint256){ return (balance+plus); } - function getaddress() constant public returns(address){ + function getaddress() view public returns(address){ return addr; } - function getall() public constant returns(string ,uint256,address) + function getall() public view returns(string memory,uint256,address) { return (name,balance,addr); } - function getcounter() constant public returns(uint256){ + function getcounter() view public returns(uint256){ return counter; } function setbalance(uint256 b) public { @@ -45,7 +44,7 @@ contract SimpleInfo{ emit on_set_empty("empty set"); } - function set(string n,uint256 b,address a) public returns(int){ + function set(string memory n,uint256 b,address a) public returns(int){ name = n; balance = b; addr = a; @@ -62,8 +61,9 @@ contract SimpleInfo{ function reset() public returns (int){ name=""; balance = 0; - addr = 0x0; + addr = address(0); emit on_reset(-100,name); } - function() public { counter = counter+1; } + + fallback() external{ counter = counter+1; } } diff --git a/demo_transaction.py b/demo_transaction.py index 3ae7854..b31ad76 100644 --- a/demo_transaction.py +++ b/demo_transaction.py @@ -26,7 +26,7 @@ import traceback demo_config = client_config if os.path.isfile(demo_config.solc_path) or os.path.isfile(demo_config.solcjs_path): - Compiler.compile_file("contracts/HelloWorld.sol") + Compiler.compile_file("contracts/HelloWorld6.sol") Compiler.compile_file("contracts/SimpleInfo.sol") abi_file = "contracts/SimpleInfo.abi" data_parser = DatatypeParser() @@ -47,7 +47,7 @@ try: contract_name = os.path.splitext(os.path.basename(abi_file))[0] memo = "tx:" + result["transactionHash"] # 把部署结果存入文件备查 - ContractNote.save_address_to_contract_note(contract_name, + ContractNote.save_address_to_contract_note("demo",contract_name, result["contractAddress"]) # 发送交易,调用一个改写数据的接口 print("\n>>sendRawTransaction:----------------------------------------------------") diff --git a/requirements.txt b/requirements.txt index c14ea76..2b5e204 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ argcomplete==2.0.0 asyncio==3.4.3 -attrdict==2.0.1 +#attrdict==2.0.1 attrs==22.2.0 bump2version==1.0.1 bumpversion==0.6.0 @@ -14,7 +14,7 @@ ecdsa==0.18.0 exceptiongroup==1.1.0 hypothesis==6.68.2 lru_dict==1.1.8 -parsimonious==0.8.1 +#parsimonious==0.8.1 promise==2.3 pyasn1==0.4.8 pycparser==2.21 -- Gitee From 62431dfebc7a87ac56a972c5999a821a5bf8b72e Mon Sep 17 00:00:00 2001 From: kentzhang <20529321+coderkentzhang@users.noreply.github.com> Date: Wed, 8 Mar 2023 14:54:20 +0800 Subject: [PATCH 4/5] test demo get/tx --- bcos3sdk/bcos3client.py | 26 ++- client/stattool.py | 6 +- .../demo_event_callback.py | 0 demo_get.py => demo/demo_get2.py | 2 + demo/demo_get3.py | 120 +++++++++++++ demo_perf.py => demo/demo_perf.py | 166 +++++++++--------- .../demo_transaction2.py | 21 ++- demo/demo_transaction3.py | 113 ++++++++++++ 8 files changed, 361 insertions(+), 93 deletions(-) rename demo_event_callback.py => demo/demo_event_callback.py (100%) rename demo_get.py => demo/demo_get2.py (99%) create mode 100644 demo/demo_get3.py rename demo_perf.py => demo/demo_perf.py (96%) rename demo_transaction.py => demo/demo_transaction2.py (89%) create mode 100644 demo/demo_transaction3.py diff --git a/bcos3sdk/bcos3client.py b/bcos3sdk/bcos3client.py index 93ea92f..6c08f22 100644 --- a/bcos3sdk/bcos3client.py +++ b/bcos3sdk/bcos3client.py @@ -15,6 +15,7 @@ int(num,16) hex -> int hex(num) : int -> hex ''' +import itertools import json import sys import time @@ -49,7 +50,7 @@ class Bcos3Client: logger = clientlogger.logger # logging.getLogger("BcosClient") config = None sdk_version = None - + request_counter = itertools.count() def __init__(self, client_config_instance=client_config): self.lastblocklimittime = 0 @@ -165,7 +166,7 @@ class Bcos3Client: return result def getBlockNumber(self): - + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, f"{sys._getframe().f_code.co_name}") self.bcossdk.bcos_rpc_get_block_number(self.bcossdk.sdk, s2b(self.group), s2b(self.node), cbfuture.callback, byref(cbfuture.context)) @@ -175,12 +176,14 @@ class Bcos3Client: return num def getPbftView(self): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_pbft_view(self.bcossdk.sdk, s2b(self.group), s2b(self.node), cbfuture.callback, byref(cbfuture.context)) return self.wait_result(cbfuture) def getSealerList(self): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_sealer_list(self.bcossdk.sdk, s2b(self.group), s2b(self.node), cbfuture.callback, byref(cbfuture.context)) @@ -193,34 +196,40 @@ class Bcos3Client: return self.wait_result(cbfuture) def getConsensusStatus(self): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_consensus_status(self.bcossdk.sdk, s2b(self.group), s2b(self.node), cbfuture.callback, byref(cbfuture.context)) return self.wait_result(cbfuture) def getSyncStatus(self): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_sync_status(self.bcossdk.sdk, s2b(self.group), s2b(self.node), cbfuture.callback, byref(cbfuture.context)) return self.wait_result(cbfuture) def getPeers(self): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_peers(self.bcossdk.sdk, cbfuture.callback, byref(cbfuture.context)) return self.wait_result(cbfuture) def getGroupPeers(self): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_group_peers(self.bcossdk.sdk, s2b(self.group), cbfuture.callback, byref(cbfuture.context)) return self.wait_result(cbfuture) def getGroupList(self): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_group_list(self.bcossdk.sdk, cbfuture.callback, byref(cbfuture.context)) return self.wait_result(cbfuture) def getBlockByHash(self, block_hash, only_header=0, only_tx_hash=0): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_block_by_hash(self.bcossdk.sdk, s2b(self.group), s2b(self.node), s2b(block_hash), @@ -230,6 +239,7 @@ class Bcos3Client: return self.wait_result(cbfuture) def getBlockByNumber(self, num, only_header=0, only_tx_hash=0): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_block_by_number(self.bcossdk.sdk, s2b(self.group), s2b(self.node), num, @@ -239,6 +249,7 @@ class Bcos3Client: return self.wait_result(cbfuture) def getBlockHashByNumber(self, num): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_block_hash_by_number(self.bcossdk.sdk, s2b(self.group), s2b(self.node), num, @@ -246,6 +257,7 @@ class Bcos3Client: return self.wait_result(cbfuture) def getTransactionByHash(self, hash, proof=0): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_transaction(self.bcossdk.sdk, s2b(self.group), s2b(self.node), s2b(hash), @@ -254,6 +266,7 @@ class Bcos3Client: return self.wait_result(cbfuture) def getTransactionReceipt(self, hash, proof=0): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_transaction_receipt(self.bcossdk.sdk, s2b(self.group), s2b(self.node), s2b(hash), @@ -262,12 +275,14 @@ class Bcos3Client: return self.wait_result(cbfuture) def getPendingTxSize(self): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_pending_tx_size(self.bcossdk.sdk, s2b(self.group), s2b(self.node), cbfuture.callback, byref(cbfuture.context)) return self.wait_result(cbfuture) def getCode(self, address): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_code(self.bcossdk.sdk, s2b(self.group), s2b(self.node), s2b(address), @@ -275,12 +290,14 @@ class Bcos3Client: return self.wait_result(cbfuture) def getTotalTransactionCount(self): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_total_transaction_count(self.bcossdk.sdk, s2b(self.group), s2b(self.node), cbfuture.callback, byref(cbfuture.context)) return self.wait_result(cbfuture) def getSystemConfigByKey(self, key): + next(self.request_counter) cbfuture = BcosCallbackFuture(sys._getframe().f_code.co_name, "") self.bcossdk.bcos_rpc_get_system_config_by_key(self.bcossdk.sdk, s2b(self.group), s2b(self.node), s2b(key), @@ -288,10 +305,12 @@ class Bcos3Client: return self.wait_result(cbfuture) def getBlocklimit(self): + tick = time.time() tickstamp = tick - self.lastblocklimittime if tickstamp < 30: # get blocklimit every 100sec return self.blockLimit + next(self.request_counter) new_blockLimit = self.bcossdk.bcos_rpc_get_block_limit(self.bcossdk.sdk, s2b(self.group)) if new_blockLimit >= self.blockLimit: self.blockLimit = new_blockLimit @@ -299,6 +318,7 @@ class Bcos3Client: return self.blockLimit def call(self, to_address, contract_abi, fn_name, args=None): + next(self.request_counter) cmd = "call" if to_address != "": common.check_and_format_address(to_address) @@ -342,7 +362,7 @@ class Bcos3Client: def sendRawTransaction(self, to_address, contract_abi, fn_name, args=None, bin_data=None, extra_abi=None): - + next(self.request_counter) if to_address is None: to_address = "" if to_address != "": diff --git a/client/stattool.py b/client/stattool.py index 2981747..1988751 100644 --- a/client/stattool.py +++ b/client/stattool.py @@ -29,8 +29,12 @@ class StatTool: def done(self): self.time_end = time.time() + return self.till_now() + + def till_now(self): self.time_used = self.time_end - self.time_begin - + return self.time_used + def make_statmsg(self, msg): if self.time_end == 0: self.done() diff --git a/demo_event_callback.py b/demo/demo_event_callback.py similarity index 100% rename from demo_event_callback.py rename to demo/demo_event_callback.py diff --git a/demo_get.py b/demo/demo_get2.py similarity index 99% rename from demo_get.py rename to demo/demo_get2.py index 2813bd6..6ff2362 100644 --- a/demo_get.py +++ b/demo/demo_get2.py @@ -12,6 +12,8 @@ @author: kentzhang @date: 2019-06 """ +import sys +sys.path.append("./") from client.bcosclient import BcosClient import os from client.stattool import StatTool diff --git a/demo/demo_get3.py b/demo/demo_get3.py new file mode 100644 index 0000000..1a11b03 --- /dev/null +++ b/demo/demo_get3.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" + FISCO BCOS/Python-SDK is a python client for FISCO BCOS2.0 (https://github.com/FISCO-BCOS/) + FISCO BCOS/Python-SDK is free software: you can redistribute it and/or modify it under the + terms of the MIT License as published by the Free Software Foundation. This project is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Thanks for + authors and contributors of eth-abi, eth-account, eth-hash,eth-keys, eth-typing, eth-utils, + rlp, eth-rlp , hexbytes ... and relative projects + @author: kentzhang + @date: 2019-06 +""" +import sys +sys.path.append("./") +from bcos3sdk.bcos3client import Bcos3Client +from client.bcosclient import BcosClient +import os +from client.stattool import StatTool +from client.datatype_parser import DatatypeParser +from client.common.compiler import Compiler +from client_config import client_config +from client.bcoserror import BcosException, BcosError +import traceback +import json +# 从文件加载abi定义 +demo_config = client_config +''' +if os.path.isfile(demo_config.solc_path) or os.path.isfile(demo_config.solcjs_path): + Compiler.compile_file("contracts/HelloWorld.sol") + Compiler.compile_file("contracts/SimpleInfo.sol") +abi_file = "contracts/SimpleInfo.abi" +data_parser = DatatypeParser() +data_parser.load_abi_file(abi_file) +contract_abi = data_parser.contract_abi +''' +# 以下是查询类的接口,大部分是返回json,可以根据对fisco bcos rpc接口json格式的理解,进行字段获取和转码 +""" +useful helper: +int(num,16) hex -> int +hex(num) : int -> hex +""" +try: + client = Bcos3Client() + + info = client.getinfo() + print("client info:", info) + stat = StatTool.begin() + print("\n>>---------------------------------------------------------------------") + res = client.getinfo() + print("\n>>---------------------------------------------------------------------") + print("getinfo", json.dumps(res, indent=4)) + print("\n>>---------------------------------------------------------------------") + try: + res = client.getBlockNumber() + print("getBlockNumber", json.dumps(res, indent=4)) + except BcosError as e: + print("bcos client error,", e.info()) + print("\n>>---------------------------------------------------------------------") + print("getPeers", client.getPeers()) + print("\n>>---------------------------------------------------------------------") + print("getBlockByNumber", json.dumps(client.getBlockByNumber(1))) + print("\n>>---------------------------------------------------------------------") + blockhash = client.getBlockHashByNumber(1) + print("getBlockHashByNumber", blockhash) + print("\n>>---------------------------------------------------------------------") + block = client.getBlockByHash(blockhash) + print("getBlockByHash", block) + if isinstance(block, dict) and "transactions" in block.keys(): + txhash = block["transactions"][0]["hash"] + print( + "\n>>---------------------------------------------------------------------" + ) + print("getTransactionByHash", json.dumps(client.getTransactionByHash(txhash))) + print( + "\n>>---------------------------------------------------------------------" + ) + + print("getTransactionReceipt", json.dumps(client.getTransactionReceipt(txhash))) + print( + "\n>>---------------------------------------------------------------------" + ) + print("getTotalTransactionCount", client.getTotalTransactionCount()) + print("\n>>---------------------------------------------------------------------") + print("getSystemConfigByKey", client.getSystemConfigByKey("tx_count_limit")) + print("\n>>---------------------------------------------------------------------") + + print("getPbftView", client.getPbftView()) + print("\n>>---------------------------------------------------------------------") + print("getSealerList", client.getSealerList()) + print("\n>>---------------------------------------------------------------------") + print("getObserverList", client.getObserverList()) + print("\n>>---------------------------------------------------------------------") + print("getConsensusStatus", client.getConsensusStatus()) + print("\n>>---------------------------------------------------------------------") + print("getSyncStatus", client.getSyncStatus()) + print("\n>>---------------------------------------------------------------------") + print("getGroupPeers", client.getGroupPeers()) + + print("\n>>---------------------------------------------------------------------") + print("getGroupList", client.getGroupList()) + stat.done() + reqcount = next(client.request_counter) + print( + "demo get finish, total request {},usedtime {},avgtime:{}".format( + reqcount, stat.time_used, (stat.time_used / reqcount) + ) + ) + client.finish() + +except BcosException as e: + print("demo_get failed, BcosException information: {}".format(e)) + traceback.print_exc() +except BcosError as e: + print("demo_get failed, BcosError information: {}".format(e)) + traceback.print_exc() +except Exception as e: + traceback.print_exc() +client.finish() diff --git a/demo_perf.py b/demo/demo_perf.py similarity index 96% rename from demo_perf.py rename to demo/demo_perf.py index 0ccb7dc..591ebd8 100644 --- a/demo_perf.py +++ b/demo/demo_perf.py @@ -1,83 +1,83 @@ -''' - FISCO BCOS/Python-SDK is a python client for FISCO BCOS2.0 (https://github.com/FISCO-BCOS/) - FISCO BCOS/Python-SDK is free software: you can redistribute it and/or modify it under the - terms of the MIT License as published by the Free Software Foundation. This project is - distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Thanks for - authors and contributors of eth-abi, eth-account, eth-hash,eth-keys, eth-typing, eth-utils, - rlp, eth-rlp , hexbytes ... and relative projects - @file: transaction_common.py - @function: - @author: yujiechen - @date: 2019-07 -''' - -from client.common.transaction_common import TransactionCommon -from concurrent.futures import ThreadPoolExecutor -from client.bcoserror import BcosException, BcosError -import multiprocessing -import random -import sys - -contract_addr = "" -contract_path = "contracts" -contract_name = "Ok" -process_num = 8 -total_count = int(sys.argv[1]) -step = int(total_count / process_num) - - -def sendRequest(client): - try: - # generate random number - trans_num = random.randint(1, 1000) - fn_name = "trans" - fn_args = [trans_num] - client.send_transaction_getReceipt(fn_name, fn_args) - except BcosException as e: - print("call trans contract failed, reason: {}".format(e)) - except BcosError as e: - print("call trans contract failed, reason: {}".format(e)) - - -def sendMultiRequests(process_id): - """ - send trans request - """ - client = TransactionCommon("", - contract_path, - contract_name) - executor = ThreadPoolExecutor(max_workers=10) - for i in range(0, step): - executor.submit(sendRequest, (client)) - print("process {}, send {}%, tx_num: {}".format(process_id, step * 100 / total_count, step)) - executor.shutdown(True) - print("\t\t process {}, receive {} %, tx_num:{}".format( - process_id, step * 100 / total_count, step)) - - -def main(argv): - """ - 1. deploy Ok.sol - 2. send transactions: set - """ - # deploy Ok contract - gasPrice = 30000000 - client = TransactionCommon("", - contract_path, - contract_name) - result = client.send_transaction_getReceipt(None, None, gasPrice, True)[0] - contract_addr = result['contractAddress'] - client.set_contract_addr(contract_addr) - pool = multiprocessing.Pool(process_num) - args_list = [] - for i in range(0, process_num): - args_list.append(i) - pool.map(sendMultiRequests, args_list) - pool.close() - pool.join() - client.finish() - - -if __name__ == "__main__": - main(sys.argv[1:]) +''' + FISCO BCOS/Python-SDK is a python client for FISCO BCOS2.0 (https://github.com/FISCO-BCOS/) + FISCO BCOS/Python-SDK is free software: you can redistribute it and/or modify it under the + terms of the MIT License as published by the Free Software Foundation. This project is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Thanks for + authors and contributors of eth-abi, eth-account, eth-hash,eth-keys, eth-typing, eth-utils, + rlp, eth-rlp , hexbytes ... and relative projects + @file: transaction_common.py + @function: + @author: yujiechen + @date: 2019-07 +''' + +from client.common.transaction_common import TransactionCommon +from concurrent.futures import ThreadPoolExecutor +from client.bcoserror import BcosException, BcosError +import multiprocessing +import random +import sys + +contract_addr = "" +contract_path = "../contracts" +contract_name = "Ok" +process_num = 8 +total_count = int(sys.argv[1]) +step = int(total_count / process_num) + + +def sendRequest(client): + try: + # generate random number + trans_num = random.randint(1, 1000) + fn_name = "trans" + fn_args = [trans_num] + client.send_transaction_getReceipt(fn_name, fn_args) + except BcosException as e: + print("call trans contract failed, reason: {}".format(e)) + except BcosError as e: + print("call trans contract failed, reason: {}".format(e)) + + +def sendMultiRequests(process_id): + """ + send trans request + """ + client = TransactionCommon("", + contract_path, + contract_name) + executor = ThreadPoolExecutor(max_workers=10) + for i in range(0, step): + executor.submit(sendRequest, (client)) + print("process {}, send {}%, tx_num: {}".format(process_id, step * 100 / total_count, step)) + executor.shutdown(True) + print("\t\t process {}, receive {} %, tx_num:{}".format( + process_id, step * 100 / total_count, step)) + + +def main(argv): + """ + 1. deploy Ok.sol + 2. send transactions: set + """ + # deploy Ok contract + gasPrice = 30000000 + client = TransactionCommon("", + contract_path, + contract_name) + result = client.send_transaction_getReceipt(None, None, gasPrice, True)[0] + contract_addr = result['contractAddress'] + client.set_contract_addr(contract_addr) + pool = multiprocessing.Pool(process_num) + args_list = [] + for i in range(0, process_num): + args_list.append(i) + pool.map(sendMultiRequests, args_list) + pool.close() + pool.join() + client.finish() + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/demo_transaction.py b/demo/demo_transaction2.py similarity index 89% rename from demo_transaction.py rename to demo/demo_transaction2.py index b31ad76..d3401c6 100644 --- a/demo_transaction.py +++ b/demo/demo_transaction2.py @@ -12,6 +12,11 @@ @author: kentzhang @date: 2019-06 ''' +import sys + +from client.stattool import StatTool + +sys.path.append("./") from client.contractnote import ContractNote from client.bcosclient import BcosClient import os @@ -20,25 +25,25 @@ from client.datatype_parser import DatatypeParser from client.common.compiler import Compiler from client.bcoserror import BcosException, BcosError from client_config import client_config -import sys import traceback # 从文件加载abi定义 demo_config = client_config if os.path.isfile(demo_config.solc_path) or os.path.isfile(demo_config.solcjs_path): - Compiler.compile_file("contracts/HelloWorld6.sol") - Compiler.compile_file("contracts/SimpleInfo.sol") -abi_file = "contracts/SimpleInfo.abi" + Compiler.compile_file("../contracts/HelloWorld6.sol") + Compiler.compile_file("../contracts/SimpleInfo.sol") +abi_file = "../contracts/SimpleInfo.abi" data_parser = DatatypeParser() data_parser.load_abi_file(abi_file) contract_abi = data_parser.contract_abi try: + stat = StatTool.begin() client = BcosClient() print(client.getinfo()) # 部署合约 print("\n>>Deploy:----------------------------------------------------------") - with open("contracts/SimpleInfo.bin", 'r') as load_f: + with open("../contracts/SimpleInfo.bin", 'r') as load_f: contract_bin = load_f.read() load_f.close() result = client.deploy(contract_bin) @@ -88,7 +93,11 @@ try: print("call getname:", res) res = client.call(to_address, contract_abi, "getall") print("call getall result:", res) - print("done,demo_tx,total req {}".format(client.request_counter)) + reqcount = client.request_counter + stat.done() + print("done,demo_tx,total request {},usedtime {},avgtime:{}".format( + reqcount, stat.time_used, (stat.time_used / reqcount) + )) except BcosException as e: print("execute demo_transaction failed ,BcosException for: {}".format(e)) diff --git a/demo/demo_transaction3.py b/demo/demo_transaction3.py new file mode 100644 index 0000000..55992b4 --- /dev/null +++ b/demo/demo_transaction3.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +''' + FISCO BCOS/Python-SDK is a python client for FISCO BCOS2.0 (https://github.com/FISCO-BCOS/) + FISCO BCOS/Python-SDK is free software: you can redistribute it and/or modify it under the + terms of the MIT License as published by the Free Software Foundation. This project is + distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Thanks for + authors and contributors of eth-abi, eth-account, eth-hash,eth-keys, eth-typing, eth-utils, + rlp, eth-rlp , hexbytes ... and relative projects + @author: kentzhang + @date: 2019-06 +''' +import sys +sys.path.append("./") +from client.stattool import StatTool +from bcos3sdk.bcos3client import Bcos3Client +from client.contractnote import ContractNote +from client.bcosclient import BcosClient +import os +from eth_utils import to_checksum_address +from client.datatype_parser import DatatypeParser +from client.common.compiler import Compiler +from client.bcoserror import BcosException, BcosError +from client_config import client_config + +import traceback + +# 从文件加载abi定义 +demo_config = client_config + +if os.path.isfile(demo_config.solc_path) or os.path.isfile(demo_config.solcjs_path): + Compiler.compile_file("./contracts/HelloWorld6.sol") + Compiler.compile_file("./contracts/SimpleInfo.sol") +abi_file = "./contracts/SimpleInfo.abi" +data_parser = DatatypeParser() +data_parser.load_abi_file(abi_file) +contract_abi = data_parser.contract_abi + +try: + stat = StatTool.begin() + client = Bcos3Client() + print(client.getinfo()) + # 部署合约 + print("\n>>Deploy:----------------------------------------------------------") + with open("./contracts/SimpleInfo.bin", 'r') as load_f: + contract_bin = load_f.read() + load_f.close() + result = client.deploy(contract_bin) + print("deploy", result) + print("new address : ", result["contractAddress"]) + contract_name = os.path.splitext(os.path.basename(abi_file))[0] + memo = "tx:" + result["transactionHash"] + # 把部署结果存入文件备查 + ContractNote.save_address_to_contract_note("demo",contract_name, + result["contractAddress"]) + # 发送交易,调用一个改写数据的接口 + print("\n>>sendRawTransaction:----------------------------------------------------") + to_address = result['contractAddress'] # use new deploy address + args = ['simplename', 2024, to_checksum_address('0x7029c502b4F824d19Bd7921E9cb74Ef92392FB1c')] + + receipt = client.sendRawTransaction(to_address, contract_abi, "set", args) + print("receipt:", receipt) + + # 解析receipt里的log + print("\n>>parse receipt and transaction:--------------------------------------") + txhash = receipt['transactionHash'] + print("transaction hash: ", txhash) + logresult = data_parser.parse_event_logs(receipt["logEntries"]) + i = 0 + for log in logresult: + if 'eventname' in log: + i = i + 1 + print("{}): log name: {} , data: {}".format(i, log['eventname'], log['eventdata'])) + # 获取对应的交易数据,解析出调用方法名和参数 + + txresponse = client.getTransactionByHash(txhash) + inputresult = data_parser.parse_transaction_input(txresponse['input']) + print("transaction input parse:", txhash) + print(inputresult) + + # 解析该交易在receipt里输出的output,即交易调用的方法的return值 + outputresult = data_parser.parse_receipt_output(inputresult['name'], receipt['output']) + print("receipt output :", outputresult) + + # 调用一下call,获取数据 + print("\n>>Call:------------------------------------------------------------------------") + res = client.call(to_address, contract_abi, "getbalance") + print("call getbalance result:", res) + res = client.call(to_address, contract_abi, "getbalance1", [100]) + print("call getbalance1 result:", res) + res = client.call(to_address, contract_abi, "getname") + print("call getname:", res) + res = client.call(to_address, contract_abi, "getall") + print("call getall result:", res) + stat.done() + reqcount = next(client.request_counter) + print("done,demo_tx,total request {},usedtime {},avgtime:{}".format( + reqcount, stat.time_used, (stat.time_used / reqcount) + )) + +except BcosException as e: + print("execute demo_transaction failed ,BcosException for: {}".format(e)) + traceback.print_exc() +except BcosError as e: + print("execute demo_transaction failed ,BcosError for: {}".format(e)) + traceback.print_exc() +except Exception as e: + client.finish() + traceback.print_exc() +client.finish() +sys.exit(0) -- Gitee From a8877fc0345ace473b20ff35474bce0564bdf095 Mon Sep 17 00:00:00 2001 From: kentzhang <20529321+coderkentzhang@users.noreply.github.com> Date: Wed, 8 Mar 2023 15:13:00 +0800 Subject: [PATCH 5/5] update readme --- README.md | 39 ++++++++++++++++++++++++------------- demo/demo_event_callback.py | 1 + demo/demo_transaction2.py | 14 ++++++------- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 7a446a0..5c61944 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,9 @@ Python SDK为[FISCO BCOS](https://github.com/FISCO-BCOS/FISCO-BCOS/tree/master) ### 环境要求 -- Python环境:python 3.6.3, 3.7.x ,3.8.x ,3.9.x (python 3.10+的语法对依赖库的要求有较大差异,尚未适配) +- Python环境:python 3.6+ ,含 3.9.x , 3.10 + + (python 3.11+的语法,对依赖库有较大兼容性差异,尚未适配,后续跟踪各依赖库的兼容情况后再做适配) - FISCO BCOS节点:请参考 @@ -84,14 +86,17 @@ source ~/.bashrc && pyenv activate python-sdk && pip install --upgrade pip **安装依赖软件** -- 直接安装[Python-3.7.x](https://www.python.org/downloads/release/python-373/)和[git](https://git-scm.com/download/win)软件 -> python环境变量配置可参考[这里](https://jingyan.baidu.com/article/b0b63dbff271e24a4830708d.html) +- 安装[Python](https://www.python.org/downloads/) .目前(2023.03)支持到3.10版本。 +> 建议采用pyenv,virtualenv或其他多环境管理软件,管理不同版本的python以及其依赖库 - [Visual C++ 14.0库](https://visualstudio.microsoft.com/downloads) > (注:Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools"解决方法: https://visualstudio.microsoft.com/downloads (注意选择vs 2005即14.0版)或 https://pan.baidu.com/s/1ZmDUGZjZNgFJ8D14zBu9og 提取码: zrby) -- 下载Windows版本solc, 点击[这里](https://github.com/ethereum/solidity/releases/download/v0.4.25/solidity-windows.zip)下载 -> solc编译器下载成功后,解压,将其中的 solc.exe 文件复制 ${python-sdk}\bin 目录下。若 python-sdk 路为 D:\\open-source\\python-sdk, 则 solc.exe 文件复制路径为D:\\open-source\\python-sdk\\bin\\solc.exe +- 下载Windows版本solc,参考[README_SOLC](README_SOLC.md),点击[这里](https://github.com/FISCO-BCOS/solidity/releases)下载 +> 目前支持到0.6.x版本的solidity编译器 +> +> solc编译器下载成功后,解压,将其中的 solc.exe 文件复制 ${python-sdk}\bin 目录下。若 python-sdk 路为 D:\\open-source\\python-sdk, 则 solc.exe 文件复制路径为D:\\open-source\\python-sdk\\bin\\solc.exe + **拉取源代码** @@ -115,19 +120,27 @@ solc_path = "D:\\open-source\\python-sdk\\bin\\solc.exe" cd python-sdk pip install -r requirements.txt ``` -注意:目前已知parsimonious库必须采用0.8.1版本,否则在发交易时出现编码错误(提示信息类似:arg 2 type must be tuple )。如python的site-packages里已经安装了版本高于0.8.1的parsimonious库,请先pip uninstall parsimonious,再pip install parsimonious==0.8.1。 +**若因网络原因,安装依赖失败,可使用清华的pip源下载,安装命令如下:** -(或者无需再安装,因为项目代码目录已经包含了parsimonious==0.8.1的库文件) +```bash +pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt +``` -如出现因库版本依赖产生的错误,请在社区群里反馈或提issue。 +**注意:目前已知parsimonious库必须采用0.8.1版本,否则在发交易时出现编码错误(提示信息类似:arg 2 type must be tuple )。** -由于Python依赖库升级较快,且版本对齐很重要,非常建议采用virtualenv等多环境工具,为每个python应用单独管理其依赖库环境。 +如python的site-packages里已经安装了版本高于0.8.1的parsimonious库, +请先pip uninstall parsimonious,再pip install parsimonious==0.8.1。 +(项目代码目录已经包含了parsimonious==0.8.1的库文件,无需安装也可以) -> **若因网络原因,安装依赖失败,可使用清华的pip源下载,安装命令如下:** +同理,**eth_abi/eth_account/eth_hash/eth_keys/eth_rlp/eth_typing/eth_utils/gmssl/hexbytes/rlp**等外部库, +因有所改动,也在本项目内维护了一份代码,如python环境的libs库里安装了同名不同版本的冲突,同样需卸载, +以使用本项目里内置的版本。 + +**如出现因其他库版本依赖产生的错误,请在社区群里反馈或提issue** + + +Python依赖库升级较快,且版本对齐很重要,非常建议采用pyenv,virtualenv等多环境工具,为每个python应用单独管理其依赖库环境。 -```bash -pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt -``` ### 初始化配置(Windows环境可跳过) diff --git a/demo/demo_event_callback.py b/demo/demo_event_callback.py index 9ed9678..97210a4 100644 --- a/demo/demo_event_callback.py +++ b/demo/demo_event_callback.py @@ -1,4 +1,5 @@ import sys +sys.path.append("./") from client.bcosclient import BcosClient from client.datatype_parser import DatatypeParser from client.contractnote import ContractNote diff --git a/demo/demo_transaction2.py b/demo/demo_transaction2.py index d3401c6..d60609d 100644 --- a/demo/demo_transaction2.py +++ b/demo/demo_transaction2.py @@ -13,10 +13,10 @@ @date: 2019-06 ''' import sys - +sys.path.append("./") from client.stattool import StatTool -sys.path.append("./") + from client.contractnote import ContractNote from client.bcosclient import BcosClient import os @@ -30,9 +30,9 @@ import traceback demo_config = client_config if os.path.isfile(demo_config.solc_path) or os.path.isfile(demo_config.solcjs_path): - Compiler.compile_file("../contracts/HelloWorld6.sol") - Compiler.compile_file("../contracts/SimpleInfo.sol") -abi_file = "../contracts/SimpleInfo.abi" + Compiler.compile_file("./contracts/HelloWorld6.sol") + Compiler.compile_file("./contracts/SimpleInfo.sol") +abi_file = "./contracts/SimpleInfo.abi" data_parser = DatatypeParser() data_parser.load_abi_file(abi_file) contract_abi = data_parser.contract_abi @@ -43,7 +43,7 @@ try: print(client.getinfo()) # 部署合约 print("\n>>Deploy:----------------------------------------------------------") - with open("../contracts/SimpleInfo.bin", 'r') as load_f: + with open("./contracts/SimpleInfo.bin", 'r') as load_f: contract_bin = load_f.read() load_f.close() result = client.deploy(contract_bin) @@ -93,7 +93,7 @@ try: print("call getname:", res) res = client.call(to_address, contract_abi, "getall") print("call getall result:", res) - reqcount = client.request_counter + reqcount = next(client.request_counter) stat.done() print("done,demo_tx,total request {},usedtime {},avgtime:{}".format( reqcount, stat.time_used, (stat.time_used / reqcount) -- Gitee