Skip to content
This repository has been archived by the owner on Oct 27, 2024. It is now read-only.

Commit

Permalink
Update raiden-contracts
Browse files Browse the repository at this point in the history
The main required change is to add the new `chain_id` and
`one_to_n_address` parameters to the IOU.

Closes raiden-network#267.
  • Loading branch information
karlb committed May 16, 2019
1 parent 6f9ca56 commit 82223f5
Show file tree
Hide file tree
Showing 17 changed files with 183 additions and 80 deletions.
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
git+https://github.com/raiden-network/raiden.git@0f3b278ae2f20b05a692c94f77d17e365926e9b8

raiden-contracts==0.18.0
raiden-contracts==0.19.0

structlog==18.2.0
colorama==0.3.9
Expand Down
20 changes: 17 additions & 3 deletions src/pathfinding_service/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,12 @@ def __init__(self, debug_mode: bool, **kwargs: Any):
def post(self, token_network_address: str) -> Tuple[dict, int]:
token_network = self._validate_token_network_argument(token_network_address)
path_req = self._parse_post(PathRequest)
process_payment(path_req.iou, self.pathfinding_service, self.service_api.service_fee)
process_payment(
path_req.iou,
self.pathfinding_service,
self.service_api.service_fee,
self.service_api.one_to_n_address,
)

# only add optional args if not None, so we can use defaults
optional_args = {}
Expand Down Expand Up @@ -179,8 +184,11 @@ def create_and_store_feedback_tokens(
return feedback_token


def process_payment(
iou: Optional[IOU], pathfinding_service: PathfindingService, service_fee: TokenAmount
def process_payment( # pylint: disable=too-many-branches
iou: Optional[IOU],
pathfinding_service: PathfindingService,
service_fee: TokenAmount,
one_to_n_address: Address,
) -> None:
if service_fee == 0:
return
Expand All @@ -190,6 +198,10 @@ def process_payment(
# Basic IOU validity checks
if not is_same_address(iou.receiver, pathfinding_service.address):
raise exceptions.WrongIOURecipient(expected=pathfinding_service.address)
if iou.chain_id != pathfinding_service.chain_id:
raise exceptions.UnsupportedChainID(expected=pathfinding_service.chain_id)
if iou.one_to_n_address != one_to_n_address:
raise exceptions.WrongOneToNAddress(expected=one_to_n_address, got=iou.one_to_n_address)
if not iou.is_signature_valid():
raise exceptions.InvalidSignature

Expand Down Expand Up @@ -393,12 +405,14 @@ class ServiceApi:
def __init__(
self,
pathfinding_service: PathfindingService,
one_to_n_address: Address,
service_fee: TokenAmount = TokenAmount(0),
debug_mode: bool = False,
) -> None:
self.flask_app = Flask(__name__)
self.api = ApiWithErrorHandler(self.flask_app)
self.rest_server: Optional[WSGIServer] = None
self.one_to_n_address = one_to_n_address
self.pathfinding_service = pathfinding_service
self.service_fee = service_fee

Expand Down
1 change: 1 addition & 0 deletions src/pathfinding_service/claim_fees.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def claim_ious(
receiver=iou.receiver,
amount=iou.amount,
expiration_block=iou.expiration_block,
one_to_n_address=iou.one_to_n_address,
signature=iou.signature,
)
transferrable = claim.call()
Expand Down
14 changes: 11 additions & 3 deletions src/pathfinding_service/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
from pathfinding_service.config import DEFAULT_API_HOST, DEFAULT_POLL_INTERVALL
from pathfinding_service.service import PathfindingService
from raiden.utils.typing import BlockNumber, TokenAmount
from raiden_contracts.constants import CONTRACT_TOKEN_NETWORK_REGISTRY, CONTRACT_USER_DEPOSIT
from raiden_contracts.constants import (
CONTRACT_ONE_TO_N,
CONTRACT_TOKEN_NETWORK_REGISTRY,
CONTRACT_USER_DEPOSIT,
)
from raiden_libs.cli import blockchain_options, common_options

log = structlog.get_logger(__name__)
Expand All @@ -25,7 +29,8 @@


@blockchain_options(
contracts_version="0.11.1", contracts=[CONTRACT_TOKEN_NETWORK_REGISTRY, CONTRACT_USER_DEPOSIT]
contracts_version="0.11.1",
contracts=[CONTRACT_TOKEN_NETWORK_REGISTRY, CONTRACT_USER_DEPOSIT, CONTRACT_ONE_TO_N],
)
@click.command()
@click.option(
Expand Down Expand Up @@ -73,7 +78,10 @@ def main( # pylint: disable-msg=too-many-arguments
)

api = ServiceApi(
pathfinding_service=service, service_fee=service_fee, debug_mode=enable_debug
pathfinding_service=service,
service_fee=service_fee,
debug_mode=enable_debug,
one_to_n_address=contracts[CONTRACT_ONE_TO_N].address,
)
api.run(host=host)

Expand Down
28 changes: 12 additions & 16 deletions src/pathfinding_service/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,6 @@ def __init__(
**contract_addresses,
)

def upsert_iou(self, iou: IOU) -> None:
iou_dict = IOU.Schema(strict=True).dump(iou)[0]
for key in ("amount", "expiration_block"):
iou_dict[key] = hex256(iou_dict[key])
self.conn.execute(
"""
INSERT OR REPLACE INTO iou (
sender, amount, expiration_block, signature, claimed
) VALUES (
:sender, :amount, :expiration_block, :signature, :claimed
)
""",
iou_dict,
)

def upsert_capacity_update(self, message: UpdatePFS) -> None:
capacity_update_dict = dict(
updating_participant=to_checksum_address(message.updating_participant),
Expand Down Expand Up @@ -122,6 +107,13 @@ def get_latest_known_block(self) -> BlockNumber:
def update_lastest_known_block(self, latest_known_block: BlockNumber) -> None:
self.conn.execute("UPDATE blockchain SET latest_known_block = ?", [latest_known_block])

def upsert_iou(self, iou: IOU) -> None:
iou_dict = IOU.Schema(strict=True, exclude=["receiver", "chain_id"]).dump(iou)[0]
iou_dict["one_to_n_address"] = to_checksum_address(iou_dict["one_to_n_address"])
for key in ("amount", "expiration_block"):
iou_dict[key] = hex256(iou_dict[key])
self.upsert("iou", iou_dict)

def get_ious(
self,
sender: Address = None,
Expand All @@ -130,7 +122,11 @@ def get_ious(
expires_before: BlockNumber = None,
amount_at_least: TokenAmount = None,
) -> Iterator[IOU]:
query = "SELECT * FROM iou WHERE 1=1"
query = """
SELECT *, (SELECT chain_id FROM blockchain) AS chain_id
FROM iou
WHERE 1=1
"""
args: list = []
if sender is not None:
query += " AND sender = ?"
Expand Down
10 changes: 10 additions & 0 deletions src/pathfinding_service/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ class UnsupportedTokenNetwork(ApiException):
msg = "This service does not work on the given token network."


class UnsupportedChainID(ApiException):
error_code = 2005
msg = "This service does not work on the given blockchain."


# ### BadIOU 21xx ###


Expand Down Expand Up @@ -95,6 +100,11 @@ class DepositTooLow(BadIOU):
msg = "Not enough deposit in UserDeposit contract."


class WrongOneToNAddress(BadIOU):
error_code = 2108
msg = "The IOU uses a different OneToN contract than the service"


# ### PFS specific errors 22xx ###


Expand Down
6 changes: 5 additions & 1 deletion src/pathfinding_service/model/iou.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from raiden.exceptions import InvalidSignature
from raiden.utils.signer import recover
from raiden.utils.typing import Address, BlockNumber, Signature, TokenAmount
from raiden.utils.typing import Address, BlockNumber, ChainID, Signature, TokenAmount
from raiden_libs.marshmallow import ChecksumAddress, HexedBytes


Expand All @@ -19,6 +19,8 @@ class IOU:
receiver: Address = field(metadata={"marshmallow_field": ChecksumAddress()})
amount: TokenAmount
expiration_block: BlockNumber
one_to_n_address: Address = field(metadata={"marshmallow_field": ChecksumAddress()})
chain_id: ChainID
signature: Signature = field(metadata={"marshmallow_field": HexedBytes()})
claimed: Optional[bool] = None
Schema: ClassVar[Type[marshmallow.Schema]]
Expand All @@ -29,6 +31,8 @@ def packed_data(self) -> bytes:
+ self.receiver
+ encode_single("uint256", self.amount)
+ encode_single("uint256", self.expiration_block)
+ self.one_to_n_address
+ encode_single("uint256", self.chain_id)
)

def is_signature_valid(self) -> bool:
Expand Down
1 change: 1 addition & 0 deletions src/pathfinding_service/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ CREATE TABLE iou (
expiration_block HEX_INT NOT NULL,
signature CHAR(132) NOT NULL,
claimed BOOL NOT NULL,
one_to_n_address CHAR(42) NOT NULL,
PRIMARY KEY (sender, expiration_block)
);

Expand Down
5 changes: 2 additions & 3 deletions src/raiden_libs/contract_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ def get_contract_addresses_and_start_block(
Returns: A dictionary with the contract addresses and start block for the given information
"""
try:
contract_data = get_contracts_deployment_info(chain_id=chain_id, version=contracts_version)
except ValueError:
contract_data = get_contracts_deployment_info(chain_id=chain_id, version=contracts_version)
if not contract_data:
log.error(
"No deployed contracts were found at the default registry",
contracts_version=contracts_version,
Expand Down
12 changes: 12 additions & 0 deletions src/raiden_libs/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ def _check_settings(
old = old_settings[key]
assert old == val, f"DB was created with {key}={old}, got {val}!"

def insert(
self, table_name: str, fields_by_colname: Dict[str, Any], keyword: str = "INSERT"
) -> sqlite3.Cursor:
cols = ", ".join(fields_by_colname.keys())
values = ", ".join(":" + col_name for col_name in fields_by_colname)
return self.conn.execute(
f"{keyword} INTO {table_name}({cols}) VALUES ({values})", fields_by_colname
)

def upsert(self, table_name: str, fields_by_colname: Dict[str, Any]) -> sqlite3.Cursor:
return self.insert(table_name, fields_by_colname, keyword="INSERT OR REPLACE")

def get_blockchain_state(self) -> BlockchainState:
blockchain = self.conn.execute("SELECT * FROM blockchain").fetchone()
token_network_addresses = [
Expand Down
1 change: 1 addition & 0 deletions tests/pathfinding/fixtures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from .accounts import * # noqa
from .api import * # noqa
from .iou import * # noqa
from .network_service import * # noqa


Expand Down
7 changes: 5 additions & 2 deletions tests/pathfinding/fixtures/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from pathfinding_service.api import ServiceApi
from pathfinding_service.config import API_PATH, DEFAULT_API_PORT
from raiden.utils.typing import Address


def get_free_port(address: str, initial_port: int):
Expand Down Expand Up @@ -60,7 +61,7 @@ def api_sut(
free_port: int,
populate_token_network_case_1, # pylint: disable=unused-argument
) -> Iterator[ServiceApi]:
api = ServiceApi(pathfinding_service_mock)
api = ServiceApi(pathfinding_service_mock, one_to_n_address=Address(bytes([1] * 20)))
api.run(port=free_port)
yield api
api.stop()
Expand All @@ -72,7 +73,9 @@ def api_sut_with_debug(
free_port: int,
populate_token_network_case_1, # pylint: disable=unused-argument
) -> Iterator[ServiceApi]:
api = ServiceApi(pathfinding_service_mock, debug_mode=True)
api = ServiceApi(
pathfinding_service_mock, one_to_n_address=Address(bytes([1] * 20)), debug_mode=True
)
api.run(port=free_port)
yield api
api.stop()
37 changes: 37 additions & 0 deletions tests/pathfinding/fixtures/iou.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import pytest
from eth_utils import encode_hex, to_checksum_address

from pathfinding_service.config import MIN_IOU_EXPIRY
from pathfinding_service.model import IOU
from raiden.utils.typing import Address
from raiden_contracts.utils import sign_one_to_n_iou
from raiden_libs.utils import private_key_to_address


@pytest.fixture
def make_iou(one_to_n_contract):
def f(
sender_priv_key,
receiver: Address,
amount=1,
expiration_block=MIN_IOU_EXPIRY + 100,
one_to_n_address=one_to_n_contract.address,
chain_id=1,
) -> IOU:
receiver_hex: str = to_checksum_address(receiver)
iou_dict = {
"sender": to_checksum_address(private_key_to_address(sender_priv_key)),
"receiver": receiver_hex,
"amount": amount,
"expiration_block": expiration_block,
"one_to_n_address": to_checksum_address(one_to_n_address),
"chain_id": chain_id,
}
iou_dict["signature"] = encode_hex(
sign_one_to_n_iou(privatekey=sender_priv_key, **iou_dict)
)
iou = IOU.Schema(strict=True).load(iou_dict)[0]
iou.claimed = False
return iou

return f
24 changes: 17 additions & 7 deletions tests/pathfinding/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@
from pathfinding_service.model.feedback import FeedbackToken
from raiden.utils.signer import LocalSigner
from raiden.utils.signing import pack_data
from raiden.utils.typing import Address, BlockNumber, Signature, TokenAmount
from raiden.utils.typing import Address, BlockNumber, ChainID, Signature, TokenAmount
from raiden_contracts.tests.utils import get_random_privkey
from raiden_libs.utils import private_key_to_address

from .test_payment import make_iou

ID_12 = 12
ID_123 = 123

Expand Down Expand Up @@ -116,6 +114,8 @@ def test_get_ious_via_debug_endpoint(
to_bytes(hexstr="118a93e9fd0a3a1c3d6edbad194b5c9d95715c754881d80e23e985793b1e13de")
),
claimed=False,
chain_id=ChainID(1),
one_to_n_address=api_sut_with_debug.one_to_n_address,
)
api_sut_with_debug.pathfinding_service.database.upsert_iou(iou)

Expand All @@ -138,7 +138,11 @@ def test_get_ious_via_debug_endpoint(
# tests for /paths endpoint
#
def test_get_paths_validation(
api_sut: ServiceApi, api_url: str, addresses: List[Address], token_network_model: TokenNetwork
api_sut: ServiceApi,
api_url: str,
addresses: List[Address],
token_network_model: TokenNetwork,
make_iou,
):
initiator_address = to_checksum_address(addresses[0])
target_address = to_checksum_address(addresses[1])
Expand Down Expand Up @@ -184,7 +188,11 @@ def request_path_with(status_code=400, **kwargs):
assert response.json()["error_code"] == exceptions.MissingIOU.error_code

# prepare iou for payment tests
iou = make_iou(get_random_privkey(), api_sut.pathfinding_service.address)
iou = make_iou(
get_random_privkey(),
api_sut.pathfinding_service.address,
one_to_n_address=api_sut.one_to_n_address,
)
good_iou_dict = iou.Schema().dump(iou)[0]

# malformed iou
Expand Down Expand Up @@ -275,7 +283,7 @@ def test_get_info(api_url: str, api_sut, pathfinding_service_mock):
#
# tests for /payment/iou endpoint
#
def test_get_iou(api_sut: ServiceApi, api_url: str, token_network_model: TokenNetwork):
def test_get_iou(api_sut: ServiceApi, api_url: str, token_network_model: TokenNetwork, make_iou):
privkey = get_random_privkey()
sender = private_key_to_address(privkey)
url = api_url + f"/{to_checksum_address(token_network_model.address)}/payment/iou"
Expand Down Expand Up @@ -304,7 +312,9 @@ def make_params(timestamp: datetime):
assert response.json() == {"last_iou": None}

# Add IOU to database
iou = make_iou(privkey, api_sut.pathfinding_service.address)
iou = make_iou(
privkey, api_sut.pathfinding_service.address, one_to_n_address=api_sut.one_to_n_address
)
iou.claimed = False
api_sut.pathfinding_service.database.upsert_iou(iou)

Expand Down
Loading

0 comments on commit 82223f5

Please sign in to comment.