From 2feeae404f7b16195f4ad87eff2b0b33742ebc9d Mon Sep 17 00:00:00 2001 From: badrogger Date: Fri, 1 Mar 2024 19:08:36 +0000 Subject: [PATCH 1/5] Add missing DKGStep enum option --- core/schains/dkg/structures.py | 5 +++-- core/schains/monitor/action.py | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/schains/dkg/structures.py b/core/schains/dkg/structures.py index b46b2456b..397b81b04 100644 --- a/core/schains/dkg/structures.py +++ b/core/schains/dkg/structures.py @@ -42,8 +42,9 @@ class DKGStep(int, Enum): COMPLAINT_BAD_DATA = 6 COMPLAINT_NO_ALRIGHT = 7 COMPLAINT_NO_RESPONSE = 8 - RESPONSE = 9 - KEY_GENERATION = 10 + PRE_RESPONSE = 9 + RESPONSE = 10 + KEY_GENERATION = 11 class ComplaintReason(int, Enum): diff --git a/core/schains/monitor/action.py b/core/schains/monitor/action.py index 3a9438916..5f6b02d65 100644 --- a/core/schains/monitor/action.py +++ b/core/schains/monitor/action.py @@ -173,7 +173,7 @@ def config_dir(self) -> bool: def dkg(self) -> bool: initial_status = self.checks.dkg.status if not initial_status: - logger.info('Running run_dkg') + logger.info('Initiing dkg client') dkg_client = get_dkg_client( skale=self.skale, node_id=self.node_config.id, @@ -181,6 +181,7 @@ def dkg(self) -> bool: sgx_key_name=self.node_config.sgx_key_name, rotation_id=self.rotation_id ) + logger.info('Running run_dkg') dkg_result = run_dkg( dkg_client=dkg_client, skale=self.skale, From 2e7ba08ffced76e9078f5d5008baf4b9c5633a44 Mon Sep 17 00:00:00 2001 From: badrogger Date: Mon, 4 Mar 2024 16:54:36 +0000 Subject: [PATCH 2/5] Add broadcast bad data test --- tests/dkg_test/main_test.py | 162 ++++++++++++++++++++++++++++++++++-- 1 file changed, 155 insertions(+), 7 deletions(-) diff --git a/tests/dkg_test/main_test.py b/tests/dkg_test/main_test.py index 68b963a12..fcf8632a0 100644 --- a/tests/dkg_test/main_test.py +++ b/tests/dkg_test/main_test.py @@ -14,13 +14,20 @@ import pytest import warnings from skale import Skale -from skale.utils.account_tools import send_eth +from skale.contracts.manager.dkg import G2Point, KeyShare from skale.wallets import SgxWallet +from skale.utils.account_tools import send_eth from skale.utils.contracts_provision import DEFAULT_DOMAIN_NAME +from core.schains.dkg.client import DkgError from core.schains.dkg.main import get_dkg_client, is_last_dkg_finished, run_dkg from core.schains.dkg.structures import DKGStatus, DKGStep +from core.schains.dkg.utils import DKGKeyGenerationError, generate_bls_keys from core.schains.config import init_schain_config_dir +from core.schains.config.generator import get_schain_nodes_with_schains + +from tools.configs import SGX_SERVER_URL, SGX_CERTIFICATES_FOLDER +from tools.configs.schains import SCHAINS_DIR_PATH from tests.dkg_test import N_OF_NODES, TEST_ETH_AMOUNT, TYPE_OF_NODES from tests.utils import ( @@ -30,10 +37,6 @@ set_automine, set_interval_mining ) -from tools.configs import SGX_SERVER_URL, SGX_CERTIFICATES_FOLDER -from tools.configs.schains import SCHAINS_DIR_PATH -from core.schains.dkg.utils import DKGKeyGenerationError, generate_bls_keys -from core.schains.dkg.client import DkgError warnings.filterwarnings("ignore") @@ -54,8 +57,9 @@ class DkgTestError(Exception): class DKGRunType(int, Enum): NORMAL = 0 BROADCAST_FAILED = 1 - ALRIGHT_FAILED = 2 - COMPLAINT_FAILED = 3 + NO_BROADCAST = 2 + ALRIGHT_FAILED = 3 + COMPLAINT_FAILED = 4 def generate_sgx_wallets(skale, n_of_keys): @@ -150,6 +154,93 @@ def get_dkg_runners(skale, skale_sgx_instances, schain_name, nodes): return runners +def generate_poly_name(group_index_str, node_id, dkg_id): + return ( + "POLY:SCHAIN_ID:" + f"{group_index_str}" + ":NODE_ID:" + f"{str(node_id)}" + ":DKG_ID:" + f"{str(dkg_id)}" + ) + + +def get_node_id_dkg_and_public_keys(schain_nodes, node_id): + node_id_dkg = -1 + public_keys = [0] * len(schain_nodes) + for i, node in enumerate(schain_nodes): + if node['id'] == node_id: + node_id_dkg = i + + public_keys[i] = node["publicKey"] + return node_id_dkg, public_keys + + +def convert_g2_points_to_array(data): + g2_array = [] + for point in data: + new_point = [] + for coord in point: + new_coord = int(coord) + new_point.append(new_coord) + g2_array.append(G2Point(*new_point).tuple) + return g2_array + + +def convert_str_to_key_share(sent_secret_key_contribution, n): + return_value = [] + for i in range(n): + public_key = sent_secret_key_contribution[i * 192: i * 192 + 128] + key_share = bytes.fromhex(sent_secret_key_contribution[i * 192 + 128: (i + 1) * 192]) + return_value.append(KeyShare(public_key, key_share).tuple) + return return_value + + +def generate_broadcast_data(skale, schain_name, node_id): + schain_nodes = get_schain_nodes_with_schains(skale, schain_name) + node_id_dkg, public_keys = get_node_id_dkg_and_public_keys(schain_nodes, node_id) + client = skale.wallet.sgx_client + + n = len(schain_nodes) + t = (2 * n + 1) // 3 + client.n, client.t = n, t + + group_index = skale.schains.name_to_group_id(schain_name) + group_index_str = str(int(skale.web3.to_hex(group_index)[2:], 16)) + rotation = skale.node_rotation.get_rotation(schain_name) + + rotation_id = rotation['rotation_id'] + poly_name = generate_poly_name(group_index_str, node_id_dkg, rotation_id) + + client.generate_dkg_poly(poly_name) + + verification_vector = client.get_verification_vector(poly_name) + secret_key_contribution = client.get_secret_key_contribution_v2(poly_name, public_keys) + + return [ + convert_g2_points_to_array(verification_vector), + convert_str_to_key_share(secret_key_contribution, n) + ] + + +def send_fake_broadcast( + skale, + schain_name, + node_id, + rotation_id=0 +): + group_index = skale.schains.name_to_group_id(schain_name).hex() + verification_vector, _ = generate_broadcast_data(skale, schain_name, node_id) + secret_key_contribution = [([b'\x18\x80\xba1\xce\x8a\x1e[B\xc3\xb5\xeb]\x84\xfc\xc7\xefwp_\xaf\xbdL\xe3\xc2\xd8\xd2\xb9\nu\xb3]', b'^D\xbcF4q\xc3\\oa"\x16\x8c\xe9\xc4\xf6\x03\xf4\xcf\xac\xd0\x9b\xb2\x1f\x8c:\xa4\x18\x9e\x03q\x82'], b'\xf6\xa3\xe3\x87[\x97m\x07\xd2\x0e2C8\x88\x1e\x8c\xa6i:\xc9$/YsdY \x14\xb6\xa6g\x03'), ([b'3"\xb4_:LN(\x8f\xdcu\xb9.\x1a\x98n\x7f\x8f\x89\xc2\xe1\\\x83\x15\x8e\xff\xca\xe5\xf7\xf7\x82\xff', b'\x9d\x12C \x8dw}\xa3_\xb3\xcd\x8d\xe7\x17I?S\x81\xbe\xca\xf9u2\xd3]\xe8p N\xf0\xc5\x07'], b'\xc3\xb1\xff\xff"\xa4.1_\xd7\xaa\xad!9\xd6\xd2\xbc\xb5(\x04\x9f5\x1d\xc3\xc1{\xdato(\x92\x82')] # noqa + return skale.dkg.broadcast( + group_index, + node_id, + verification_vector, + secret_key_contribution, + rotation_id + ) + + @contextmanager def dkg_test_client( skale: Skale, @@ -165,6 +256,9 @@ def dkg_test_client( effect = DkgError('Broadcast failed on purpose') method, original = 'broadcast', dkg_client.skale.dkg.broadcast dkg_client.skale.dkg.broadcast = mock.Mock(side_effect=effect) + if run_type == DKGRunType.NO_BROADCAST: + method, original = 'broadcast', dkg_client.skale.dkg.broadcast + dkg_client.skale.dkg.broadcast = mock.Mock() elif run_type == DKGRunType.ALRIGHT_FAILED: effect = DkgError('Alright failed on purpose') method, original = 'alright', dkg_client.skale.dkg.alright @@ -593,6 +687,60 @@ def test_dkg_procedure_complaint_failed( assert not skale.dkg.is_last_dkg_successful(gid) assert not is_last_dkg_finished(skale, schain_name) + def test_dkg_procedure_boradcast_bad_data( + self, + skale, + schain_creation_data, + skale_sgx_instances, + nodes, + dkg_timeout_small, + no_automine, + interval_mining, + schain + ): + schain_name, _ = schain_creation_data + assert not is_last_dkg_finished(skale, schain_name) + nodes.sort(key=lambda x: x['node_id']) + runners = get_dkg_runners( + skale, + skale_sgx_instances, + schain_name, + nodes + ) + + runners[0] = functools.partial( + run_node_dkg, + skale_sgx_instances[0], + schain_name, + 0, + nodes[0]['node_id'], + runs=(DKGRunType.NO_BROADCAST,) + ) + # Sending bad brodcast without runner + send_fake_broadcast(skale_sgx_instances[0], schain_name, nodes[0]['node_id']) + for i in range(1, N_OF_NODES): + runners[i] = functools.partial( + run_node_dkg, + skale_sgx_instances[i], + schain_name, + i, + nodes[i]['node_id'], + runs=(DKGRunType.NORMAL,) + ) + results = exec_dkg_runners(runners) + assert len(results) == N_OF_NODES + gid = skale.schains.name_to_id(schain_name) + + for i, (node_data, result) in enumerate(zip(nodes, results)): + assert result.status == DKGStatus.FAILED + if i == 0: + assert result.step == DKGStep.RESPONSE + else: + assert result.step == DKGStep.COMPLAINT_BAD_DATA + assert result.keys_data is None + assert not skale.dkg.is_last_dkg_successful(gid) + assert not is_last_dkg_finished(skale, schain_name) + @pytest.fixture def no_ids_for_schain_skale(self, skale): get_node_ids_f = skale.schains_internal.get_node_ids_for_schain From 23c4a2aa0eb1f4f0922865f61c2f49c84f4b1bb9 Mon Sep 17 00:00:00 2001 From: badrogger Date: Mon, 4 Mar 2024 16:58:52 +0000 Subject: [PATCH 3/5] Small broadcast bad data test improvement --- core/schains/monitor/action.py | 2 +- tests/dkg_test/main_test.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/schains/monitor/action.py b/core/schains/monitor/action.py index 5f6b02d65..9ee78af1b 100644 --- a/core/schains/monitor/action.py +++ b/core/schains/monitor/action.py @@ -173,7 +173,7 @@ def config_dir(self) -> bool: def dkg(self) -> bool: initial_status = self.checks.dkg.status if not initial_status: - logger.info('Initiing dkg client') + logger.info('Initing dkg client') dkg_client = get_dkg_client( skale=self.skale, node_id=self.node_config.id, diff --git a/tests/dkg_test/main_test.py b/tests/dkg_test/main_test.py index fcf8632a0..65ac60879 100644 --- a/tests/dkg_test/main_test.py +++ b/tests/dkg_test/main_test.py @@ -708,6 +708,9 @@ def test_dkg_procedure_boradcast_bad_data( nodes ) + # Sending bad brodcast without runner + send_fake_broadcast(skale_sgx_instances[0], schain_name, nodes[0]['node_id']) + # Modifing runner to skip broadcast runners[0] = functools.partial( run_node_dkg, skale_sgx_instances[0], @@ -716,8 +719,6 @@ def test_dkg_procedure_boradcast_bad_data( nodes[0]['node_id'], runs=(DKGRunType.NO_BROADCAST,) ) - # Sending bad brodcast without runner - send_fake_broadcast(skale_sgx_instances[0], schain_name, nodes[0]['node_id']) for i in range(1, N_OF_NODES): runners[i] = functools.partial( run_node_dkg, From 0fa059cdb99dfd0cad45b549bf1e073898db4809 Mon Sep 17 00:00:00 2001 From: badrogger Date: Mon, 4 Mar 2024 18:13:18 +0000 Subject: [PATCH 4/5] Fix typo --- tests/dkg_test/main_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/dkg_test/main_test.py b/tests/dkg_test/main_test.py index 65ac60879..e8d2471fb 100644 --- a/tests/dkg_test/main_test.py +++ b/tests/dkg_test/main_test.py @@ -687,7 +687,7 @@ def test_dkg_procedure_complaint_failed( assert not skale.dkg.is_last_dkg_successful(gid) assert not is_last_dkg_finished(skale, schain_name) - def test_dkg_procedure_boradcast_bad_data( + def test_dkg_procedure_broadcast_bad_data( self, skale, schain_creation_data, From 6b5535a5df4edf034f18559665c96ec170abeb24 Mon Sep 17 00:00:00 2001 From: badrogger Date: Mon, 4 Mar 2024 20:50:01 +0000 Subject: [PATCH 5/5] Bump version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e70b4523a..6a6a3d8e3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.6.0 +2.6.1