Skip to content
This repository has been archived by the owner on Dec 15, 2023. It is now read-only.

Add dump path check #182

Merged
merged 3 commits into from
Jul 15, 2022
Merged
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
7 changes: 6 additions & 1 deletion starknet_devnet/blueprints/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from starknet_devnet.fee_token import FeeToken

from starknet_devnet.state import state
from starknet_devnet.util import StarknetDevnetException
from starknet_devnet.util import StarknetDevnetException, check_valid_dump_path

base = Blueprint("base", __name__)

Expand Down Expand Up @@ -61,6 +61,11 @@ def dump():
if not dump_path:
raise StarknetDevnetException(message="No path provided.", status_code=400)

try:
check_valid_dump_path(dump_path)
except ValueError as error:
raise StarknetDevnetException(status_code=400, message=str(error)) from error

state.dumper.dump(dump_path)
return Response(status=200)

Expand Down
16 changes: 11 additions & 5 deletions starknet_devnet/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@
A server exposing Starknet functionalities as API endpoints.
"""

import sys
from pickle import UnpicklingError
import sys

from flask import Flask, jsonify
from flask_cors import CORS
import meinheld

from starkware.starkware_utils.error_handling import StarkException

from .blueprints.base import base
from .blueprints.gateway import gateway
from .blueprints.feeder_gateway import feeder_gateway
from .blueprints.postman import postman
from .blueprints.rpc import rpc
from .util import DumpOn, parse_args
from .state import state
from .util import DumpOn, check_valid_dump_path, parse_args
from .starknet_wrapper import DevnetConfig
from .state import state

app = Flask(__name__)
CORS(app)
Expand All @@ -44,6 +44,12 @@ def generate_accounts(args):

def set_dump_options(args):
"""Assign dumping options from args to state."""
if args.dump_path:
try:
check_valid_dump_path(args.dump_path)
except ValueError as error:
sys.exit(str(error))

state.dumper.dump_path = args.dump_path
state.dumper.dump_on = args.dump_on

Expand Down Expand Up @@ -89,8 +95,8 @@ def main():
# starknet_wrapper.origin = origin

load_dumped(args)
generate_accounts(args)
set_dump_options(args)
generate_accounts(args)
enable_lite_mode(args)
set_start_time(args)
set_gas_price(args)
Expand Down
15 changes: 14 additions & 1 deletion starknet_devnet/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
Utility functions used across the project.
"""

import argparse
from dataclasses import dataclass
from enum import Enum, auto
import argparse
import os
import sys
from typing import List, Dict, Union

Expand Down Expand Up @@ -302,3 +303,15 @@ def to_bytes(value: Union[int, bytes]) -> bytes:
If bytes, return the received value
"""
return value if isinstance(value, bytes) else value.to_bytes(32, "big")

def check_valid_dump_path(dump_path: str):
"""Checks if dump path is a directory. Raises ValueError if not."""

dump_path_dir = os.path.dirname(dump_path)

if not dump_path_dir:
# dump_path is just a file, with no parent dir
return

if not os.path.isdir(dump_path_dir):
raise ValueError(f"Invalid dump path: directory '{dump_path_dir}' not found.")
26 changes: 23 additions & 3 deletions test/test_dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def test_load_if_no_file():
"""Test loading if dump file not present."""
assert_no_dump_present(DUMP_PATH)
devnet_proc = ACTIVE_DEVNET.start("--load-path", DUMP_PATH, stderr=subprocess.PIPE)
assert devnet_proc.returncode != 0
assert devnet_proc.returncode == 1
expected_msg = f"Error: Cannot load from {DUMP_PATH}. Make sure the file exists and contains a Devnet dump.\n"
assert expected_msg == devnet_proc.stderr.read().decode("utf-8")

Expand All @@ -117,6 +117,26 @@ def test_dumping_if_path_not_provided():
resp = send_dump_request()
assert resp.status_code == 400

NONEXISTENT_DIR = "nonexistent-dir"

def test_dumping_if_nonexistent_dir_via_cli():
"""Assert failure if dumping attempted via cli with a path containing a nonexistent dir"""
invalid_path = os.path.join(NONEXISTENT_DIR, DUMP_PATH)
devnet_proc = ACTIVE_DEVNET.start("--dump-path", invalid_path, stderr=subprocess.PIPE)
assert devnet_proc.returncode == 1

expected_msg = f"Invalid dump path: directory '{NONEXISTENT_DIR}' not found.\n"
assert expected_msg == devnet_proc.stderr.read().decode("utf-8")

@devnet_in_background()
def test_dumping_if_nonexistent_dir_via_http():
"""Assert failure if dumping attempted via http with a path containing a nonexistent dir"""
invalid_path = os.path.join(NONEXISTENT_DIR, DUMP_PATH)

resp = send_dump_request(dump_path=invalid_path)
assert resp.json()["message"] == f"Invalid dump path: directory '{NONEXISTENT_DIR}' not found."
assert resp.status_code == 400

@devnet_in_background("--dump-path", DUMP_PATH)
def test_dumping_if_path_provided_as_cli_option():
"""Test dumping if path provided as CLI option"""
Expand Down Expand Up @@ -207,15 +227,15 @@ def test_invalid_dump_on_option():
stderr=subprocess.PIPE
)

assert devnet_proc.returncode != 0
assert devnet_proc.returncode == 1
expected_msg = b"Error: Invalid --dump-on option: obviously-invalid. Valid options: exit, transaction\n"
assert devnet_proc.stderr.read() == expected_msg

def test_dump_path_not_present_with_dump_on_present():
"""Test behavior when dump-path is not present and dump-on is."""
devnet_proc = ACTIVE_DEVNET.start("--dump-on", "exit", stderr=subprocess.PIPE)

assert devnet_proc.returncode != 0
assert devnet_proc.returncode == 1
expected_msg = b"Error: --dump-path required if --dump-on present\n"
assert devnet_proc.stderr.read() == expected_msg

Expand Down