Skip to content

Commit

Permalink
refactor: kakarot file architecture (#343)
Browse files Browse the repository at this point in the history
  • Loading branch information
matthieuauger committed Dec 7, 2022
1 parent 2ff5841 commit 16f0a41
Show file tree
Hide file tree
Showing 80 changed files with 407 additions and 412 deletions.
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.PHONY: build test coverage
solidity_folder = $(shell pwd)/tests/solidity_files
solidity_folder = $(shell pwd)/tests/integration/solidity_files
solidity_files = $(shell ls ${solidity_folder} | grep .sol)

build:
Expand All @@ -26,10 +26,10 @@ test-no-log: build-sol
poetry run pytest tests -n logical

test-integration: build-sol
poetry run pytest tests/integrations --log-cli-level=INFO -n logical
poetry run pytest tests/integration --log-cli-level=INFO -n logical

test-units: build-sol
poetry run pytest tests/units --log-cli-level=INFO
test-unit: build-sol
poetry run pytest tests/unit --log-cli-level=INFO

run-test-log: build-sol
poetry run pytest -k $(test) --log-cli-level=INFO -vvv
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<p align="center">
<img src="resources/img/kakarot_github_banner.png" height="200">
<img src="docs/img/kakarot_github_banner.png" height="200">
</p>
<div align="center">
<h3 align="center">
Expand Down Expand Up @@ -31,7 +31,7 @@ production.
[Report a bug](https://github.com/sayajin-labs/kakarot/issues/new?assignees=&labels=bug&template=01_BUG_REPORT.md&title=bug%3A+)[Questions](https://www.newton.so/view?tags=kakarot)
</div>

![](resources/img/kakarot.gif)
![](docs/img/kakarot.gif)

## Supported opcodes

Expand All @@ -55,7 +55,7 @@ list.

### Architecture

![](resources/img/architecture.png)
![](docs/img/architecture.png)

- ✅ Kakarot is a smart contract, deployed on Starknet (goerli). It is written
in Cairo.
Expand Down Expand Up @@ -141,7 +141,7 @@ Which corresponds to the following EVM program:

Here is the execution trace of the program on Kakarot:

![Tutorial](resources/img/sample_execution.png)
![Tutorial](docs/img/sample_execution.png)

## Installation

Expand Down Expand Up @@ -291,5 +291,5 @@ for being involved!
<!-- ALL-CONTRIBUTORS-LIST:END -->

<p align="center">
<img src="resources/img/kakarot_github_banner_footer.png" height="200">
<img src="docs/img/kakarot_github_banner_footer.png" height="200">
</p>
2 changes: 1 addition & 1 deletion docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Please try to create bug reports that are:
[Pull Requests](https://github.com/sayajin-labs/kakarot/pulls) that relate to
your submission. You don't want to duplicate effort.
2. Fork the project
3. **Enable workflows** so CI can add an auto-commit during format checks ![enable-workflow](/resources/img/github_workflows.png)
3. **Enable workflows** so CI can add an auto-commit during format checks ![enable-workflow](/docs/img/github_workflows.png)
4. Create your feature branch (`git checkout -b feat/amazing_feature`)
5. Commit your changes (`git commit -m 'feat: add amazing_feature'`)
6. Push to the branch (`git push origin feat/amazing_feature`)
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
1 change: 0 additions & 1 deletion resources/img/hackathon/counter_contract_bytecode.txt

This file was deleted.

42 changes: 0 additions & 42 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,42 +0,0 @@
from pathlib import Path

import yaml


class Object:
pass


def update(ref: dict, new: dict) -> dict:
"""Update ref recursively with new."""
for key, value in new.items():
if isinstance(value, dict):
ref[key] = update(ref.get(key, {}), value)
else:
ref[key] = value
return ref


def objectify(parent: object, attributes: dict) -> object:
"""Set attributes recursively to parent object."""
for key, value in attributes.items():
if isinstance(value, dict):
value = objectify(Object(), value)
setattr(parent, key, value)
return parent


def load(path: str, context: object):
"""Read config files and setup context."""
# load config
path = Path(path)
config = {}
for parent in reversed(path.parents):
config_path = parent / path.name
if not config_path.exists():
continue
with open(config_path, "r") as file_instance:
update(config, yaml.safe_load(file_instance))

# set up context
context = objectify(context, config)
137 changes: 5 additions & 132 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
import asyncio
import logging
import os
import shutil
from pathlib import Path
from typing import AsyncGenerator

import pandas as pd
import pytest
import pytest_asyncio
from cairo_coverage import cairo_coverage
from starkware.starknet.business_logic.execution.execute_entry_point import (
ExecuteEntryPoint,
)
from starkware.starknet.business_logic.state.state_api_objects import BlockInfo
from starkware.starknet.testing.contract import DeclaredClass, StarknetContract
from starkware.starknet.testing.starknet import Starknet

from tests.utils.utils import dump_coverage, dump_reports, timeit, traceit

pd.set_option("display.max_rows", 500)
pd.set_option("display.max_columns", 500)
pd.set_option("display.width", 1000)
logging.getLogger("asyncio").setLevel(logging.ERROR)
logger = logging.getLogger()

Expand All @@ -41,117 +23,8 @@ def event_loop():
loop.close()


@pytest_asyncio.fixture(scope="session")
async def starknet(worker_id, request) -> AsyncGenerator[Starknet, None]:
starknet = await Starknet.empty()
starknet.state.state.update_block_info(
BlockInfo.create_for_testing(block_number=1, block_timestamp=1)
)

starknet.deploy = traceit.trace_all(timeit(starknet.deploy))
starknet.declare = timeit(starknet.declare)
if request.config.getoption("trace_run"):
logger.info("trace-run option enabled")
ExecuteEntryPoint._run = traceit.trace_run(ExecuteEntryPoint._run)
else:
logger.info("trace-run option disabled")
output_dir = Path("coverage")
shutil.rmtree(output_dir, ignore_errors=True)

yield starknet

output_dir.mkdir(exist_ok=True, parents=True)
files = cairo_coverage.report_runs(
excluded_file={"site-packages", "cairo_files", "ERC20.cairo"}
)
total_covered = []
for file in files:
if file.pct_covered < 80:
logger.warning(f"{file.name} only {file.pct_covered:.2f}% covered")
total_covered.append(file.pct_covered)
if files and (val := not sum(total_covered) / len(files)) >= 80:
logger.warning(f"Project is not covered enough {val:.2f})")

if worker_id == "master":
dump_reports(output_dir)
dump_coverage(output_dir, files)
else:
dump_reports(output_dir / worker_id)
dump_coverage(output_dir / worker_id, files)
if len(os.listdir(output_dir)) == int(os.environ["PYTEST_XDIST_WORKER_COUNT"]):
# This is the last teardown of the testsuite, merge the files
resources = pd.concat(
[pd.read_csv(f) for f in output_dir.glob("**/resources.csv")],
)
if not resources.empty:
resources.sort_values(["n_steps"], ascending=False).to_csv(
output_dir / "resources.csv", index=False
)
times = pd.concat(
[pd.read_csv(f) for f in output_dir.glob("**/times.csv")],
ignore_index=True,
)
if not times.empty:
times.sort_values(["duration"], ascending=False).to_csv(
output_dir / "times.csv", index=False
)


@pytest_asyncio.fixture(scope="session")
async def eth(starknet: Starknet):
return await starknet.deploy(
source="./tests/utils/ERC20.cairo",
constructor_calldata=[2] * 6,
# Uint256(2, 2) tokens to 2
)


@pytest_asyncio.fixture(scope="session")
async def account_registry(starknet: Starknet):
return await starknet.deploy(
source="./src/kakarot/accounts/registry/account_registry.cairo",
cairo_path=["src"],
disable_hint_validation=True,
constructor_calldata=[1],
)


@pytest_asyncio.fixture(scope="session")
async def contract_account_class(starknet: Starknet):
return await starknet.declare(
source="./src/kakarot/accounts/contract/contract_account.cairo",
cairo_path=["src"],
disable_hint_validation=True,
)


@pytest_asyncio.fixture(scope="package")
async def kakarot(
starknet: Starknet, eth: StarknetContract, contract_account_class: DeclaredClass
) -> StarknetContract:
return await starknet.deploy(
source="./src/kakarot/kakarot.cairo",
cairo_path=["src"],
disable_hint_validation=True,
constructor_calldata=[
1,
eth.contract_address,
contract_account_class.class_hash,
],
)


@pytest_asyncio.fixture(scope="package", autouse=True)
async def set_account_registry(
kakarot: StarknetContract, account_registry: StarknetContract
):
await account_registry.transfer_ownership(kakarot.contract_address).execute(
caller_address=1
)
await kakarot.set_account_registry(
registry_address_=account_registry.contract_address
).execute(caller_address=1)
yield
await account_registry.transfer_ownership(1).execute(
caller_address=kakarot.contract_address
)
pytest_plugins = [
"tests.fixtures.1_starknet",
"tests.fixtures.2_kakarot",
"tests.fixtures.3_account_registry",
]
77 changes: 77 additions & 0 deletions tests/fixtures/1_starknet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import logging
import os
import shutil
from pathlib import Path
from typing import AsyncGenerator

import pandas as pd
import pytest_asyncio
from cairo_coverage import cairo_coverage
from starkware.starknet.business_logic.execution.execute_entry_point import (
ExecuteEntryPoint,
)
from starkware.starknet.business_logic.state.state_api_objects import BlockInfo
from starkware.starknet.testing.starknet import Starknet

from tests.utils.reporting import dump_coverage, dump_reports, timeit, traceit

pd.set_option("display.max_rows", 500)
pd.set_option("display.max_columns", 500)
pd.set_option("display.width", 1000)

logging.getLogger("asyncio").setLevel(logging.ERROR)
logger = logging.getLogger()


@pytest_asyncio.fixture(scope="session")
async def starknet(worker_id, request) -> AsyncGenerator[Starknet, None]:
starknet = await Starknet.empty()
starknet.state.state.update_block_info(
BlockInfo.create_for_testing(block_number=1, block_timestamp=1)
)

starknet.deploy = traceit.trace_all(timeit(starknet.deploy))
starknet.declare = timeit(starknet.declare)
if request.config.getoption("trace_run"):
logger.info("trace-run option enabled")
ExecuteEntryPoint._run = traceit.trace_run(ExecuteEntryPoint._run)
else:
logger.info("trace-run option disabled")
output_dir = Path("coverage")
shutil.rmtree(output_dir, ignore_errors=True)

yield starknet

output_dir.mkdir(exist_ok=True, parents=True)
files = cairo_coverage.report_runs(excluded_file={"site-packages", "tests"})
total_covered = []
for file in files:
if file.pct_covered < 80:
logger.warning(f"{file.name} only {file.pct_covered:.2f}% covered")
total_covered.append(file.pct_covered)
if files and (val := not sum(total_covered) / len(files)) >= 80:
logger.warning(f"Project is not covered enough {val:.2f})")

if worker_id == "master":
dump_reports(output_dir)
dump_coverage(output_dir, files)
else:
dump_reports(output_dir / worker_id)
dump_coverage(output_dir / worker_id, files)
if len(os.listdir(output_dir)) == int(os.environ["PYTEST_XDIST_WORKER_COUNT"]):
# This is the last teardown of the testsuite, merge the files
resources = pd.concat(
[pd.read_csv(f) for f in output_dir.glob("**/resources.csv")],
)
if not resources.empty:
resources.sort_values(["n_steps"], ascending=False).to_csv(
output_dir / "resources.csv", index=False
)
times = pd.concat(
[pd.read_csv(f) for f in output_dir.glob("**/times.csv")],
ignore_index=True,
)
if not times.empty:
times.sort_values(["duration"], ascending=False).to_csv(
output_dir / "times.csv", index=False
)
37 changes: 37 additions & 0 deletions tests/fixtures/2_kakarot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import pytest_asyncio
from starkware.starknet.testing.contract import DeclaredClass, StarknetContract
from starkware.starknet.testing.starknet import Starknet


@pytest_asyncio.fixture(scope="session")
async def eth(starknet: Starknet):
return await starknet.deploy(
source="./tests/fixtures/ERC20.cairo",
constructor_calldata=[2] * 6,
# Uint256(2, 2) tokens to 2
)


@pytest_asyncio.fixture(scope="session")
async def contract_account_class(starknet: Starknet):
return await starknet.declare(
source="./src/kakarot/accounts/contract/contract_account.cairo",
cairo_path=["src"],
disable_hint_validation=True,
)


@pytest_asyncio.fixture(scope="package")
async def kakarot(
starknet: Starknet, eth: StarknetContract, contract_account_class: DeclaredClass
) -> StarknetContract:
return await starknet.deploy(
source="./src/kakarot/kakarot.cairo",
cairo_path=["src"],
disable_hint_validation=True,
constructor_calldata=[
1,
eth.contract_address,
contract_account_class.class_hash,
],
)
Loading

0 comments on commit 16f0a41

Please sign in to comment.