From 478b07239567296f8e70eb0a03cbffc229e1286a Mon Sep 17 00:00:00 2001 From: Gideon Kaempfer Date: Tue, 28 Jun 2022 18:40:19 +0300 Subject: [PATCH] committee v4 forward compatibility patch --- .../committee/availability_gateway_client.py | 5 +++ committee/committee/committee.py | 41 +++++++++++++++++-- committee/committee/committee_test.py | 15 ++++++- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/committee/committee/availability_gateway_client.py b/committee/committee/availability_gateway_client.py index 3696be8..f6359a4 100644 --- a/committee/committee/availability_gateway_client.py +++ b/committee/committee/availability_gateway_client.py @@ -31,6 +31,11 @@ def _send_request(self, send_method, uri, data=None): raise BadRequest(res.status_code, res.text) return res.text + async def order_tree_height(self) -> int: + uri = "/availability_gateway/order_tree_height" + answer = await self._send_request("GET", uri) + return int(answer) + async def get_batch_data(self, batch_id: int) -> Optional[StateUpdate]: uri = f'/availability_gateway/get_batch_data?batch_id={batch_id}' answer = self._send_request('GET', uri) diff --git a/committee/committee/committee.py b/committee/committee/committee.py index a868a7d..61a2ef0 100644 --- a/committee/committee/committee.py +++ b/committee/committee/committee.py @@ -21,7 +21,7 @@ from starkware.storage.merkle_tree import MerkleTree from starkware.storage.storage import Storage -from .availability_gateway_client import AvailabilityGatewayClient +from .availability_gateway_client import AvailabilityGatewayClient, BadRequest from .custom_validation import is_valid logger = logging.getLogger(__package__) @@ -44,7 +44,8 @@ def deserialize(cls, data: bytes) -> 'CommitteeBatchInfo': class Committee: def __init__(self, config: dict, private_key: str, storage: Storage, - merkle_storage: Storage, hash_func, availability_gateway): + merkle_storage: Storage, hash_func, + availability_gateway: AvailabilityGatewayClient): self.storage = storage self.merkle_storage = merkle_storage self.hash_func = hash_func @@ -145,11 +146,43 @@ async def compute_order_root(storage): await self.storage.set_value( self.committee_batch_info_key(batch_id), batch_info.serialize()) + # In StarkEx version 4.5, the height of the order tree has changed. For an old committee + # (i.e. a committee from version 4.0 or below) to work with a version 4.5 backend, the order + # tree height must be checked against the availability gateway, and possibly changed. + # If the configured height doesn't match the height sent in response from the availability + # gateway, assert that the order tree is not validated (self.validate_orders must be False + # to swap order tree heights, otherwise the computed order root is incorrect anyway) and + # that the new height is the expected height in version 4.5 (which is 251). + # This will work when the committee is not validating orders, because in that case, the root + # provided by the availability gateway is the correct root (of the height-251 tree), so when + # the committee blindly signs this root along with the correct height, the claim will be + # approved. + # This patch will be deleted in the version 4.5 committee. + logger.info("Trying to fetch trades height from the availability gateway") + # If the API of order_tree_height exist in the Availability Gateway use it. Otherwise, + # stick with the configured configured_trades_height (this can happen if the SE + # Availability Gateway is using an old SE version whcih don't have the + # order_tree_height API). + trades_height = self.orders_merkle_height + try: + trades_height = await self.availability_gateway.order_tree_height() + if self.orders_merkle_height != trades_height: + assert not validate_orders, ( + f"validate_orders is {validate_orders}, but configured trades height " + f"{self.orders_merkle_height} is not equal to response from the availability " + f"gateway ({trades_height}). This indicates that the root of the order " + f"tree was computed incorrectly and the claim will not be approved by the " + f"availability gateway, so there is no point in signing and sending the " + f"signature." + ) + except BadRequest: + pass + logger.info(f'Signing batch with sequence number {batch_info.sequence_number}') availability_claim = hash_availability_claim( batch_info.vaults_root, self.vaults_merkle_height, batch_info.orders_root, - self.orders_merkle_height, batch_info.sequence_number) + trades_height, batch_info.sequence_number) signature = eth.Account._sign_hash(availability_claim, self.account.key).signature.hex() return signature, availability_claim.hex() @@ -221,4 +254,4 @@ async def async_hash_func(x, y): if __name__ == '__main__': - sys.exit(asyncio.run(main())) + sys.exit(asyncio.run(main())) \ No newline at end of file diff --git a/committee/committee/committee_test.py b/committee/committee/committee_test.py index 8b6c1ca..d6f2153 100644 --- a/committee/committee/committee_test.py +++ b/committee/committee/committee_test.py @@ -10,11 +10,22 @@ from .committee import Committee +ORDER_TREE_HEIGHT = 63 + + +class AvailabilityGatewayClientMock: + def __init__(self): + pass + + async def order_tree_height(self) -> int: + return ORDER_TREE_HEIGHT + + @pytest.fixture def committee(): config = { 'VAULTS_MERKLE_HEIGHT': 31, - 'ORDERS_MERKLE_HEIGHT': 63, + 'ORDERS_MERKLE_HEIGHT': ORDER_TREE_HEIGHT, 'POLLING_INTERVAL': 1, } @@ -24,7 +35,7 @@ def committee(): storage=MockStorage(), merkle_storage=MockStorage(), hash_func=async_pedersen_hash_func, - availability_gateway=None) + availability_gateway=AvailabilityGatewayClientMock()) @pytest.fixture