Skip to content

Commit

Permalink
Adapt to starknet/cairo-lang 0.9.1 (0xSpaceShard#181)
Browse files Browse the repository at this point in the history
  • Loading branch information
FabijanC committed Jul 20, 2022
1 parent e43fef2 commit 5e7e5ff
Show file tree
Hide file tree
Showing 23 changed files with 234 additions and 106 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ If you don't specify the `HOST` part, the server will indeed be available on all
- `deploy`
- `estimate_fee`
- `get_block` (currently pending block is not supported)
- `get_block_traces`
- `get_class_by_hash`
- `get_class_hash_at`
- `get_code`
Expand Down Expand Up @@ -548,12 +549,20 @@ poetry run pytest test/<TEST_FILE> # for a single file
poetry run pytest test/<TEST_FILE>::<TEST_CASE> # for a single test case
```

### Development - Check Versioning consistency
### Development - Check versioning consistency

```
./scripts/check_versions.sh
```

### Development - working with a local version of cairo-lang:

In `pyproject.toml` under `[tool.poetry.dependencies]` specify

```
cairo-lang = { path = "your-cairo-lang-package.zip" }
```

### Development - Build

You don't need to build anything to be able to run locally, but if you need the `*.whl` or `*.tar.gz` artifacts, run
Expand Down
32 changes: 6 additions & 26 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ keywords = ["starknet", "cairo", "testnet", "local", "server"]
python = ">=3.7.2,<3.10"
Flask = {extras = ["async"], version = "~2.0.3"}
flask-cors = "~3.0.10"
cairo-lang = "0.9.0"
cairo-lang = "0.9.1"
meinheld = "~1.0.2"
Werkzeug = "~2.0.3"
cloudpickle = "~2.1.0"
Expand All @@ -41,14 +41,15 @@ markers = [
"call",
"declare",
"deploy",
"estimate_fee",
"fee_token",
"general_workflow",
"invoke",
"restart",
"state_update",
"timestamps",
"transaction_trace",
"general_workflow",
"tx_version",
"timestamps",
"web3_messaging"
]
junit_family="xunit1"
Expand Down
5 changes: 4 additions & 1 deletion starknet_devnet/block_info_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from starkware.starknet.business_logic.state.state import BlockInfo
from starkware.starknet.definitions.general_config import StarknetGeneralConfig

from starknet_devnet.constants import CAIRO_LANG_VERSION

def now() -> int:
"""Get the current time in seconds."""
return int(time.time())
Expand Down Expand Up @@ -34,7 +36,8 @@ def next_block(self, block_info: BlockInfo, general_config: StarknetGeneralConfi
gas_price=self.gas_price,
block_number=block_info.block_number,
block_timestamp=block_timestamp,
sequencer_address=general_config.sequencer_address
sequencer_address=general_config.sequencer_address,
starknet_version=CAIRO_LANG_VERSION
)

def increase_time(self, time_s: int):
Expand Down
5 changes: 4 additions & 1 deletion starknet_devnet/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from starkware.starknet.services.api.feeder_gateway.response_objects import StarknetBlock, BlockStatus
from starkware.starknet.services.api.feeder_gateway.response_objects import BlockStateUpdate

from starknet_devnet.constants import CAIRO_LANG_VERSION

from .origin import Origin
from .util import StarknetDevnetException
from .transactions import DevnetTransaction
Expand Down Expand Up @@ -132,7 +134,8 @@ async def generate(
status=BlockStatus.ACCEPTED_ON_L2,
gas_price=state.state.block_info.gas_price,
sequencer_address=state.general_config.sequencer_address,
parent_block_hash=parent_block_hash
parent_block_hash=parent_block_hash,
starknet_version=CAIRO_LANG_VERSION
)

self.__num2block[block_number] = block
Expand Down
57 changes: 43 additions & 14 deletions starknet_devnet/blueprints/feeder_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

from flask import request, jsonify, Blueprint, Response
from marshmallow import ValidationError
from starkware.starknet.services.api.feeder_gateway.response_objects import BlockTransactionTraces
from starkware.starknet.services.api.gateway.transaction import InvokeFunction
from werkzeug.datastructures import MultiDict

from starknet_devnet.state import state
from starknet_devnet.util import StarknetDevnetException, custom_int, fixed_length_hex
from .shared import validate_transaction

feeder_gateway = Blueprint("feeder_gateway", __name__, url_prefix="/feeder_gateway")

Expand All @@ -33,6 +33,18 @@ def _check_block_arguments(block_hash, block_number):
message = "Ambiguous criteria: only one of (block number, block hash) can be provided."
raise StarknetDevnetException(message=message, status_code=500)

def _get_block_object(block_hash: str, block_number: int):
"""Returns the block object"""

_check_block_arguments(block_hash, block_number)

if block_hash is not None:
block = state.starknet_wrapper.blocks.get_by_hash(block_hash)
else:
block = state.starknet_wrapper.blocks.get_by_number(block_number)

return block

@feeder_gateway.route("/is_alive", methods=["GET"])
def is_alive():
"""Health check endpoint."""
Expand All @@ -56,20 +68,40 @@ async def call_contract():
return jsonify(result_dict)

@feeder_gateway.route("/get_block", methods=["GET"])
async def get_block():
def get_block():
"""Endpoint for retrieving a block identified by its hash or number."""

block_hash = request.args.get("blockHash")
block_number = request.args.get("blockNumber", type=custom_int)

_check_block_arguments(block_hash, block_number)

if block_hash is not None:
block = state.starknet_wrapper.blocks.get_by_hash(block_hash)
else:
block = state.starknet_wrapper.blocks.get_by_number(block_number)
block = _get_block_object(block_hash=block_hash, block_number=block_number)

return Response(block.dumps(), status=200, mimetype="application/json")

@feeder_gateway.route("/get_block_traces", methods=["GET"])
def get_block_traces():
"""Returns the traces of the transactions in the specified block."""

block_hash = request.args.get("blockHash")
block_number = request.args.get("blockNumber", type=custom_int)

block = _get_block_object(block_hash=block_hash, block_number=block_number)

traces = []
for transaction in block.transaction_receipts:
tx_hash = hex(transaction.transaction_hash)
trace = state.starknet_wrapper.transactions.get_transaction_trace(tx_hash)

# expected trace is equal to response of get_transaction, but with the hash property
trace_dict = trace.dump()
trace_dict["transaction_hash"] = tx_hash
traces.append(trace_dict)

# assert correct structure
block_transaction_traces = BlockTransactionTraces.load({ "traces": traces })

return jsonify(block_transaction_traces.dump())

@feeder_gateway.route("/get_code", methods=["GET"])
def get_code():
"""
Expand Down Expand Up @@ -183,10 +215,7 @@ def get_state_update():
@feeder_gateway.route("/estimate_fee", methods=["POST"])
async def estimate_fee():
"""Returns the estimated fee for a transaction."""
transaction = validate_transaction(request.data, InvokeFunction)
actual_fee = await state.starknet_wrapper.calculate_actual_fee(transaction)
transaction = validate_call(request.data)
fee_response = await state.starknet_wrapper.calculate_actual_fee(transaction)

return jsonify({
"amount": actual_fee,
"unit": "wei"
})
return jsonify(fee_response)
2 changes: 1 addition & 1 deletion starknet_devnet/blueprints/rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ def contracts() -> List[RpcContractDiff]:
for contract in state_update.state_diff.deployed_contracts:
diff: RpcContractDiff = {
"address": rpc_felt(contract.address),
"contract_hash": rpc_root(contract.class_hash.hex())
"contract_hash": rpc_felt(contract.class_hash)
}
_contracts.append(diff)
return _contracts
Expand Down
2 changes: 1 addition & 1 deletion starknet_devnet/contract_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async def call(
Calls the function identified with `entry_point_selector`, potentially passing in `calldata` and `signature`.
"""

call_info = await self.contract.state.call_raw(
call_info, _ = await self.contract.state.call_raw(
calldata=calldata,
caller_address=caller_address,
contract_address=self.contract.contract_address,
Expand Down
12 changes: 11 additions & 1 deletion starknet_devnet/starknet_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,12 +378,22 @@ async def calculate_actual_fee(self, external_tx: InvokeFunction):
child_state = state.state.create_child_state_for_querying()
call_info = await internal_tx.execute(child_state, state.general_config, only_query=True)

return calculate_tx_fee(
tx_fee = calculate_tx_fee(
state=child_state,
call_info=call_info,
general_config=state.general_config
)

gas_price = state.state.block_info.gas_price
gas_usage = tx_fee // gas_price

return {
"overall_fee": tx_fee,
"unit": "wei",
"gas_price": gas_price,
"gas_usage": gas_usage,
}

def increase_block_time(self, time_s: int):
"""Increases the block time by `time_s`."""
self.block_info_generator.increase_time(time_s)
Expand Down
4 changes: 2 additions & 2 deletions starknet_devnet/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Classes for storing and handling transactions.
"""

from typing import List, Union
from typing import Dict, List, Union

from web3 import Web3

Expand Down Expand Up @@ -156,7 +156,7 @@ class DevnetTransactions:

def __init__(self, origin: Origin):
self.origin = origin
self.__instances = {}
self.__instances: Dict[int, DevnetTransaction] = {}

def __get_transaction_by_hash(self, tx_hash: str) -> DevnetTransaction or None:
"""
Expand Down
20 changes: 16 additions & 4 deletions starknet_devnet/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def parse_args():
)
parser.add_argument(
"--gas-price", "-g",
type=int,
action=NonNegativeAction,
default=DEFAULT_GAS_PRICE,
help="Specify the gas price in wei per gas unit; " +
f"defaults to {DEFAULT_GAS_PRICE:g}"
Expand Down Expand Up @@ -265,14 +265,25 @@ def generate_state_update(previous_state: CarriedState, current_state: CarriedSt
Returns roots, deployed contracts and storage diffs between 2 states
"""
deployed_contracts: List[DeployedContract] = []
declared_contracts: List[int] = []
storage_diffs: Dict[int, List[StorageEntry]] = {}

for contract_address in current_state.contract_states.keys():
for class_hash in current_state.contract_definitions:
if class_hash not in previous_state.contract_definitions:
declared_contracts.append(
int.from_bytes(class_hash, byteorder="big")
)

for contract_address in current_state.contract_states:
if contract_address not in previous_state.contract_states:
class_hash = int.from_bytes(
current_state.contract_states[contract_address].state.contract_hash,
"big"
)
deployed_contracts.append(
DeployedContract(
address=contract_address,
class_hash=current_state.contract_states[contract_address].state.contract_hash
class_hash=class_hash
)
)
else:
Expand All @@ -287,7 +298,8 @@ def generate_state_update(previous_state: CarriedState, current_state: CarriedSt
old_root = previous_state.shared_state.contract_states.root
state_diff = StateDiff(
deployed_contracts=deployed_contracts,
storage_diffs=storage_diffs,
declared_contracts=tuple(declared_contracts),
storage_diffs=storage_diffs
)

return BlockStateUpdate(
Expand Down
Loading

0 comments on commit 5e7e5ff

Please sign in to comment.