Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated end-to-end tests to use Madara #1576

Open
wants to merge 1 commit into
base: testnet-fix-chain-id
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ INFURA_KEY=

# Account used by default in all kakarot_scripts
# Prefixed accounts {NETWORK}_ will take precedeance over the default one
MADARA_ACCOUNT_ADDRESS=0x3
MADARA_PRIVATE_KEY=0x00c1cf1490de1352865301bb8705143f3ef938f97fdf892f1090dcb5ac7bcd1d

MADARA_ACCOUNT_ADDRESS=0x055be462e718c4166d656d11f89e341115b8bc82389c3762a10eade04fcb225d
MADARA_PRIVATE_KEY=0x077e56c6dc32d40a67f6f7e6625c8dc5e570abe49c0a24e9202e4ae906abcc07

SHARINGAN_ACCOUNT_ADDRESS=
SHARINGAN_PRIVATE_KEY=
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ jobs:
tests-end-to-end:
runs-on: ubuntu-latest
env:
STARKNET_NETWORK: katana
STARKNET_NETWORK: madara
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION: python
needs: paths-filter
if:
Expand All @@ -119,11 +119,11 @@ jobs:
needs.paths-filter.outputs.rust == 'true'
steps:
- uses: actions/checkout@v4
- name: Extract Katana Version
id: extract_katana_version
- name: Extract Madara Version
id: extract_madara_version
run: |
KATANA_VERSION=$(grep -oP '^KATANA_VERSION = \K.*' Makefile)
echo "katana_version=$KATANA_VERSION" >> "$GITHUB_OUTPUT"
MADARA_VERSION=$(grep -oP '^MADARA_VERSION = \K.*' Makefile)
echo "madara_version=$MADARA_VERSION" >> "$GITHUB_OUTPUT"
- uses: astral-sh/setup-uv@v2
with:
enable-cache: true
Expand All @@ -142,13 +142,13 @@ jobs:
with:
path: ~/.cargo/bin
key: katana-${{ steps.extract_katana_version.outputs.katana_version }}
- name: Install Katana
- name: Install Madara
if: steps.cached-katana.outputs.cache-hit != 'true'
run: make install-katana
run: make install-madara
- name: Run tests
run: |
cp .env.example .env
make run-nodes & make test-end-to-end
make test-end-to-end

forge-test:
runs-on: ubuntu-latest
Expand Down
13 changes: 13 additions & 0 deletions .madara/deploy_core_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from kakarot_scripts.utils.l1 import (
deploy_on_l1,
get_l1_addresses,
dump_l1_addresses
)

contract = deploy_on_l1(
"starknet",
"StarknetMessagingLocal",
)
l1_addresses = get_l1_addresses()
l1_addresses.update({"StarknetMessagingLocal": {"address": contract.address}})
dump_l1_addresses(l1_addresses)
24 changes: 12 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ endif
KKRT_SSJ_RELEASE_ID = 176384150
# Kakarot SSJ artifacts for precompiles.
KKRT_SSJ_BUILD_ARTIFACT_URL = $(shell curl -L https://api.github.com/repos/kkrt-labs/kakarot-ssj/releases/${KKRT_SSJ_RELEASE_ID} | jq -r '.assets[0].browser_download_url')
KATANA_VERSION = v1.0.0-alpha.14
MADARA_VERSION = d188aa91
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))

BUILD_DIR = build
Expand Down Expand Up @@ -45,7 +45,7 @@ test: deploy
test-unit: build-sol
uv run pytest tests/src -m "not NoCI" -n logical --seed 42

test-end-to-end: deploy
test-end-to-end: madara-test-deploy
uv run pytest tests/end_to_end --seed 42

format:
Expand All @@ -67,16 +67,16 @@ build-sol:
git submodule update --init --recursive
forge build --names --force

install-katana:
cargo install --git https://github.com/dojoengine/dojo --locked --tag "${KATANA_VERSION}" katana
install-madara:
cargo install --git https://github.com/madara-alliance/madara.git --locked --rev "${MADARA_VERSION}"

run-katana:
katana --chain-id test --validate-max-steps 6000000 --invoke-max-steps 14000000 --eth-gas-price 0 --strk-gas-price 0 --disable-fee --seed 0

run-anvil:
anvil --block-base-fee-per-gas 1
madara-test-deploy: run-nodes deploy
@echo "Deploying Starknet Core contract and restarting Madara..."
uv run python .madara/deploy_core_contract.py
pkill madara
sleep 1
madara --devnet --l1-endpoint=http://localhost:8545 --chain-config-override eth_core_contract_address=0x5FbDB2315678afecb367f032d93F642f64180aa3 &

run-nodes:
@echo "Starting Anvil and Katana in messaging mode"
@anvil --block-base-fee-per-gas 1 &
@katana --chain-id test --validate-max-steps 6000000 --invoke-max-steps 14000000 --eth-gas-price 0 --strk-gas-price 0 --disable-fee --messaging .katana/messaging_config.json --seed 0
anvil --block-base-fee-per-gas 1 &
madara --devnet &
4 changes: 2 additions & 2 deletions kakarot_scripts/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ class NetworkType(Enum):
"rpc_url": os.getenv("MADARA_RPC_URL", "http://127.0.0.1:9944"),
"l1_rpc_url": "http://127.0.0.1:8545",
"type": NetworkType.DEV,
"check_interval": 6,
"max_wait": 30,
"check_interval": 0.01,
"max_wait": 3,
},
"sharingan": {
"name": "sharingan",
Expand Down
4 changes: 2 additions & 2 deletions kakarot_scripts/utils/starknet.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,12 @@ async def get_starknet_account(
message = str(err)
if (
"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 40: Requested entry point was not found." in message
or "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)
or "{'error': 'Invalid message selector'}" in message
or ("Entry point" in message and "not found in contract" in message)
):
continue
else:
Expand Down
12 changes: 9 additions & 3 deletions solidity_contracts/src/starknet/IStarknetMessaging.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019-2022 StarkWare Industries Ltd.
Copyright 2019-2024 StarkWare Industries Ltd.

Licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License.
Expand All @@ -14,7 +14,7 @@
and limitations under the License.
*/
// SPDX-License-Identifier: Apache-2.0.
pragma solidity ^0.8.0;
pragma solidity ^0.8.24;

import "./IStarknetMessagingEvents.sol";

Expand All @@ -24,9 +24,15 @@ interface IStarknetMessaging is IStarknetMessagingEvents {
*/
function getMaxL1MsgFee() external pure returns (uint256);

/**
Returns `msg_fee + 1` if there is a pending message associated with the given 'msgHash',
otherwise, returns 0.
*/
function l1ToL2Messages(bytes32 msgHash) external view returns (uint256);

/**
Sends a message to an L2 contract.
This function is payable, the paid amount is the message fee.
This function is payable, the payed amount is the message fee.

Returns the hash of the message and the nonce of the message.
*/
Expand Down
4 changes: 2 additions & 2 deletions solidity_contracts/src/starknet/IStarknetMessagingEvents.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2019-2022 StarkWare Industries Ltd.
Copyright 2019-2024 StarkWare Industries Ltd.

Licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License.
Expand All @@ -14,7 +14,7 @@
and limitations under the License.
*/
// SPDX-License-Identifier: Apache-2.0.
pragma solidity ^0.8.0;
pragma solidity ^0.8.24;

interface IStarknetMessagingEvents {
// This event needs to be compatible with the one defined in Output.sol.
Expand Down
175 changes: 175 additions & 0 deletions solidity_contracts/src/starknet/Output.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
Copyright 2019-2024 StarkWare Industries Ltd.

Licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.starkware.co/open-source-license/

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions
and limitations under the License.
*/
// SPDX-License-Identifier: Apache-2.0.
pragma solidity ^0.8.0;

import "./IStarknetMessagingEvents.sol";

library CommitmentTreeUpdateOutput {
/**
Returns the previous commitment tree root.
*/
function getPrevRoot(uint256[] calldata commitmentTreeUpdateData)
internal
pure
returns (uint256)
{
return commitmentTreeUpdateData[0];
}

/**
Returns the new commitment tree root.
*/
function getNewRoot(uint256[] calldata commitmentTreeUpdateData)
internal
pure
returns (uint256)
{
return commitmentTreeUpdateData[1];
}
}

library StarknetOutput {
uint256 internal constant MERKLE_UPDATE_OFFSET = 0;
uint256 internal constant BLOCK_NUMBER_OFFSET = 2;
uint256 internal constant BLOCK_HASH_OFFSET = 3;
uint256 internal constant CONFIG_HASH_OFFSET = 4;
uint256 internal constant USE_KZG_DA_OFFSET = 5;
uint256 internal constant HEADER_SIZE = 6;
uint256 internal constant KZG_SEGMENT_SIZE = 5;

uint256 constant MESSAGE_TO_L1_FROM_ADDRESS_OFFSET = 0;
uint256 constant MESSAGE_TO_L1_TO_ADDRESS_OFFSET = 1;
uint256 constant MESSAGE_TO_L1_PAYLOAD_SIZE_OFFSET = 2;
uint256 constant MESSAGE_TO_L1_PREFIX_SIZE = 3;

uint256 constant MESSAGE_TO_L2_FROM_ADDRESS_OFFSET = 0;
uint256 constant MESSAGE_TO_L2_TO_ADDRESS_OFFSET = 1;
uint256 constant MESSAGE_TO_L2_NONCE_OFFSET = 2;
uint256 constant MESSAGE_TO_L2_SELECTOR_OFFSET = 3;
uint256 constant MESSAGE_TO_L2_PAYLOAD_SIZE_OFFSET = 4;
uint256 constant MESSAGE_TO_L2_PREFIX_SIZE = 5;

/**
Returns the offset of the messages segment in the output_data.
*/
function messageSegmentOffset(uint256 use_kzg_da) internal pure returns (uint256) {
return HEADER_SIZE + (use_kzg_da == 1 ? KZG_SEGMENT_SIZE : 0);
}

/**
Returns a slice of the 'output_data' with the commitment tree update information.
*/
function getMerkleUpdate(uint256[] calldata output_data)
internal
pure
returns (uint256[] calldata)
{
return output_data[MERKLE_UPDATE_OFFSET:MERKLE_UPDATE_OFFSET + 2];
}

/**
Processes a message segment from the program output.
The format of a message segment is the length of the messages in words followed
by the concatenation of all the messages.

The 'messages' mapping is updated according to the messages and the direction ('isL2ToL1').
*/
function processMessages(
bool isL2ToL1,
uint256[] calldata programOutputSlice,
mapping(bytes32 => uint256) storage messages
) internal returns (uint256) {
uint256 messageSegmentSize = programOutputSlice[0];
require(messageSegmentSize < 2**30, "INVALID_MESSAGE_SEGMENT_SIZE");

uint256 offset = 1;
uint256 messageSegmentEnd = offset + messageSegmentSize;

uint256 payloadSizeOffset = (
isL2ToL1 ? MESSAGE_TO_L1_PAYLOAD_SIZE_OFFSET : MESSAGE_TO_L2_PAYLOAD_SIZE_OFFSET
);

uint256 totalMsgFees = 0;
while (offset < messageSegmentEnd) {
uint256 payloadLengthOffset = offset + payloadSizeOffset;
require(payloadLengthOffset < programOutputSlice.length, "MESSAGE_TOO_SHORT");

uint256 payloadLength = programOutputSlice[payloadLengthOffset];
require(payloadLength < 2**30, "INVALID_PAYLOAD_LENGTH");

uint256 endOffset = payloadLengthOffset + 1 + payloadLength;
require(endOffset <= programOutputSlice.length, "TRUNCATED_MESSAGE_PAYLOAD");

if (isL2ToL1) {
bytes32 messageHash = keccak256(
abi.encodePacked(programOutputSlice[offset:endOffset])
);

emit IStarknetMessagingEvents.LogMessageToL1(
// from=
programOutputSlice[offset + MESSAGE_TO_L1_FROM_ADDRESS_OFFSET],
// to=
address(uint160(programOutputSlice[offset + MESSAGE_TO_L1_TO_ADDRESS_OFFSET])),
// payload=
(uint256[])(programOutputSlice[offset + MESSAGE_TO_L1_PREFIX_SIZE:endOffset])
);
messages[messageHash] += 1;
} else {
{
bytes32 messageHash = keccak256(
abi.encodePacked(programOutputSlice[offset:endOffset])
);

uint256 msgFeePlusOne = messages[messageHash];
require(msgFeePlusOne > 0, "INVALID_MESSAGE_TO_CONSUME");
totalMsgFees += msgFeePlusOne - 1;
messages[messageHash] = 0;
}

uint256 nonce = programOutputSlice[offset + MESSAGE_TO_L2_NONCE_OFFSET];
uint256[] memory messageSlice = (uint256[])(
programOutputSlice[offset + MESSAGE_TO_L2_PREFIX_SIZE:endOffset]
);
emit IStarknetMessagingEvents.ConsumedMessageToL2(
// from=
address(
uint160(programOutputSlice[offset + MESSAGE_TO_L2_FROM_ADDRESS_OFFSET])
),
// to=
programOutputSlice[offset + MESSAGE_TO_L2_TO_ADDRESS_OFFSET],
// selector=
programOutputSlice[offset + MESSAGE_TO_L2_SELECTOR_OFFSET],
// payload=
messageSlice,
// nonce =
nonce
);
}

offset = endOffset;
}
require(offset == messageSegmentEnd, "INVALID_MESSAGE_SEGMENT_SIZE");

if (totalMsgFees > 0) {
// NOLINTNEXTLINE: low-level-calls.
(bool success, ) = msg.sender.call{value: totalMsgFees}("");
require(success, "ETH_TRANSFER_FAILED");
}

return offset;
}
}
Loading
Loading