def max_byzantium(self) -> int: """ Maximum number of Byzantine nodes """ return get_f(self.consensus_node_config_list)
import time import allure import pytest from common import log from deploy.deploy import AutoDeployPlaton from common.connect import connect_web3 from conf import setting as conf from common.load_file import get_f, get_node_info, get_node_list node_yml = conf.NODE_YML collusion_list, _ = get_node_list(node_yml) f = int(get_f(collusion_list)) n = len(collusion_list) auto = AutoDeployPlaton() url_list, enode_list, nodeid_list, ip_list, _ = get_node_info( node_yml)["collusion"] genesis_file = conf.GENESIS_TMP static_node_file = conf.STATIC_NODE_FILE def teardown_function(): log.info("关闭所有节点") auto.kill_of_yaml(node_yml) def teardown_module(): auto.start_all_node(node_yml)
class TestConsensus: node_yml = conf.NODE_YML consensus_list, _ = get_node_list(node_yml) f = get_f(consensus_list) n = len(consensus_list) url_list, enode_list, nodeid_list, ip_list, _ = get_node_info( node_yml)["collusion"] genesis_path = conf.GENESIS_TMP auto = AutoDeployPlaton() cbft_path = conf.CBFT_TMP cbft_template = conf.CBFT_TEMPLATE def teardown_class(self): self.auto.start_all_node(self.node_yml) def get_cbft_json_data(self, period, duration): with open(self.cbft_template, 'r', encoding='utf-8') as f: res = json.loads(f.read()) res['period'] = period res['duration'] = duration with open(self.cbft_path, 'w', encoding='utf-8') as b: cbft_json = json.dumps(res) b.write(cbft_json) @allure.title("每个节点在窗口期正常出块") def test_block_out_of_each_node_window(self): """ 用例id:73 测试 N 个节点每个窗口期都在出块 """ log.info("更新cbft文件") self.get_cbft_json_data(period=1, duration=10) auto = AutoDeployPlaton(cbft=self.cbft_path) auto.start_all_node(self.node_yml) log.info("跟所有节点建立连接") w3_list = [connect_web3(url) for url in self.url_list] w3 = w3_list[0] start_block = w3.eth.blockNumber time.sleep(self.n * 10 + 5) block_number = w3.eth.blockNumber if block_number > 0: log.info("正在出块,块高:{}".format(block_number)) node_id_dict = {} log.info("获取1至{}块的nodeID".format(block_number)) for block in range(start_block, block_number + 1): node_id = get_pub_key(self.url_list[0], block) if node_id not in node_id_dict.keys(): node_id_dict[node_id] = 1 else: node_id_dict[node_id] += 1 log.info("nodeID对应的出块数{}".format(node_id_dict)) assert self.n == len(node_id_dict), "出块节点数少于共识节点数" for k, v in node_id_dict.items(): assert 0 <= v <= 20, "节点{}出块周期约为10个块,实际为{}".format(k, v) @allure.title("cbft.json配置period{period}-{duration}") @pytest.mark.parametrize('period,duration', [(1, 10), (3, 30), (5, 50), (10, 100), (0, 10)]) def test_block_time_period(self, period, duration): ''' 用例id 1,2,3,4,5 测试period的不同值,观察查看时间 根据5种场景,分别出块时间约为1,3,5,10,1s ''' log.info("更新cbft.json") self.get_cbft_json_data(period, duration) auto = AutoDeployPlaton(cbft=self.cbft_path) auto.start_all_node(self.node_yml) time.sleep(duration + 5) log.info("跟所有节点建立连接") w3_list = [connect_web3(url) for url in self.url_list] w3 = w3_list[0] block_number = w3.eth.blockNumber assert block_number > 1, "没有正常出块" log.info(block_number) start_time = w3.eth.getBlock(1).get("timestamp") end_time = w3.eth.getBlock(block_number).get("timestamp") use_time = end_time - start_time average_time = int(use_time / (block_number - 1)) log.info("平均出块时间{}".format(average_time)) if period == 0: period = 1 deviation = int(period * 1000 * 0.5) assert period * 1000 - deviation < average_time < period * \ 1000 + deviation, "出块间隔过大或过小" @allure.title("cbft.json配置period{period}-{duration}-{delay_time}--{number}" ) @pytest.mark.parametrize('period,duration,delay_time,number', [(1, 10, 50, 30), (1, 20, 90, 70), (1, 30, 130, 90), (1, 50, 180, 140), (1, 100, 350, 250)]) def test_block_cycle_duration(self, period, duration, delay_time, number): ''' 用例id 6,7,8,9,10 测试duration的不同值,观察出块周期 根据5种场景,出块周期约为10,20,30,50,100 ''' self.get_cbft_json_data(period, duration) auto = AutoDeployPlaton(cbft=self.cbft_path) log.info("上传cbft文件成功") auto.start_all_node(self.node_yml) time.sleep(delay_time) log.info("跟所有节点建立连接") w3_list = [connect_web3(url) for url in self.url_list] w3 = w3_list[0] block_number = w3.eth.blockNumber if block_number > 0: log.info("正在出块,块高:{}".format(block_number)) if block_number < number: raise Exception("出块很慢,没达到预期{}".format(number)) node_id_dict = {} log.info("获取1至{}块的nodeID".format(number)) for block in range(1, number): node_id = get_pub_key(self.url_list[0], block) if node_id not in node_id_dict.keys(): node_id_dict[node_id] = [block] else: node_id_dict[node_id].append(block) log.info("获取到全部的nodeID对应的出块".format(node_id_dict)) log.info("由于第一组nodeID收集数据不全,从第二组开始收集统计,删除第一组") node_id_list = [] for node_id in node_id_dict.keys(): node_id_list.append(node_id) node_id_dict.pop(node_id_list[0]) log.info("统计出nodeID对应的出块ID{}".format(node_id_dict)) print(node_id_dict) print(node_id_list) if duration == 10: block_cycle_a = node_id_dict.get(node_id_list[1]) log.info("出块人A出块周期数:%s" % block_cycle_a) assert 7 <= len(block_cycle_a) <= 12, "出块周期预期在7到12,实际{}".format( len(block_cycle_a)) block_cycle_b = node_id_dict.get(node_id_list[2]) log.info("出块人B出块周期数:%s" % block_cycle_b) assert 7 <= len(block_cycle_b) <= 12, "出块周期预期在7到12,实际{}".format( len(block_cycle_b)) times_tamp_a = w3.eth.getBlock(block_cycle_a[-1]).get("timestamp") times_tamp_b = w3.eth.getBlock(block_cycle_b[-1]).get("timestamp") log.info("获取出块人B的最后一个块的时间戳%s" % times_tamp_b) assert 8000 < times_tamp_b - \ times_tamp_a < 12000, "预期出块周期为8到12s,实际为{}".format( times_tamp_b - times_tamp_a) log.info( "出块人B最后一个块出块时间-出块人A最后一个块出块时间 = 出块周期时间{}".format(times_tamp_b - times_tamp_a)) if duration == 20: block_cycle_a = node_id_dict.get(node_id_list[1]) log.info("出块人A出块周期数:%s" % block_cycle_a) assert 16 <= len(block_cycle_a) <= 23, "出块周期预期在16到23,实际{}".format( len(block_cycle_a)) block_cycle_b = node_id_dict.get(node_id_list[2]) log.info("出块人B出块周期数:%s" % block_cycle_b) assert 16 <= len(block_cycle_b) <= 23, "出块周期预期在16到23,实际{}".format( len(block_cycle_b)) times_tamp_a = w3.eth.getBlock(block_cycle_a[-1]).get("timestamp") times_tamp_b = w3.eth.getBlock(block_cycle_b[-1]).get("timestamp") log.info("获取出块人B的最后一个块的时间戳%s" % times_tamp_b) assert 16000 < times_tamp_b - times_tamp_a < 23000, "预期出块周期为16到23s,实际为{}".format( times_tamp_b - times_tamp_a) log.info( "出块人B最后一个块出块时间-出块人A最后一个块出块时间 = 出块周期时间{}".format(times_tamp_b - times_tamp_a)) if duration == 30: block_cycle_a = node_id_dict.get(node_id_list[1]) log.info("出块人A出块周期数:%s" % block_cycle_a) assert 26 <= len(block_cycle_a) <= 33, "出块周期预期在26到33,实际{}".format( len(block_cycle_a)) block_cycle_b = node_id_dict.get(node_id_list[2]) log.info("出块人B出块周期数:%s" % block_cycle_b) assert 26 <= len(block_cycle_b) <= 33, "出块周期预期在26到33,实际{}".format( len(block_cycle_b)) times_tamp_a = w3.eth.getBlock(block_cycle_a[-1]).get("timestamp") times_tamp_b = w3.eth.getBlock(block_cycle_b[-1]).get("timestamp") log.info("获取出块人B的最后一个块的时间戳%s" % times_tamp_b) assert 26000 < times_tamp_b - times_tamp_a < 33000, "预期出块周期为26到30s,实际为{}".format( times_tamp_b - times_tamp_a) log.info( "出块人B最后一个块出块时间-出块人A最后一个块出块时间 = 出块周期时间{}".format(times_tamp_b - times_tamp_a)) if duration == 50: block_cycle_a = node_id_dict.get(node_id_list[1]) log.info("出块人A出块周期数:%s" % block_cycle_a) assert 40 <= len(block_cycle_a) <= 60, "出块周期预期在40到60,实际{}".format( len(block_cycle_a)) block_cycle_b = node_id_dict.get(node_id_list[2]) log.info("出块人B出块周期数:%s" % block_cycle_b) assert 40 <= len(block_cycle_b) <= 60, "出块周期预期在40到60,实际{}".format( len(block_cycle_b)) times_tamp_a = w3.eth.getBlock(block_cycle_a[-1]).get("timestamp") times_tamp_b = w3.eth.getBlock(block_cycle_b[-1]).get("timestamp") log.info("获取出块人B的最后一个块的时间戳%s" % times_tamp_b) assert 4000 < times_tamp_b - times_tamp_a < 60000, "预期出块周期为40到60s,实际为{}".format( times_tamp_b - times_tamp_a) log.info( "出块人B最后一个块出块时间-出块人A最后一个块出块时间 = 出块周期时间{}".format(times_tamp_b - times_tamp_a)) if duration == 100: block_cycle_a = node_id_dict.get(node_id_list[1]) log.info("出块人A出块周期数:%s" % block_cycle_a) assert 90 <= len( block_cycle_a) <= 110, "出块周期预期在90到110,实际{}".format( len(block_cycle_a)) block_cycle_b = node_id_dict.get(node_id_list[2]) log.info("出块人B出块周期数:%s" % block_cycle_b) assert 90 <= len( block_cycle_b) <= 110, "出块周期预期在90到110,实际{}".format( len(block_cycle_b)) times_tamp_a = w3.eth.getBlock(block_cycle_a[-1]).get("timestamp") times_tamp_b = w3.eth.getBlock(block_cycle_b[-1]).get("timestamp") log.info("获取出块人B的最后一个块的时间戳%s" % times_tamp_b) assert 90000 < times_tamp_b - times_tamp_a < 110000, "预期出块周期为99到110s,实际为{}".format( times_tamp_b - times_tamp_a) log.info( "出块人B最后一个块出块时间-出块人A最后一个块出块时间 = 出块周期时间{}".format(times_tamp_b - times_tamp_a)) @allure.title("重启节点后查看旧块交易,钱包余额") def test_kill_process_observation_block_data(self): ''' 用例id 30,31,32,33 测试kill进程后,重启查看块高持续增长 测试kill进程后,重启查看旧块转账,合约信息不变 测试kill进程后,钱包余额不变 ''' log.info("部署节点") self.auto.start_all_node(self.node_yml) log.info("启动会等待60s出块") time.sleep(10) log.info("跟所有节点建立连接") w3_list = [connect_web3(url) for url in self.url_list] w3 = w3_list[0] number_before = w3.eth.blockNumber if number_before == 0: raise Exception("起服务但未出块") log.info("块高为:{}".format(number_before)) log.info("发起转账交易") t_hash = self.transaction(w3) result, number, result_block, hash_list = self.check_block_information( w3, t_hash) log.info("发起合约交易") contract_address, resp, contract_number = self.deploy_contract() log.info("kill 所有节点") self.auto.kill_of_yaml(self.node_yml) time.sleep(2) log.info("重启platon服务") self.auto.start_all_node(self.node_yml, is_need_init=False) log.info("重启25节点后,延迟30s") time.sleep(30) w3_list = [connect_web3(url) for url in self.url_list] w3 = w3_list[0] number_after = w3.eth.blockNumber assert number_after >= number_before, "块高未有增长" balance = w3.eth.getBalance(w3.eth.accounts[1]) assert balance == 100000, "kill进程重启后余额发生变化,余额为:{}".format(balance) log.info("查看重启前的{}区块转账信息".format(number)) t_hash_list = (w3.eth.getBlock(number).get("transactions")) log.info("查看重启前的{}区块合约信息".format(contract_number)) c_hash_list = (w3.eth.getBlock(contract_number).get("transactions")) log.info("通过transactions字段得到的交易哈希列表:{}".format(hash_list)) assert t_hash in t_hash_list, "kill进程重启后转账交易丢失" c_hash = HexBytes(resp) assert c_hash in c_hash_list, "kill进程重启后合约交易丢失" contract_address_after = w3.eth.waitForTransactionReceipt(resp).get( 'contractAddress') assert contract_address == contract_address_after, "kill进程后,合约地址发生改变" def check_block_information(self, w3, hash): transaction_hash = HexBytes(hash).hex() result = w3.eth.waitForTransactionReceipt(transaction_hash) number = result.get("blockNumber") result_block = w3.eth.getBlock(number) hash_list = result_block.get("transactions") return result, number, result_block, hash_list def transaction(self, w3, value=100000): from_address = w3.toChecksumAddress(w3.eth.accounts[0]) to_address = w3.toChecksumAddress(w3.personal.newAccount('88888888')) log.info("解锁账号") w3.personal.unlockAccount(from_address, '88888888', 666666) params = { 'to': to_address, 'from': from_address, 'gas': 91000000, 'gasPrice': 9000000000, 'value': value } t_hash = w3.eth.sendTransaction(params) return t_hash def deploy_contract(self): consensus_list, _ = get_node_list(self.node_yml) url = consensus_list[0]['url'] wt = PlatonContractTransaction(url) addrress = wt.w3.toChecksumAddress(conf.ADDRESS) wt.w3.personal.unlockAccount(addrress, conf.PASSWORD, 99999999) log.info("部署合约") resp = wt.contract_deploy( get_byte_code(abspath('./data/contract/sum.wasm')), get_abi_bytes(abspath('./data/contract/sum.cpp.abi.json')), addrress) log.info("获取合约交易信息") result = wt.eth.waitForTransactionReceipt(resp) contract_address = result['contractAddress'] contract_number = result['blockNumber'] return contract_address, resp, contract_number
''' import time from hexbytes import HexBytes from client_sdk_python import Web3 from client_sdk_python.eth import Eth from common.connect import connect_web3 from common.load_file import get_node_list, get_f from conf import setting as conf from utils.platon_lib.send_raw_transaction import send_raw_transaction from deploy.deploy import generate_init_node node_yml = conf.NODE_YML collusion_list, nocollusion_list = get_node_list(node_yml) f = get_f(collusion_list) send_address = Web3.toChecksumAddress( "0xdB245C0ebbCa84395c98c3b2607863cA36ABBD79") send_privatekey = "b735b2d48e5f6e1dc897081f8655fdbb376ece5b2b648c55eee72c38102a0357" def setup_module(): collusion_list_p2p, _ = generate_init_node(collusion_list) for node in nocollusion_list: w3 = connect_web3(node["url"]) for p2p in collusion_list_p2p: w3.admin.addPeer(p2p) time.sleep(10) def transaction(w3,