Skip to content

Commit

Permalink
Setup integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hweawer committed Sep 3, 2024
1 parent 2d86a87 commit 54ba420
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 15 deletions.
1 change: 1 addition & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
run: |
poetry run pytest tests -m integration_chiado
env:
WEB3_RPC_ENDPOINTS: "https://gnosis-chiado-rpc.publicnode.com"
ONCHAIN_TRANSPORT_RPC_ENDPOINTS: "https://gnosis-chiado-rpc.publicnode.com"
ONCHAIN_TRANSPORT_ADDRESS: "0x42E1DEfC18388E3AA1fCADa851499A11405cf37f"
DEPOSIT_CONTRACT: "0x4242424242424242424242424242424242424242"
Expand Down
45 changes: 45 additions & 0 deletions interfaces/DataBusContract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[
{
"anonymous": true,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "eventId",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"indexed": false,
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "Message",
"type": "event"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "_eventId",
"type": "bytes32"
},
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
}
],
"name": "sendMessage",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
18 changes: 18 additions & 0 deletions src/blockchain/contracts/data_bus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import logging

from blockchain.contracts.base_interface import ContractInterface
from web3.contract.contract import ContractFunction

logger = logging.getLogger(__name__)


class DataBusContract(ContractInterface):
abi_path = './interfaces/DataBusContract.json'

def send_message(self, event_id: bytes, mes: bytes) -> ContractFunction:
"""
Build send message transaction to Data Bus contract
"""
tx = self.functions.send_message(event_id, mes)
logger.info({'msg': 'Build `send_message(...)` tx.'})
return tx
95 changes: 95 additions & 0 deletions src/transport/msg_providers/onchain_sender.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from blockchain.contracts.data_bus import DataBusContract
from transport.msg_providers.onchain_transport import (
DEPOSIT_V1_DATA_SCHEMA,
PAUSE_V2_DATA_SCHEMA,
PAUSE_V3_DATA_SCHEMA,
PING_V1_DATA_SCHEMA,
UNVET_V1_DATA_SCHEMA,
OnchainTransportSinks,
)
from transport.msg_types.deposit import DepositMessage
from transport.msg_types.pause import PauseMessage
from transport.msg_types.ping import PingMessage
from transport.msg_types.unvet import UnvetMessage
from utils.bytes import from_hex_string_to_bytes
from web3 import Web3


class OnchainTransportSender:
"""
Is used in tests to create sequence of the events emitted from the DataBus contract
"""

_DEFAULT_SIGNATURE = from_hex_string_to_bytes(
'0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
)

def __init__(self, w3: Web3, data_bus_contract: DataBusContract):
self._w3 = w3
self._data_bus = data_bus_contract

def send_deposit(self, deposit_mes: DepositMessage):
deposit_topic = self._w3.keccak(text=OnchainTransportSinks.DEPOSIT_V1)
deposit_root, nonce, block_number, block_hash, staking_module_id, app = (
deposit_mes['depositRoot'],
deposit_mes['nonce'],
deposit_mes['blockNumber'],
deposit_mes['blockHash'],
deposit_mes['stakingModuleId'],
(deposit_mes['app']['version'],),
)
mes = self._w3.codec.encode(
types=[DEPOSIT_V1_DATA_SCHEMA],
args=[(deposit_root, nonce, block_number, block_hash, self._DEFAULT_SIGNATURE, staking_module_id, app)],
)
tx = self._data_bus.functions.sendMessage(deposit_topic, mes)
return tx.transact()

def send_pause_v2(self, pause_mes: PauseMessage):
pause_topic = self._w3.keccak(text=OnchainTransportSinks.PAUSE_V2)
deposit_root, nonce, block_number, block_hash, staking_module_id, app = (
pause_mes['depositRoot'],
pause_mes['nonce'],
pause_mes['blockNumber'],
pause_mes['blockHash'],
pause_mes['stakingModuleId'],
pause_mes['app']['version'],
)
mes = self._w3.codec.encode(
types=[PAUSE_V2_DATA_SCHEMA],
args=[deposit_root, nonce, block_number, block_hash, self._DEFAULT_SIGNATURE, staking_module_id, app],
)
tx = self._data_bus.functions.sendMessage(pause_topic, mes)
return self._w3.transaction.send(tx, False, 6)

def send_pause_v3(self, pause_mes: PauseMessage):
pause_topic = self._w3.keccak(text=OnchainTransportSinks.PAUSE_V3)
block_number, version = pause_mes['blockNumber'], pause_mes['app']['version']
mes = self._w3.codec.encode(types=[PAUSE_V3_DATA_SCHEMA], args=[block_number, self._DEFAULT_SIGNATURE, version])
tx = self._data_bus.functions.sendMessage(pause_topic, mes)
return self._w3.transaction.send(tx, False, 6)

def send_unvet(self, unvet_mes: UnvetMessage):
unvet_topic = self._w3.keccak(text=OnchainTransportSinks.UNVET_V1)
block_number, block_hash, staking_module_id, nonce, operator_ids, vetted_keys, version = (
unvet_mes['blockNumber'],
unvet_mes['blockHash'],
unvet_mes['stakingModuleId'],
unvet_mes['nonce'],
unvet_mes['operatorIds'],
unvet_mes['vettedKeysByOperator'],
unvet_mes['app']['version'],
)
mes = self._w3.codec.encode(
types=[UNVET_V1_DATA_SCHEMA],
args=[block_number, block_hash, self._DEFAULT_SIGNATURE, staking_module_id, nonce, operator_ids, vetted_keys, (version,)],
)
tx = self._data_bus.functions.sendMessage(unvet_topic, mes)
return self._w3.transaction.send(tx, False, 6)

def send_ping(self, ping_mes: PingMessage):
ping_topic = self._w3.keccak(text=OnchainTransportSinks.PING_V1)
block_number, version = ping_mes['blockNumber'], ping_mes['app']['version']
mes = self._w3.codec.encode(types=[PING_V1_DATA_SCHEMA], args=[block_number, (version,)])
tx = self._data_bus.functions.sendMessage(ping_topic, mes)
return self._w3.transaction.send(tx, False, 6)
8 changes: 4 additions & 4 deletions src/transport/msg_providers/onchain_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from transport.msg_providers.rabbit import MessageType
from transport.msg_types.deposit import DepositMessage
from transport.msg_types.pause import PauseMessage
from transport.msg_types.ping import PingMessageDataBus
from transport.msg_types.ping import PingMessage
from transport.msg_types.unvet import UnvetMessage
from utils.bytes import bytes_to_hex_string
from web3 import Web3
Expand Down Expand Up @@ -46,8 +46,8 @@


def signature_to_r_vs(signature: bytes) -> tuple[VRS, VRS]:
r, s, v = signature[:32], signature[32:64], signature[64:]
_vs = compute_vs(v, HexStr(s))
r, s, v = signature[:32], signature[32:64], int.from_bytes(signature[64:])
_vs = compute_vs(v, HexStr(bytes_to_hex_string(s)))
return HexStr(bytes_to_hex_string(r)), HexStr(_vs)


Expand Down Expand Up @@ -132,7 +132,7 @@ def __init__(self, w3: Web3):

def _create_message(self, parsed_data: tuple, guardian: str) -> dict:
block_number, app = parsed_data
return PingMessageDataBus(
return PingMessage(
type=MessageType.PING,
blockNumber=block_number,
guardianAddress=guardian,
Expand Down
3 changes: 3 additions & 0 deletions src/transport/msg_types/pause.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@

class PauseMessage(TypedDict):
type: str
depositRoot: str
nonce: int
blockNumber: int
guardianAddress: str
signature: Signature
stakingModuleId: int
app: dict
3 changes: 2 additions & 1 deletion src/transport/msg_types/ping.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
)


class PingMessageDataBus(TypedDict):
class PingMessage(TypedDict):
type: str
blockNumber: int
guardianAddress: str
app: dict


def to_check_sum_address(msg: dict):
Expand Down
1 change: 1 addition & 0 deletions src/transport/msg_types/unvet.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ class UnvetMessage(TypedDict):
nonce: int
operatorIds: str
vettedKeysByOperator: str
app: dict
7 changes: 5 additions & 2 deletions src/utils/bytes.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from eth_typing import HexStr


def from_hex_string_to_bytes(hex_string: str) -> bytes:
if hex_string.startswith('0x'):
return bytes.fromhex(hex_string[2:])
return bytes.fromhex(hex_string)


def bytes_to_hex_string(b: bytes) -> str:
return '0x' + b.hex()
def bytes_to_hex_string(b: bytes) -> HexStr:
return HexStr('0x' + b.hex())
2 changes: 2 additions & 0 deletions tests/fixtures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
web3_lido_integration,
web3_lido_unit,
web3_provider_integration,
web3_transaction_integration,
)
from .strategy import (
base_deposit_strategy,
Expand All @@ -39,6 +40,7 @@
'web3_lido_unit',
'web3_provider_integration',
'web3_lido_integration',
'web3_transaction_integration',
'weth',
'simple_dvt_staking_strategy',
'staking_module',
Expand Down
10 changes: 10 additions & 0 deletions tests/fixtures/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,13 @@ def web3_lido_integration(web3_provider_integration: Web3) -> Web3:
}
)
yield web3_provider_integration


@pytest.fixture
def web3_transaction_integration(web3_provider_integration: Web3) -> Web3:
web3_provider_integration.attach_modules(
{
'transaction': TransactionUtils,
}
)
yield web3_provider_integration
40 changes: 32 additions & 8 deletions tests/transport/test_data_bus.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,72 @@
from typing import cast
from unittest.mock import Mock

import pytest
import variables
from blockchain.contracts.data_bus import DataBusContract
from eth_typing import ChecksumAddress, HexAddress, HexStr
from schema import Or, Schema
from transport.msg_providers.onchain_sender import OnchainTransportSender
from transport.msg_providers.onchain_transport import (
DEPOSIT_V1_DATA_SCHEMA,
PING_V1_DATA_SCHEMA,
OnchainTransportProvider,
OnchainTransportSinks,
)
from transport.msg_types.deposit import DepositMessageSchema
from transport.msg_types.deposit import DepositMessage, DepositMessageSchema
from transport.msg_types.ping import PingMessageSchema
from web3 import Web3
from web3.types import EventData
from web3_multi_provider import FallbackProvider

_DEFAULT_GUARDIAN = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'


# Started with config: {
# NODE_HOST: 'http://127.0.0.1:8888',
# DATA_BUS_ADDRESS: '0x5FbDB2315678afecb367f032d93F642f64180aa3'
# }
@pytest.mark.integration_chiado
def test_data_bus_provider():
def test_data_bus_provider(web3_transaction_integration):
"""
Utilise this function for an adhoc testing of data bus transport
"""
variables.ONCHAIN_TRANSPORT_RPC_ENDPOINTS = ['https://gnosis-chiado-rpc.publicnode.com']
variables.ONCHAIN_TRANSPORT_ADDRESS = ChecksumAddress(HexAddress(HexStr('0x42E1DEfC18388E3AA1fCADa851499A11405cf37f')))
data_bus_contract = cast(
DataBusContract,
web3_transaction_integration.eth.contract(
address=variables.ONCHAIN_TRANSPORT_ADDRESS,
ContractFactoryClass=DataBusContract,
),
)

onchain_sender = OnchainTransportSender(w3=web3_transaction_integration, data_bus_contract=data_bus_contract)
onchain_sender.send_deposit(
deposit_mes=DepositMessage(
type='deposit',
depositRoot='0x0000000000000000000000000000000000000000000000000000000000000000',
nonce=40,
blockNumber=2,
blockHash='0x42eef33d13c4440627c3fab6e3abee85af796ae6f77dcade628b183640b519d0',
guardianAddress=_DEFAULT_GUARDIAN,
stakingModuleId=1,
app={'version': (1).to_bytes(32)},
)
)
web3_transaction_integration.provider.make_request('anvil_mine', [10])
provider = OnchainTransportProvider(
w3=Web3(FallbackProvider(variables.ONCHAIN_TRANSPORT_RPC_ENDPOINTS)),
w3=web3_transaction_integration,
onchain_address=variables.ONCHAIN_TRANSPORT_ADDRESS,
message_schema=Schema(Or(DepositMessageSchema, PingMessageSchema)),
sinks=[OnchainTransportSinks.DEPOSIT_V1, OnchainTransportSinks.PING_V1],
)
messages = provider.get_messages()
# todo: doesn't work on chiado now, because of the limit in 50k blocks
# assert messages
assert messages
for mes in messages:
print(mes)


_DEFAULT_GUARDIAN = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'


@pytest.mark.unit
def test_data_bus_mock_responses(web3_lido_unit):
receipts = mock_receipts(web3_lido_unit)
Expand Down

0 comments on commit 54ba420

Please sign in to comment.