예제 #1
0
def main() -> None:
    tmpdir = tempfile.mkdtemp()

    geth_nodes = []
    for i in range(NUM_GETH_NODES):
        is_miner = i == 0
        node_key = PrivateKey(sha3(f"node:{i}".encode()))
        p2p_port = Port(START_PORT + i)
        rpc_port = Port(START_RPCPORT + i)

        description = EthNodeDescription(
            private_key=node_key,
            rpc_port=rpc_port,
            p2p_port=p2p_port,
            miner=is_miner,
            extra_config={},
        )

        geth_nodes.append(description)

    rpc_endpoint = f"http://127.0.0.1:{START_RPCPORT}"
    web3 = Web3(HTTPProvider(rpc_endpoint))

    random_marker = remove_0x_prefix(hex(random.getrandbits(100)))
    genesis_description = GenesisDescription(
        prefunded_accounts=DEFAULT_ACCOUNTS,
        random_marker=random_marker,
        chain_id=ChainID(NETWORKNAME_TO_ID["smoketest"]),
    )
    private_chain: ContextManager[
        List[JSONRPCExecutor]] = run_private_blockchain(
            web3=web3,
            eth_nodes=geth_nodes,
            base_datadir=tmpdir,
            log_dir=tmpdir,
            verbosity="info",
            genesis_description=genesis_description,
        )

    with private_chain:
        from IPython import embed

        embed()
예제 #2
0
def test_user_deposit_proxy_withdraw(
    private_keys: List[bytes],
    web3: Web3,
    contract_manager: ContractManager,
    user_deposit_address: Address,
):
    c0_client = JSONRPCClient(web3, PrivateKey(private_keys[0]))
    c0_proxy_manager = ProxyManager(
        rpc_client=c0_client,
        contract_manager=contract_manager,
        metadata=ProxyManagerMetadata(
            token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER,
            filters_start_at=GENESIS_BLOCK_NUMBER,
        ),
    )
    c0_user_deposit_proxy = c0_proxy_manager.user_deposit(
        UserDepositAddress(user_deposit_address), BLOCK_ID_LATEST)

    withdraw_plan = c0_user_deposit_proxy.get_withdraw_plan(
        c0_client.address, BLOCK_ID_LATEST)

    # There should be no withdraw plan
    assert withdraw_plan.withdraw_block == 0
    assert withdraw_plan.withdraw_amount == 0

    current_deposit = c0_user_deposit_proxy.get_total_deposit(
        c0_client.address, BLOCK_ID_LATEST)

    # None of these are valid plan_withdraw amounts
    for value in [-1, 0, current_deposit + 1]:
        with pytest.raises(BrokenPreconditionError):
            c0_user_deposit_proxy.plan_withdraw(TokenAmount(value),
                                                BLOCK_ID_LATEST)

    # With no plan any withdraw must fail in the precondition check
    with pytest.raises(BrokenPreconditionError):
        c0_user_deposit_proxy.withdraw(TokenAmount(1), BLOCK_ID_LATEST)

    withdraw_amount = TokenAmount(current_deposit // 2)
    withdraw_block = c0_user_deposit_proxy.plan_withdraw(
        withdraw_amount, BLOCK_ID_LATEST)

    # The effective balance must take the planned withdraw into account
    effective_balance_after_withdraw_plan = c0_user_deposit_proxy.effective_balance(
        c0_client.address, BLOCK_ID_LATEST)
    assert effective_balance_after_withdraw_plan == current_deposit - withdraw_amount

    # Wait until target block - 1.
    # We set the retry timeout to 0.1 to make sure there is enough time for the failing case
    # below.
    c0_client.wait_until_block(BlockNumber(withdraw_block - 1),
                               retry_timeout=0.1)

    #  Withdraw should still fail
    with pytest.raises(BrokenPreconditionError):
        c0_user_deposit_proxy.withdraw(TokenAmount(withdraw_amount),
                                       BLOCK_ID_LATEST)

    # Wait the final block
    c0_user_deposit_proxy.client.wait_until_block(withdraw_block)

    # Now withdraw must succeed
    c0_user_deposit_proxy.withdraw(TokenAmount(withdraw_amount),
                                   BLOCK_ID_LATEST)

    # The total deposit must now match the reduced value
    new_current_deposit = c0_user_deposit_proxy.get_total_deposit(
        c0_client.address, BLOCK_ID_LATEST)
    assert new_current_deposit == current_deposit - withdraw_amount
예제 #3
0
    CONTRACT_TOKEN_NETWORK_REGISTRY,
    CONTRACT_USER_DEPOSIT,
    TEST_SETTLE_TIMEOUT_MAX,
    TEST_SETTLE_TIMEOUT_MIN,
)
from raiden_contracts.contract_manager import ContractManager, contracts_precompiled_path

if TYPE_CHECKING:
    # pylint: disable=unused-import
    from raiden.tests.utils.transport import ParsedURL  # noqa: F401

# the smoketest will assert that a different endpoint got successfully registered
TEST_DEPOSIT_AMOUNT = TokenAmount(5)

TEST_PRIVKEY = PrivateKey(
    b"\xad\xd4\xd3\x10\xba\x04$hy\x1d\xd7\xbf\x7fn\xae\x85\xac"
    b"\xc4\xdd\x14?\xfa\x81\x0e\xf1\x80\x9aj\x11\xf2\xbcD")
TEST_ACCOUNT_ADDRESS = privatekey_to_address(TEST_PRIVKEY)


class StepPrinter(Protocol):
    def __call__(self, description: str, error: bool = False) -> None:
        ...


def ensure_executable(cmd):
    """look for the given command and make sure it can be executed"""
    if not shutil.which(cmd):
        raise ValueError(
            "Error: unable to locate %s binary.\n"
            "Make sure it is installed and added to the PATH variable." % cmd)
예제 #4
0
from raiden.utils.keys import privatekey_to_address
from raiden.utils.signing import sha3
from raiden.utils.typing import ChainID, List, Port, PrivateKey, TokenAmount
from raiden_contracts.constants import NETWORKNAME_TO_ID

NUM_GETH_NODES = 3
NUM_RAIDEN_ACCOUNTS = 10
START_PORT = 30301
START_RPCPORT = 8101

DEFAULT_ACCOUNTS_SEEDS = [
    "127.0.0.1:{}".format(START_PORT + i).encode()
    for i in range(NUM_RAIDEN_ACCOUNTS)
]
DEFAULT_ACCOUNTS_KEYS: List[PrivateKey] = [
    PrivateKey(keccak(seed)) for seed in DEFAULT_ACCOUNTS_SEEDS
]
DEFAULT_ACCOUNTS = [
    AccountDescription(privatekey_to_address(key),
                       TokenAmount(DEFAULT_BALANCE))
    for key in DEFAULT_ACCOUNTS_KEYS
]


def main() -> None:
    tmpdir = tempfile.mkdtemp()

    geth_nodes = []
    for i in range(NUM_GETH_NODES):
        is_miner = i == 0
        node_key = PrivateKey(sha3(f"node:{i}".encode()))
예제 #5
0
def test_participant_selection(raiden_network, token_addresses):
    # pylint: disable=too-many-locals
    registry_address = raiden_network[0].raiden.default_registry.address
    one_to_n_address = raiden_network[0].raiden.default_one_to_n_address
    token_address = token_addresses[0]
    # connect the first node - this will register the token and open the first channel
    # Since there is no other nodes available to connect to this call will do nothing more
    RaidenAPI(raiden_network[0].raiden).token_network_connect(
        registry_address=registry_address,
        token_address=token_address,
        funds=TokenAmount(100))

    # Test invalid argument values
    with pytest.raises(InvalidAmount):
        RaidenAPI(raiden_network[0].raiden).token_network_connect(
            registry_address=registry_address,
            token_address=token_address,
            funds=TokenAmount(-1))
    with pytest.raises(InvalidAmount):
        RaidenAPI(raiden_network[0].raiden).token_network_connect(
            registry_address=registry_address,
            token_address=token_address,
            funds=TokenAmount(100),
            joinable_funds_target=2,
        )
    with pytest.raises(InvalidAmount):
        RaidenAPI(raiden_network[0].raiden).token_network_connect(
            registry_address=registry_address,
            token_address=token_address,
            funds=TokenAmount(100),
            joinable_funds_target=-1,
        )

    # Call the connect endpoint for all but the first node
    connect_greenlets = set(
        gevent.spawn(
            RaidenAPI(app.raiden).token_network_connect, registry_address,
            token_address, 100) for app in raiden_network[1:])
    gevent.joinall(connect_greenlets, raise_error=True)

    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(raiden_network[0].raiden),
        token_network_registry_address=registry_address,
        token_address=token_address,
    )
    connection_managers = [
        app.raiden.connection_manager_for_token_network(token_network_address)
        for app in raiden_network
    ]

    unsaturated_connection_managers = connection_managers[:]
    exception = AssertionError("Unsaturated connection managers",
                               unsaturated_connection_managers)
    with gevent.Timeout(120, exception):
        while unsaturated_connection_managers:
            for manager in unsaturated_connection_managers:
                if is_manager_saturated(manager, registry_address,
                                        token_address):
                    unsaturated_connection_managers.remove(manager)
            gevent.sleep(1)

    assert saturated_count(connection_managers, registry_address,
                           token_address) == len(connection_managers)

    # ensure unpartitioned network
    for app in raiden_network:
        node_state = views.state_from_raiden(app.raiden)
        network_state = views.get_token_network_by_token_address(
            node_state, registry_address, token_address)
        assert network_state is not None
        for target in raiden_network:
            if target.raiden.address == app.raiden.address:
                continue
            _, routes, _ = routing.get_best_routes(
                chain_state=node_state,
                token_network_address=network_state.address,
                one_to_n_address=one_to_n_address,
                from_address=app.raiden.address,
                to_address=target.raiden.address,
                amount=PaymentAmount(1),
                previous_address=None,
                pfs_config=None,
                privkey=PrivateKey(b""),  # not used if pfs is not configured
            )
            assert routes is not None

    # create a transfer to the leaving node, so we have a channel to settle
    for app in raiden_network:
        sender = app.raiden
        sender_channel = next(
            (channel_state for channel_state in RaidenAPI(
                sender).get_channel_list(registry_address=registry_address,
                                         token_address=token_address)
             if channel_state.our_state.contract_balance > 0
             and channel_state.partner_state.contract_balance > 0),
            None,
        )  # choose a fully funded channel from sender
        if sender_channel:
            break
    assert sender_channel
    registry_address = sender.default_registry.address

    receiver = next(
        app.raiden for app in raiden_network
        if app.raiden.address == sender_channel.partner_state.address)

    # assert there is a direct channel receiver -> sender (vv)
    receiver_channel = RaidenAPI(receiver).get_channel_list(
        registry_address=registry_address,
        token_address=token_address,
        partner_address=sender.address,
    )
    assert len(receiver_channel) == 1

    with gevent.Timeout(30, exception=ValueError("partner not reachable")):
        waiting.wait_for_healthy(sender, receiver.address, PaymentAmount(1))

    with watch_for_unlock_failures(*raiden_network):
        amount = PaymentAmount(1)
        RaidenAPI(sender).transfer_and_wait(registry_address,
                                            token_address,
                                            amount,
                                            receiver.address,
                                            transfer_timeout=10)

        with gevent.Timeout(
                30,
                exception=ValueError(
                    "timeout while waiting for incoming transaction")):
            wait_for_transaction(receiver, registry_address, token_address,
                                 sender.address)

    # test `leave()` method
    connection_manager = connection_managers[0]
    raiden = connection_manager.raiden
    blocks = BlockOffset(sender_channel.settle_timeout * 10)

    channels = views.list_channelstate_for_tokennetwork(
        chain_state=views.state_from_raiden(connection_manager.raiden),
        token_network_registry_address=registry_address,
        token_address=token_address,
    )
    channel_identifiers = [channel.identifier for channel in channels]

    timeout = block_offset_timeout(raiden, "Timeout while waiting for leave",
                                   blocks)
    with timeout:
        RaidenAPI(sender).token_network_leave(registry_address, token_address)

        timeout.exception_to_throw = ValueError("Channels not settled in time")
        waiting.wait_for_settle(
            raiden=connection_manager.raiden,
            token_network_registry_address=registry_address,
            token_address=token_address,
            channel_ids=channel_identifiers,
            retry_timeout=0.1,
        )
예제 #6
0
def test_user_deposit_proxy_withdraw(
    private_keys: List[bytes],
    web3: Web3,
    contract_manager: ContractManager,
    user_deposit_address: Address,
):
    c0_client = JSONRPCClient(web3, PrivateKey(private_keys[0]))
    c0_proxy_manager = ProxyManager(
        rpc_client=c0_client,
        contract_manager=contract_manager,
        metadata=ProxyManagerMetadata(
            token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER,
            filters_start_at=GENESIS_BLOCK_NUMBER,
        ),
    )
    c0_user_deposit_proxy = c0_proxy_manager.user_deposit(
        UserDepositAddress(user_deposit_address), BLOCK_ID_LATEST)

    withdraw_plan = c0_user_deposit_proxy.get_withdraw_plan(
        c0_client.address, BLOCK_ID_LATEST)

    # There should be no withdraw plan
    assert withdraw_plan.withdraw_block == 0
    assert withdraw_plan.withdraw_amount == 0

    initial_deposit = c0_user_deposit_proxy.get_total_deposit(
        c0_client.address, BLOCK_ID_LATEST)

    # None of these are valid plan_withdraw amounts
    for value in [-1, 0, initial_deposit + 1]:
        with pytest.raises(BrokenPreconditionError):
            c0_user_deposit_proxy.plan_withdraw(TokenAmount(value),
                                                BLOCK_ID_LATEST)

    # With no plan any withdraw must fail in the precondition check
    with pytest.raises(BrokenPreconditionError):
        c0_user_deposit_proxy.withdraw(TokenAmount(1), BLOCK_ID_LATEST)

    withdraw_amount = TokenAmount(initial_deposit // 2)
    transaction_hash, withdraw_block = c0_user_deposit_proxy.plan_withdraw(
        withdraw_amount, BLOCK_ID_LATEST)
    assert is_tx_hash_bytes(transaction_hash)

    # The effective balance must take the planned withdraw into account
    effective_balance_after_withdraw_plan = c0_user_deposit_proxy.effective_balance(
        c0_client.address, BLOCK_ID_LATEST)
    assert effective_balance_after_withdraw_plan == initial_deposit - withdraw_amount

    # Wait until target block - 1.
    # We set the retry timeout to 0.1 to make sure there is enough time for the failing case
    # below.
    c0_client.wait_until_block(BlockNumber(withdraw_block - 1),
                               retry_timeout=0.1)

    #  Withdraw should still fail
    with pytest.raises(BrokenPreconditionError):
        c0_user_deposit_proxy.withdraw(TokenAmount(withdraw_amount),
                                       BLOCK_ID_LATEST)

    # Wait the final block
    c0_user_deposit_proxy.client.wait_until_block(withdraw_block)

    # Now withdraw must succeed
    transaction_hash = c0_user_deposit_proxy.withdraw(
        TokenAmount(withdraw_amount), BLOCK_ID_LATEST)
    assert is_tx_hash_bytes(transaction_hash)

    # The current balance must now match the reduced value
    new_current_balance = c0_user_deposit_proxy.get_balance(
        c0_client.address, BLOCK_ID_LATEST)
    assert new_current_balance == initial_deposit - withdraw_amount

    # Deposit again after the funds were withdrawn
    amount_to_deposit = 1
    tasks = set()
    # Force a race condition between deposits, letting successive, concurrent calls
    # wait for the first inflight transaction
    for _ in range(3):
        task = gevent.spawn(
            c0_user_deposit_proxy.approve_and_deposit,
            beneficiary=c0_client.address,
            # the total deposit needs to increase monotonically in the contract
            total_deposit=initial_deposit + amount_to_deposit,
            given_block_identifier=BLOCK_ID_LATEST,
        )
        tasks.add(task)
    results = gevent.joinall(tasks, raise_error=True)
    # All tx have the same deposit,
    # so one of them should successfully transact,
    # while all others should wait for the inflight transaction
    # All calls should then be associated to the same on-chain transaction
    tx_hashes = set(result.get() for result in results)
    assert len(tx_hashes) == 1
    assert is_tx_hash_bytes(tx_hashes.pop())