Skip to content

Commit

Permalink
feat: bump katana (#999)
Browse files Browse the repository at this point in the history
<!--- Please provide a general summary of your changes in the title
above -->

<!-- Give an estimate of the time you spent on this PR in terms of work
days.
Did you spend 0.5 days on this PR or rather 2 days?  -->

Time spent on this PR:

## Pull request type

<!-- Please try to limit your pull request to one type,
submit multiple pull requests if needed. -->

Please check the type of change your PR introduces:

- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no api changes)
- [x] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## What is the current behavior?

<!-- Please describe the current behavior that you are modifying,
or link to a relevant issue. -->

Resolves #998 

## What is the new behavior?

<!-- Please describe the behavior or changes that are being added by
this PR. -->

- remove wait_for_transaction fixture and function, use
client.wait_for_tx instead
- bump starknet py and katana
- don't bump tx type to v3 because it just doesn't work (signature
invalid error without any change to the payload)

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg"
height="34" align="absmiddle"
alt="Reviewable"/>](https://reviewable.io/reviews/kkrt-labs/kakarot/999)
<!-- Reviewable:end -->
  • Loading branch information
Eikix authored Feb 28, 2024
1 parent b5f385e commit 80d99d0
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 464 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ jobs:
uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: katana-fe8f233
key: katana-v0.6.0-alpha.2
- name: Install Katana
if: steps.cached-katana.outputs.cache-hit != 'true'
run: make install-katana
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ build-sol:
forge build --names --force

install-katana:
cargo install --git https://github.com/dojoengine/dojo --locked --rev fe8f233 katana
cargo install --git https://github.com/dojoengine/dojo --locked --tag v0.6.0-alpha.2 katana

run-katana:
katana --validate-max-steps 16777216 --invoke-max-steps 16777216 --gas-price 0 --disable-fee
katana --validate-max-steps 16777216 --invoke-max-steps 16777216 --eth-gas-price 0 --strk-gas-price 0 --disable-fee
254 changes: 144 additions & 110 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ packages = [{ include = "scripts" }, { include = "tests" }]
python = ">=3.9,<3.10"
cairo-lang = "0.13.0"
amarna = "^0.1.5"
starknet-py = "^0.18.3"
starknet-py = "^0.20.0"
py-evm = "^0.7.0a1"
openzeppelin-cairo-contracts = "^0.6.1"
ethereum = { git = "https://github.com/ethereum/execution-specs.git" }
Expand Down
2 changes: 1 addition & 1 deletion scripts/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"explorer_url": "https://testnet.starkscan.co",
"rpc_url": f"https://starknet-goerli.infura.io/v3/{os.getenv('INFURA_KEY')}",
"devnet": False,
"chain_id": StarknetChainId.TESTNET,
"chain_id": StarknetChainId.GOERLI,
},
"starknet-devnet": {
"name": "starknet-devnet",
Expand Down
4 changes: 2 additions & 2 deletions scripts/utils/kakarot.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from starknet_py.net.account.account import Account
from starknet_py.net.client_errors import ClientError
from starknet_py.net.client_models import Call, Event
from starknet_py.net.models.transaction import Invoke
from starknet_py.net.models.transaction import InvokeV1
from starknet_py.net.signer.stark_curve_signer import KeyPair
from starkware.starknet.public.abi import starknet_keccak
from web3 import Web3
Expand Down Expand Up @@ -329,7 +329,7 @@ async def eth_send_transaction(
)
# We need to reconstruct the prepared_invoke with the new signature
# And Invoke.signature is Frozen
prepared_invoke = Invoke(
prepared_invoke = InvokeV1(
version=prepared_invoke.version,
max_fee=prepared_invoke.max_fee,
signature=[*int_to_uint256(evm_tx.r), *int_to_uint256(evm_tx.s), evm_tx.v],
Expand Down
101 changes: 28 additions & 73 deletions scripts/utils/starknet.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import logging
import random
import subprocess
import time
from copy import deepcopy
from datetime import datetime
from functools import cache
Expand All @@ -27,13 +26,9 @@
from starknet_py.hash.transaction import TransactionHashPrefix, compute_transaction_hash
from starknet_py.hash.utils import message_signature
from starknet_py.net.account.account import Account
from starknet_py.net.client_models import (
Call,
DeclareTransactionResponse,
TransactionStatus,
)
from starknet_py.net.client_models import Call, DeclareTransactionResponse
from starknet_py.net.full_node_client import _create_broadcasted_txn
from starknet_py.net.models.transaction import Declare
from starknet_py.net.models.transaction import DeclareV1
from starknet_py.net.schemas.rpc import DeclareTransactionResponseSchema
from starknet_py.net.signer.stark_curve_signer import KeyPair
from starkware.starknet.public.abi import get_selector_from_name
Expand Down Expand Up @@ -100,13 +95,14 @@ async def get_starknet_account(
)[0]
break
except Exception as err:
message = str(err)
if (
err.message == "Client failed with code 40: Contract error."
or err.message
== "Client failed with code 40: Requested entry point was not found."
or err.message
== "Client failed with code 21: Invalid message selector."
or "StarknetErrorCode.ENTRY_POINT_NOT_FOUND_IN_CONTRACT" in err.message
"Client failed with code 40: Contract error." in message
or "Client failed with code 40: Requested entry point was not found."
in message
or "Client failed with code 21: Invalid message selector." in message
or "StarknetErrorCode.ENTRY_POINT_NOT_FOUND_IN_CONTRACT" in message
or ("code 40" in message and "not found in contract" in message)
):
continue
else:
Expand Down Expand Up @@ -177,7 +173,7 @@ async def fund_address(
raise ValueError(
f"Cannot send {amount / 1e18} ETH from default account with current balance {balance / 1e18} ETH"
)
prepared = eth_contract.functions["transfer"].prepare(
prepared = eth_contract.functions["transfer"].prepare_invoke_v1(
address, int_to_uint256(amount)
)
tx = await prepared.invoke(max_fee=_max_fee)
Expand Down Expand Up @@ -343,7 +339,7 @@ async def deploy_starknet_account(class_hash=None, private_key=None, amount=1):
logger.info(f"ℹ️ Funding account {hex(address)} with {amount} ETH")
await fund_address(address, amount=amount)
logger.info("ℹ️ Deploying account")
res = await Account.deploy_account(
res = await Account.deploy_account_v1(
address=address,
class_hash=class_hash,
salt=salt,
Expand Down Expand Up @@ -388,7 +384,7 @@ async def declare(contract):
except Exception:
pass

declare_v2_transaction = await account.sign_declare_v2_transaction(
declare_v2_transaction = await account.sign_declare_v2(
compiled_contract=sierra_compiled_contract,
compiled_class_hash=class_hash,
max_fee=_max_fee,
Expand Down Expand Up @@ -420,7 +416,7 @@ async def declare(contract):
signature = message_signature(
msg_hash=tx_hash, priv_key=account.signer.private_key
)
transaction = Declare(
transaction = DeclareV1(
contract_class=contract_class,
sender_address=account.address,
max_fee=_max_fee,
Expand All @@ -441,6 +437,7 @@ async def declare(contract):
deployed_class_hash = resp.class_hash

status = await wait_for_transaction(resp.transaction_hash)

logger.info(
f"{status} {contract['contract_name']} class hash: {hex(resp.class_hash)}"
)
Expand All @@ -461,7 +458,7 @@ async def deploy(contract_name, *args):
abi = json.loads(sierra_compiled_contract)["abi"]

account = await get_starknet_account()
deploy_result = await Contract.deploy_contract(
deploy_result = await Contract.deploy_contract_v1(
account=account,
class_hash=declarations[contract_name],
abi=abi,
Expand All @@ -486,7 +483,7 @@ async def invoke_address(contract_address, function_name, *calldata, account=Non
f"ℹ️ Invoking {function_name}({json.dumps(calldata) if calldata else ''}) "
f"at address {hex(contract_address)[:10]}"
)
return await account.execute(
return await account.execute_v1(
Call(
to_addr=contract_address,
selector=get_selector_from_name(function_name),
Expand All @@ -501,11 +498,11 @@ async def invoke_contract(
):
account = account or (await get_starknet_account())
contract = get_contract(contract_name, address=address, provider=account)
call = contract.functions[function_name].prepare(*inputs, max_fee=_max_fee)
call = contract.functions[function_name].prepare_invoke_v1(*inputs)
logger.info(
f"ℹ️ Invoking {contract_name}.{function_name}({json.dumps(inputs) if inputs else ''})"
)
return await account.execute(call, max_fee=_max_fee)
return await account.execute_v1(call, max_fee=_max_fee)


async def invoke(contract: Union[str, int], *args, **kwargs):
Expand Down Expand Up @@ -561,56 +558,14 @@ async def call(contract: Union[str, int], *args, **kwargs):


@functools.wraps(RPC_CLIENT.wait_for_tx)
async def wait_for_transaction(*args, **kwargs):
"""
We need to write this custom hacky wait_for_transaction instead of using the one from starknet-py
because the RPCs don't know RECEIVED, PENDING and REJECTED states currently.
"""
start = datetime.now()
elapsed = 0
check_interval = kwargs.get("check_interval", NETWORK.get("check_interval", 5))
max_wait = kwargs.get("max_wait", NETWORK.get("max_wait", 20))
transaction_hash = args[0] if args else kwargs["tx_hash"]
finality_status = None
logger.info(f"⏳ Waiting for tx {get_tx_url(transaction_hash)}")
while (
finality_status
not in [TransactionStatus.ACCEPTED_ON_L2, TransactionStatus.REJECTED]
and elapsed < max_wait
):
if elapsed > 0:
# don't log at the first iteration
logger.info(f"ℹ️ Current status: {finality_status}")
logger.info(f"ℹ️ Sleeping for {check_interval}s")
time.sleep(check_interval)
response = requests.post(
RPC_CLIENT.url,
json={
"jsonrpc": "2.0",
"method": "starknet_getTransactionReceipt",
"params": {"transaction_hash": hex(transaction_hash)},
"id": 0,
},
)
payload = json.loads(response.text)
if payload.get("error"):
if payload["error"]["message"] != "Transaction hash not found":
logger.warn(
f"tx {transaction_hash:x} error: {json.dumps(payload['error'])}"
)
break
finality_status = payload.get("result", {}).get("finality_status")
execution_status = payload.get("result", {}).get("execution_status")
if finality_status is not None:
finality_status = TransactionStatus(finality_status)
if execution_status is not None:
execution_status = TransactionStatus(execution_status)
elapsed = (datetime.now() - start).total_seconds()
return (
"✅"
if (
finality_status == TransactionStatus.ACCEPTED_ON_L2
and execution_status == TransactionStatus.SUCCEEDED
async def wait_for_transaction(tx_hash):
try:
await RPC_CLIENT.wait_for_tx(
tx_hash,
check_interval=NETWORK["check_interval"],
retries=int(NETWORK["max_wait"] / NETWORK["check_interval"]),
)
else "❌"
)
return "✅"
except Exception as e:
logger.error(f"Error while waiting for transaction {tx_hash}: {e}")
return "❌"
14 changes: 4 additions & 10 deletions tests/end_to_end/PlainOpcodes/test_safe.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,11 @@ async def test_should_withdraw_transfer_eth(self, safe, owner, eth_balance_of):
safe_balance = await safe.balance()
owner_balance_before = await eth_balance_of(owner.address)

receipt = await safe.withdrawTransfer(caller_eoa=owner.starknet_contract)
await safe.withdrawTransfer(caller_eoa=owner.starknet_contract)

owner_balance_after = await eth_balance_of(owner.address)
assert await safe.balance() == 0
assert (
owner_balance_after - owner_balance_before
== safe_balance - receipt.actual_fee
)
assert owner_balance_after - owner_balance_before == safe_balance

class TestWithdrawCall:
async def test_should_withdraw_call_eth(self, safe, owner, eth_balance_of):
Expand All @@ -50,14 +47,11 @@ async def test_should_withdraw_call_eth(self, safe, owner, eth_balance_of):
safe_balance = await safe.balance()
owner_balance_before = await eth_balance_of(owner.address)

receipt = await safe.withdrawCall(caller_eoa=owner.starknet_contract)
await safe.withdrawCall(caller_eoa=owner.starknet_contract)

owner_balance_after = await eth_balance_of(owner.address)
assert await safe.balance() == 0
assert (
owner_balance_after - owner_balance_before
== safe_balance - receipt.actual_fee
)
assert owner_balance_after - owner_balance_before == safe_balance

class TestDeploySafeWithValue:
async def test_deploy_safe_with_value(
Expand Down
21 changes: 6 additions & 15 deletions tests/end_to_end/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from starknet_py.contract import Contract
from starknet_py.net.account.account import Account

from scripts.utils.starknet import wait_for_transaction
from tests.utils.helpers import generate_random_private_key

logging.basicConfig()
Expand Down Expand Up @@ -167,30 +168,20 @@ async def _factory(evm_address: Union[int, str]):


@pytest.fixture(scope="session")
def wait_for_transaction():
from scripts.utils.starknet import wait_for_transaction

async def _factory(*args, **kwargs):
return await wait_for_transaction(*args, **kwargs)

return _factory


@pytest.fixture(scope="session")
def deploy_externally_owned_account(
kakarot: Contract, max_fee: int, wait_for_transaction
):
def deploy_externally_owned_account(kakarot: Contract, max_fee: int):
"""
Isolate the starknet-py logic and make the test agnostic of the backend.
"""

async def _factory(evm_address: Union[int, str]):
if isinstance(evm_address, str):
evm_address = int(evm_address, 16)
tx = await kakarot.functions["deploy_externally_owned_account"].invoke(
tx = await kakarot.functions["deploy_externally_owned_account"].invoke_v1(
evm_address, max_fee=max_fee
)
await wait_for_transaction(tx.hash)
await wait_for_transaction(
tx.hash,
)
return tx

return _factory
Expand Down
18 changes: 12 additions & 6 deletions tests/end_to_end/test_kakarot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from starknet_py.contract import Contract
from starknet_py.net.full_node_client import FullNodeClient

from scripts.utils.starknet import wait_for_transaction
from tests.end_to_end.bytecodes import test_cases
from tests.utils.constants import PRE_FUND_AMOUNT
from tests.utils.helpers import (
Expand Down Expand Up @@ -79,7 +80,6 @@ async def test_execute(
self,
starknet: FullNodeClient,
eth: Contract,
wait_for_transaction,
params: dict,
request,
evm: Contract,
Expand Down Expand Up @@ -117,15 +117,17 @@ async def test_execute(
events = params.get("events")
if events:
# Events only show up in a transaction, thus we run the same call, but in a tx
tx = await evm.functions["evm_execute"].invoke(
tx = await evm.functions["evm_execute"].invoke_v1(
origin=origin,
value=int(params["value"]),
bytecode=hex_string_to_bytes_array(params["code"]),
calldata=hex_string_to_bytes_array(params["calldata"]),
max_fee=max_fee,
access_list=[],
)
status = await wait_for_transaction(tx.hash)
status = await wait_for_transaction(
tx.hash,
)
assert status == "✅"
receipt = await starknet.get_transaction_receipt(tx.hash)
assert [
Expand Down Expand Up @@ -172,7 +174,6 @@ async def test_eth_call_should_succeed(
deploy_externally_owned_account,
is_account_deployed,
compute_starknet_address,
wait_for_transaction,
kakarot,
):
seed = random.randint(0, 0x5EED)
Expand All @@ -185,7 +186,9 @@ async def test_eth_call_should_succeed(
amount = PRE_FUND_AMOUNT / 1e16
await fund_starknet_address(starknet_address, amount)
tx = await deploy_externally_owned_account(evm_address)
status = await wait_for_transaction(tx.hash)
status = await wait_for_transaction(
tx.hash,
)
assert status == "✅"

result = await kakarot.functions["eth_call"].call(
Expand Down Expand Up @@ -213,7 +216,10 @@ async def test_should_raise_when_caller_is_not_owner(
self, starknet, kakarot, invoke, other, class_hashes
):
prev_class_hash = await starknet.get_class_hash_at(kakarot.address)
await invoke("kakarot", "upgrade", class_hashes["EVM"], account=other)
try:
await invoke("kakarot", "upgrade", class_hashes["EVM"], account=other)
except Exception as e:
print(e)
new_class_hash = await starknet.get_class_hash_at(kakarot.address)
assert prev_class_hash == new_class_hash

Expand Down
Loading

0 comments on commit 80d99d0

Please sign in to comment.