Skip to content

Commit

Permalink
Genesis block, create block endpoint, performace optimizations(0xSpac…
Browse files Browse the repository at this point in the history
  • Loading branch information
tabaktoni committed Aug 4, 2022
1 parent 7aa1ff7 commit b961de8
Show file tree
Hide file tree
Showing 33 changed files with 271 additions and 120 deletions.
3 changes: 3 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
[FORMAT]
max-line-length=150
string-quote=double
triple-quote=double
docstring-quote=double

[BASIC]
min-public-methods=1
Expand Down
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,38 @@ docker run \

A local block explorer (Voyager), as noted [here](https://voyager.online/local-version/), apparently cannot be set up to work with Devnet. Read more in [this issue](https://github.com/Shard-Labs/starknet-devnet/issues/60).

## Block

Devnet start with a genesis block.

GENESIS_BLOCK_NUMBER = 0

GENESIS_BLOCK_HASH = "0x0"

You can create empty block without transaction.

```
POST /create_block
```

Response:

```
{
"transactions": [],
"parent_block_hash": "0x0",
"timestamp": 1659457385,
"state_root": "004bee3ee...",
"gas_price": "0x174876e800",
"sequencer_address": "0x4bbfb0d1aa...",
"transaction_receipts": [],
"starknet_version": "0.9.1",
"block_hash": "0x1",
"block_number": 1,
"status": "ACCEPTED_ON_L2"
}
```

## Lite mode

To improve Devnet performance, instead of calculating the actual hash of deployment transactions and blocks, sequential numbering can be used (0x0, 0x1, 0x2, ...).
Expand Down
23 changes: 15 additions & 8 deletions poetry.lock

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

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ web3 = "~5.28.0"
psutil = "~5.9.1"
jsonschema = "~3.2.0"
pytest-xdist = "~2.5.0"
pylint-quotes = "~0.2.3"

[build-system]
requires = ["poetry-core>=1.0.0"]
Expand Down
2 changes: 1 addition & 1 deletion scripts/lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

set -e

poetry run pylint $(git ls-files '*.py')
poetry run pylint --load-plugins pylint_quotes $(git ls-files '*.py')
47 changes: 47 additions & 0 deletions starknet_devnet/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,50 @@ async def generate(
self.__state_updates[block_number] = state_update

return block

def generate_empty(
self, state: StarknetState, state_root: bytes, state_update = None
) -> StarknetBlock:
"""
Generate block without transaction
"""
block_number = self.get_number_of_blocks()
timestamp = state.state.block_info.block_timestamp

if block_number == 0:
parent_block_hash = 0
else:
last_block = self.__get_last_block()
parent_block_hash = last_block.block_hash

#Fake block number
block_hash = block_number

block = StarknetBlock.create(
block_hash=block_hash,
block_number=block_number,
state_root=state_root,
transactions=[],
timestamp=timestamp,
transaction_receipts=(),
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,
starknet_version=CAIRO_LANG_VERSION
)

self.__num2block[block_number] = block
self.__hash2num[block_hash] = block_number

if state_update is not None:
state_update = BlockStateUpdate(
block_hash=block_hash,
old_root=state_update.old_root,
new_root=state_update.new_root,
state_diff=state_update.state_diff,
)

self.__state_updates[block_number] = state_update

return block
6 changes: 6 additions & 0 deletions starknet_devnet/blueprints/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,9 @@ async def mint():
"unit": "wei",
"tx_hash": tx_hash
})

@base.route("/create_block", methods=["POST"])
async def create_block():
"""Create empty block"""
block = await state.starknet_wrapper.create_empty_block()
return Response(block.dumps(), status=200, mimetype="application/json")
29 changes: 16 additions & 13 deletions starknet_devnet/blueprints/feeder_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ def _get_block_object(block_hash: str, block_number: int):

return block

def _get_block_transaction_traces(block):
traces = []
if block.transaction_receipts:
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
return BlockTransactionTraces.load({ "traces": traces })

@feeder_gateway.route("/is_alive", methods=["GET"])
def is_alive():
"""Health check endpoint."""
Expand Down Expand Up @@ -86,19 +101,7 @@ def get_block_traces():
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 })
block_transaction_traces = _get_block_transaction_traces(block)

return jsonify(block_transaction_traces.dump())

Expand Down
6 changes: 3 additions & 3 deletions starknet_devnet/blueprints/rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ async def call(contract_address: str, entry_point_selector: str, calldata: list,
raise RpcError(code=-1, message=ex.message) from ex


async def estimate_fee():
async def estimate_fee(request_body: dict):
"""
Get the estimate fee for the transaction
"""
Expand All @@ -304,7 +304,7 @@ async def chain_id() -> str:
"""
Return the currently configured StarkNet chain id
"""
devnet_state = await state.starknet_wrapper.get_state()
devnet_state = state.starknet_wrapper.get_state()
config = devnet_state.general_config
chain: int = config.chain_id.value
return hex(chain)
Expand Down Expand Up @@ -526,7 +526,7 @@ def new_root() -> str:
}
transactions: list = await mapping[requested_scope]()

devnet_state = await state.starknet_wrapper.get_state()
devnet_state = state.starknet_wrapper.get_state()
config = devnet_state.general_config

block: RpcBlock = {
Expand Down
6 changes: 3 additions & 3 deletions starknet_devnet/fee_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ async def deploy(self):
state=newly_deployed_fee_token_state,
storage_updates={
# Running the constructor doesn't need to be simulated
get_selector_from_name('ERC20_name'): StorageLeaf(int.from_bytes(bytes(FeeToken.NAME, "ascii"), "big")),
get_selector_from_name('ERC20_symbol'): StorageLeaf(int.from_bytes(bytes(FeeToken.SYMBOL, "ascii"), "big")),
get_selector_from_name('ERC20_decimals'): StorageLeaf(18)
get_selector_from_name("ERC20_name"): StorageLeaf(int.from_bytes(bytes(FeeToken.NAME, "ascii"), "big")),
get_selector_from_name("ERC20_symbol"): StorageLeaf(int.from_bytes(bytes(FeeToken.SYMBOL, "ascii"), "big")),
get_selector_from_name("ERC20_decimals"): StorageLeaf(18)
}
)

Expand Down
3 changes: 3 additions & 0 deletions starknet_devnet/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from pickle import UnpicklingError
import sys
import asyncio

from flask import Flask, jsonify
from flask_cors import CORS
Expand Down Expand Up @@ -102,6 +103,8 @@ def main():
set_start_time(args)
set_gas_price(args)

asyncio.run(state.starknet_wrapper.initialize())

try:
meinheld.listen((args.host, args.port))
print(f" * Listening on http:https://{args.host}:{args.port}/ (Press CTRL+C to quit)")
Expand Down
Loading

0 comments on commit b961de8

Please sign in to comment.