Esempio n. 1
0
def test_monitor_on_wrong_token_network_registry(
    token_network_in_another_token_network_registry: Contract,
    monitoring_service_external: Contract,
    monitor_data: Dict,
    ms_address: HexAddress,
    web3: Web3,
) -> None:
    A, B = monitor_data["participants"]

    # wait until MS is allowed to monitor
    mine_blocks(web3, monitor_data["first_allowed"] - web3.eth.block_number)

    # monitor() call fails because the TokenNetwork is not registered on the
    # supposed TokenNetworkRegistry
    with pytest.raises(TransactionFailed, match="Unknown TokenNetwork"):
        call_and_transact(
            monitoring_service_external.functions.monitor(
                A,
                B,
                *monitor_data["balance_proof_B"]._asdict().values(),
                monitor_data["non_closing_signature"],
                REWARD_AMOUNT,
                token_network_in_another_token_network_registry.address,
                monitor_data["reward_proof_signature"],
            ),
            {"from": ms_address},
        )
Esempio n. 2
0
def print_gas_user_deposit(
    user_deposit_contract: Contract,
    custom_token: Contract,
    get_accounts: Callable,
    web3: Web3,
    print_gas: Callable,
) -> None:
    """Abusing pytest to print gas cost of UserDeposit functions

    The `transfer` function is not included because it's only called by trusted
    contracts as part of another function.
    """
    (A,) = get_accounts(1)
    call_and_transact(custom_token.functions.mint(20), {"from": A})
    call_and_transact(
        custom_token.functions.approve(user_deposit_contract.address, 20), {"from": A}
    )

    # deposit
    txn_hash = call_and_transact(user_deposit_contract.functions.deposit(A, 10), {"from": A})
    print_gas(txn_hash, CONTRACT_USER_DEPOSIT + ".deposit")
    txn_hash = call_and_transact(user_deposit_contract.functions.deposit(A, 20), {"from": A})
    print_gas(txn_hash, CONTRACT_USER_DEPOSIT + ".deposit (increase balance)")

    # plan withdraw
    txn_hash = call_and_transact(user_deposit_contract.functions.planWithdraw(10), {"from": A})
    print_gas(txn_hash, CONTRACT_USER_DEPOSIT + ".planWithdraw")

    # withdraw
    withdraw_delay = user_deposit_contract.functions.withdraw_delay().call()
    mine_blocks(web3, withdraw_delay)
    txn_hash = call_and_transact(user_deposit_contract.functions.withdraw(10), {"from": A})
    print_gas(txn_hash, CONTRACT_USER_DEPOSIT + ".withdraw")
Esempio n. 3
0
def deploy_contract_txhash(
    web3: Web3,
    contracts_manager: ContractManager,
    deployer_address: HexAddress,
    contract_name: str,
    libs: Dict = None,
    **kwargs: Any,
) -> Tuple[HexAddress, Contract]:
    json_contract = contracts_manager.get_contract(contract_name)
    abi = json_contract["abi"]
    bytecode = json_contract["bin"]
    bytecode_runtime = None

    if isinstance(libs, dict) and len(libs.keys()) > 0:
        bytecode = link_code(bytecode, libs)
        bytecode_runtime = link_code(json_contract["bin-runtime"], libs)

    if bytecode_runtime is not None:
        contract = web3.eth.contract(abi=abi, bytecode=bytecode, bytecode_runtime=bytecode_runtime)
    else:
        contract = web3.eth.contract(abi=abi, bytecode=bytecode)

    mine_blocks(web3, 3)
    # Failure does not fire an exception. Check the receipt for status.
    txhash = contract.constructor(**kwargs).transact({"from": deployer_address})
    mine_blocks(web3, 1)

    receipt = web3.eth.getTransactionReceipt(txhash)
    if receipt["status"] != 1:
        raise TransactionFailed("deployment failed")

    return txhash, contract(receipt["contractAddress"])
def test_settle2_no_bp_success(
    web3: Web3,
    custom_token: Contract,
    token_network: Contract,
    create_channel_and_deposit: Callable,
    get_accounts: Callable,
    create_close_signature_for_no_balance_proof: Callable,
) -> None:
    """The simplest settlement, tested against the V2 ABI settle"""
    (A, B) = get_accounts(2)
    deposit_A = 10
    deposit_B = 6
    settle_timeout = TEST_SETTLE_TIMEOUT_MIN
    channel_identifier = create_channel_and_deposit(A, B, deposit_A, deposit_B)
    closing_sig = create_close_signature_for_no_balance_proof(
        A, channel_identifier)

    # Close channel with no balance proof
    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier,
            B,
            A,
            EMPTY_BALANCE_HASH,
            0,
            EMPTY_ADDITIONAL_HASH,
            EMPTY_SIGNATURE,
            closing_sig,
        ),
        {"from": A},
    )

    # Do not call updateNonClosingBalanceProof

    # Settlement window must be over before settling the channel
    mine_blocks(web3, settle_timeout + 1)

    # Settling the channel should work with no balance proofs
    call_and_transact(
        token_network.functions.settleChannel2(
            channel_identifier=channel_identifier,
            participant1_settlement=dict(
                participant=A,
                transferred_amount=0,
                locked_amount=0,
                locksroot=LOCKSROOT_OF_NO_LOCKS,
            ),
            participant2_settlement=dict(
                participant=B,
                transferred_amount=0,
                locked_amount=0,
                locksroot=LOCKSROOT_OF_NO_LOCKS,
            ),
        ),
        {"from": A},
    )

    assert custom_token.functions.balanceOf(A).call() == deposit_A
    assert custom_token.functions.balanceOf(B).call() == deposit_B
Esempio n. 5
0
    def get(
        participant1: HexAddress,
        locked_amount1: int,
        locksroot1: bytes,
        participant2: HexAddress,
        locked_amount2: int,
        locksroot2: bytes,
        settle_timeout: int = TEST_SETTLE_TIMEOUT_MIN,
    ) -> int:
        participant1_values = ChannelValues(
            transferred=5,
            locked_amounts=LockedAmounts(claimable_locked=locked_amount1),
            locksroot=locksroot1,
        )
        participant2_values = ChannelValues(
            transferred=40,
            locked_amounts=LockedAmounts(claimable_locked=locked_amount2),
            locksroot=locksroot2,
        )

        participant1_values.deposit = (
            participant1_values.locked_amounts.locked +
            participant1_values.transferred - 5)
        participant2_values.deposit = (
            participant2_values.locked_amounts.locked +
            participant2_values.transferred + 5)

        channel_identifier = create_channel_and_deposit(
            participant1,
            participant2,
            participant1_values.deposit,
            participant2_values.deposit,
            settle_timeout,
        )

        close_and_update_channel(
            channel_identifier,
            participant1,
            participant1_values,
            participant2,
            participant2_values,
        )

        mine_blocks(web3, settle_timeout)

        call_settle(
            token_network,
            channel_identifier,
            participant1,
            participant1_values,
            participant2,
            participant2_values,
        )

        return channel_identifier
def test_withdraw_to_beneficiary(
    user_deposit_contract: Contract,
    deposit_to_udc: Callable,
    get_accounts: Callable,
    web3: Web3,
    event_handler: Callable,
    custom_token: Contract,
) -> None:
    """Test the interaction between planWithdraw, withdrawToBeneficiary and effectiveBalance"""
    ev_handler = event_handler(user_deposit_contract)
    (A, B) = get_accounts(2)
    deposit_to_udc(A, 30)
    assert user_deposit_contract.functions.balances(A).call() == 30
    assert user_deposit_contract.functions.effectiveBalance(A).call() == 30

    # plan withdraw of 20 tokens
    tx_hash = call_and_transact(
        user_deposit_contract.functions.planWithdraw(20), {"from": A})
    ev_handler.assert_event(
        tx_hash,
        UserDepositEvent.WITHDRAW_PLANNED,
        dict(withdrawer=A, plannedBalance=10),
    )
    assert user_deposit_contract.functions.balances(A).call() == 30
    assert user_deposit_contract.functions.effectiveBalance(A).call() == 10

    # beneficiary can not be zero address
    with pytest.raises(TransactionFailed, match="beneficiary is zero"):
        user_deposit_contract.functions.withdrawToBeneficiary(
            18, ZERO_ADDRESS).call({"from": A})

    # withdraw won't work before withdraw_delay elapsed
    withdraw_delay = user_deposit_contract.functions.withdraw_delay().call()
    mine_blocks(web3, withdraw_delay - 1)
    with pytest.raises(TransactionFailed, match="withdrawing too early"):
        user_deposit_contract.functions.withdrawToBeneficiary(18, B).call(
            {"from": A})

    # can't withdraw more then planned
    mine_blocks(web3, 1)  # now withdraw_delay is over
    with pytest.raises(TransactionFailed,
                       match="withdrawing more than planned"):
        user_deposit_contract.functions.withdrawToBeneficiary(21, B).call(
            {"from": A})

    # actually withdraw 18 tokens
    assert custom_token.functions.balanceOf(B).call() == 0
    call_and_transact(
        user_deposit_contract.functions.withdrawToBeneficiary(18, B),
        {"from": A})
    assert user_deposit_contract.functions.balances(A).call() == 12
    assert user_deposit_contract.functions.effectiveBalance(A).call() == 12

    assert custom_token.functions.balanceOf(B).call() == 18
Esempio n. 7
0
    def fn(
        web3: Web3, deployer_address: HexAddress, abi: List, bytecode: str, **kwargs: Dict
    ) -> Contract:
        contract = web3.eth.contract(abi=abi, bytecode=bytecode)
        txhash = deploy_contract_txhash(web3, deployer_address, abi, bytecode, **kwargs)
        contract_address = web3.eth.getTransactionReceipt(txhash)["contractAddress"]
        mine_blocks(web3, 1)

        if web3.eth.getTransactionReceipt(txhash)["status"] != 1:
            raise TransactionFailed("deployment failed")

        return contract(contract_address)
def test_update_not_allowed_after_settlement_period(
    token_network: Contract,
    create_channel: Callable,
    channel_deposit: Callable,
    get_accounts: Callable,
    create_balance_proof: Callable,
    create_balance_proof_countersignature: Callable,
    web3: Web3,
) -> None:
    """ updateNonClosingBalanceProof cannot be called after the settlement period. """
    (A, B) = get_accounts(2)
    settle_timeout = TEST_SETTLE_TIMEOUT_MIN
    deposit_A = 20
    channel_identifier = create_channel(A, B, settle_timeout)[0]
    channel_deposit(channel_identifier, A, deposit_A, B)
    balance_proof_A = create_balance_proof(channel_identifier, A, 10, 0, 5,
                                           fake_bytes(32, "02"))
    balance_proof_B = create_balance_proof(channel_identifier, B, 5, 0, 3,
                                           fake_bytes(32, "02"))
    closing_sig_A = create_balance_proof_countersignature(
        participant=A,
        channel_identifier=channel_identifier,
        msg_type=MessageTypeId.BALANCE_PROOF,
        **balance_proof_B._asdict(),
    )
    balance_proof_update_signature_B = create_balance_proof_countersignature(
        participant=B,
        channel_identifier=channel_identifier,
        msg_type=MessageTypeId.BALANCE_PROOF_UPDATE,
        **balance_proof_A._asdict(),
    )
    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier, B, A,
            *balance_proof_B._asdict().values(), closing_sig_A),
        {"from": A},
    )
    mine_blocks(web3, settle_timeout + 1)
    with pytest.raises(TransactionFailed):
        token_network.functions.updateNonClosingBalanceProof(
            channel_identifier,
            A,
            B,
            *balance_proof_A._asdict().values(),
            balance_proof_update_signature_B,
        ).call({"from": A})
def test_withdraw(
    user_deposit_contract: Contract,
    deposit_to_udc: Callable,
    get_accounts: Callable,
    web3: Web3,
    event_handler: Callable,
) -> None:
    """Test the interaction between planWithdraw, widthdraw and effectiveBalance"""
    ev_handler = event_handler(user_deposit_contract)
    (A, ) = get_accounts(1)
    deposit_to_udc(A, 30)
    assert user_deposit_contract.functions.balances(A).call() == 30
    assert user_deposit_contract.functions.effectiveBalance(A).call() == 30

    # plan withdraw of 20 tokens
    tx_hash = call_and_transact(
        user_deposit_contract.functions.planWithdraw(20), {"from": A})
    ev_handler.assert_event(
        tx_hash,
        UserDepositEvent.WITHDRAW_PLANNED,
        dict(withdrawer=A, plannedBalance=10),
    )
    assert user_deposit_contract.functions.balances(A).call() == 30
    assert user_deposit_contract.functions.effectiveBalance(A).call() == 10

    # withdraw won't work before withdraw_delay elapsed
    withdraw_delay = user_deposit_contract.functions.withdraw_delay().call()
    mine_blocks(web3, withdraw_delay - 1)
    with pytest.raises(TransactionFailed, match="withdrawing too early"):
        user_deposit_contract.functions.withdraw(18).call({"from": A})

    # can't withdraw more then planned
    mine_blocks(web3, 1)  # now withdraw_delay is over
    with pytest.raises(TransactionFailed,
                       match="withdrawing more than planned"):
        user_deposit_contract.functions.withdraw(21).call({"from": A})

    # actually withdraw 18 tokens
    call_and_transact(user_deposit_contract.functions.withdraw(18),
                      {"from": A})
    assert user_deposit_contract.functions.balances(A).call() == 12
    assert user_deposit_contract.functions.effectiveBalance(A).call() == 12
def test_deposit_notapproved(
    token_network: Contract,
    custom_token: Contract,
    create_channel: Callable,
    get_accounts: Callable,
    web3: Web3,
) -> None:
    """ Calling setTotalDeposit() fails without approving transfers on the token contract """
    (A, B) = get_accounts(2)
    channel_identifier = create_channel(A, B)[0]
    deposit_A = 1

    call_and_transact(custom_token.functions.mint(deposit_A), {"from": A})
    mine_blocks(web3, 1)
    balance = custom_token.functions.balanceOf(A).call()
    assert balance >= deposit_A, f"minted {deposit_A} but the balance is still {balance}"

    with pytest.raises(TransactionFailed):
        token_network.functions.setTotalDeposit(channel_identifier, A,
                                                deposit_A, B).call({"from": A})
    assert (0 == token_network.functions.getChannelParticipantInfo(
        channel_identifier, A, B).call()[0])
Esempio n. 11
0
def test_monitor_by_unregistered_service(
    token_network: Contract,
    monitoring_service_external: Contract,
    monitor_data: Dict,
    ms_address: HexAddress,
    web3: Web3,
) -> None:
    A, B = monitor_data["participants"]

    # wait until MS is allowed to monitor
    mine_blocks(web3, monitor_data["first_allowed"] - web3.eth.block_number)

    # only registered service providers may call `monitor`
    with pytest.raises(TransactionFailed, match="service not registered"):
        monitoring_service_external.functions.monitor(
            A,
            B,
            *monitor_data["balance_proof_B"]._asdict().values(),
            monitor_data["non_closing_signature"],
            REWARD_AMOUNT,
            token_network.address,
            monitor_data["reward_proof_signature"],
        ).call({"from": B})

    # See a success to make sure the above failure is not spurious
    call_and_transact(
        monitoring_service_external.functions.monitor(
            A,
            B,
            *monitor_data["balance_proof_B"]._asdict().values(),
            monitor_data["non_closing_signature"],
            REWARD_AMOUNT,
            token_network.address,
            monitor_data["reward_proof_signature"],
        ),
        {"from": ms_address},
    )
def test_settle_channel_state(
    web3: Web3,
    get_accounts: Callable,
    custom_token: Contract,
    token_network: Contract,
    create_channel_and_deposit: Callable,
    withdraw_channel: Callable,
    close_and_update_channel: Callable,
    settle_state_tests: Callable,
) -> None:
    """settleChannel() with some balance proofs"""
    (A, B) = get_accounts(2)
    vals_A = ChannelValues(
        deposit=40,
        withdrawn=10,
        transferred=20020,
        locked_amounts=LockedAmounts(claimable_locked=3, unclaimable_locked=4),
    )
    vals_B = ChannelValues(
        deposit=35,
        withdrawn=5,
        transferred=20030,
        locked_amounts=LockedAmounts(claimable_locked=2, unclaimable_locked=3),
    )

    pending_transfers_tree_A = get_pending_transfers_tree_with_generated_lists(
        web3,
        unlockable_amount=vals_A.locked_amounts.claimable_locked,
        expired_amount=vals_A.locked_amounts.unclaimable_locked,
    )
    pending_transfers_tree_B = get_pending_transfers_tree_with_generated_lists(
        web3,
        unlockable_amount=vals_B.locked_amounts.claimable_locked,
        expired_amount=vals_B.locked_amounts.unclaimable_locked,
    )
    vals_A.locksroot = pending_transfers_tree_A.hash_of_packed_transfers
    vals_B.locksroot = pending_transfers_tree_B.hash_of_packed_transfers

    channel_identifier = create_channel_and_deposit(A, B, vals_A.deposit,
                                                    vals_B.deposit)
    withdraw_channel(channel_identifier, A, vals_A.withdrawn, UINT256_MAX, B)
    withdraw_channel(channel_identifier, B, vals_B.withdrawn, UINT256_MAX, A)
    close_and_update_channel(channel_identifier, A, vals_A, B, vals_B)

    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)

    pre_balance_A = custom_token.functions.balanceOf(A).call()
    pre_balance_B = custom_token.functions.balanceOf(B).call()
    pre_balance_contract = custom_token.functions.balanceOf(
        token_network.address).call()

    call_settle(token_network, channel_identifier, A, vals_A, B, vals_B)

    # Balance & state tests
    settle_state_tests(
        channel_identifier,
        A,
        vals_A,
        B,
        vals_B,
        pre_balance_A,
        pre_balance_B,
        pre_balance_contract,
    )

    # Some manual checks for the final balances, in case the settlement algorithms
    # used in `settle_state_tests` are incorrect

    # FIXME after setTotalWithdraw is implemented again
    post_balance_A = pre_balance_A + 33
    post_balance_B = pre_balance_B + 15
    post_balance_contract = pre_balance_contract - 48

    assert custom_token.functions.balanceOf(A).call() == post_balance_A
    assert custom_token.functions.balanceOf(B).call() == post_balance_B
    assert custom_token.functions.balanceOf(
        token_network.address).call() == post_balance_contract
def test_settle_single_direct_transfer_for_counterparty(
    web3: Web3,
    get_accounts: Callable,
    custom_token: Contract,
    token_network: Contract,
    create_channel: Callable,
    channel_deposit: Callable,
    create_balance_proof: Callable,
    create_balance_proof_countersignature: Callable,
    create_close_signature_for_no_balance_proof: Callable,
) -> None:
    """Test settle of a channel with one direct transfer to the participant
    that did not call close.
    """
    (A, B) = get_accounts(2)
    (vals_A, vals_B) = (
        ChannelValues(deposit=10, withdrawn=0, transferred=5),
        ChannelValues(deposit=1, withdrawn=0, transferred=0),
    )
    settle_timeout = TEST_SETTLE_TIMEOUT_MIN

    channel_identifier = create_channel(A, B)[0]
    channel_deposit(channel_identifier, A, vals_A.deposit, B)
    channel_deposit(channel_identifier, B, vals_B.deposit, A)
    closing_sig = create_close_signature_for_no_balance_proof(
        A, channel_identifier)
    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier,
            B,
            A,
            EMPTY_BALANCE_HASH,
            0,
            EMPTY_ADDITIONAL_HASH,
            EMPTY_SIGNATURE,
            closing_sig,
        ),
        {"from": A},
    )

    balance_proof_A = create_balance_proof(
        channel_identifier,
        A,
        vals_A.transferred,
        vals_A.locked_amounts.locked,
        1,
        LOCKSROOT_OF_NO_LOCKS,
    )

    balance_proof_update_signature_B = create_balance_proof_countersignature(
        participant=B,
        channel_identifier=channel_identifier,
        msg_type=MessageTypeId.BALANCE_PROOF_UPDATE,
        **balance_proof_A._asdict(),
    )
    call_and_transact(
        token_network.functions.updateNonClosingBalanceProof(
            channel_identifier,
            A,
            B,
            *balance_proof_A._asdict().values(),
            balance_proof_update_signature_B,
        ),
        {"from": B},
    )

    pre_balance_A = custom_token.functions.balanceOf(A).call()
    pre_balance_B = custom_token.functions.balanceOf(B).call()
    pre_balance_contract = custom_token.functions.balanceOf(
        token_network.address).call()

    mine_blocks(web3, settle_timeout + 1)
    call_and_transact(
        token_network.functions.settleChannel(
            channel_identifier=channel_identifier,
            participant1=B,
            participant1_transferred_amount=0,
            participant1_locked_amount=0,
            participant1_locksroot=LOCKSROOT_OF_NO_LOCKS,
            participant2=A,
            participant2_transferred_amount=vals_A.transferred,
            participant2_locked_amount=0,
            participant2_locksroot=LOCKSROOT_OF_NO_LOCKS,
        ),
        {"from": B},
    )

    # Calculate how much A and B should receive
    expected_settlement = get_settlement_amounts(vals_B, vals_A)
    # Calculate how much A and B receive according to onchain computation
    onchain_settlement = get_onchain_settlement_amounts(vals_B, vals_A)

    assert expected_settlement.participant1_balance == onchain_settlement.participant1_balance
    assert expected_settlement.participant2_balance == onchain_settlement.participant2_balance
    assert custom_token.functions.balanceOf(A).call() == pre_balance_A + 5
    assert custom_token.functions.balanceOf(B).call() == pre_balance_B + 6
    assert (custom_token.functions.balanceOf(
        token_network.address).call() == pre_balance_contract - 11)
Esempio n. 14
0
def print_gas_channel_cycle(
    web3: Web3,
    token_network: Contract,
    create_channel: Callable,
    channel_deposit: Callable,
    withdraw_channel: Callable,
    secret_registry_contract: Contract,
    get_accounts: Callable,
    print_gas: Callable,
    create_balance_proof: Callable,
    create_balance_proof_countersignature: Callable,
) -> None:
    """Abusing pytest to print gas costs of TokenNetwork's operations"""
    (A, B, C, D) = get_accounts(4)
    settle_timeout = 11

    (channel_identifier, txn_hash) = create_channel(A, B, settle_timeout)
    print_gas(txn_hash, CONTRACT_TOKEN_NETWORK + ".openChannel")

    (_, txn_hash) = create_channel(C, D, settle_timeout)
    print_gas(txn_hash, CONTRACT_TOKEN_NETWORK + ".openChannel")

    txn_hash = channel_deposit(channel_identifier, A, 20, B)
    print_gas(txn_hash, CONTRACT_TOKEN_NETWORK + ".setTotalDeposit")

    txn_hash = channel_deposit(channel_identifier, B, 10, A)
    print_gas(txn_hash, CONTRACT_TOKEN_NETWORK + ".setTotalDeposit")

    txn_hash = withdraw_channel(channel_identifier, A, 5, UINT256_MAX, B)
    print_gas(txn_hash, CONTRACT_TOKEN_NETWORK + ".setTotalWithdraw")

    pending_transfers_tree1 = get_pending_transfers_tree(
        web3, [1, 1, 2, 3], [2, 1])
    locksroot1 = pending_transfers_tree1.hash_of_packed_transfers
    locked_amount1 = get_locked_amount(pending_transfers_tree1.transfers)

    pending_transfers_tree2 = get_pending_transfers_tree(web3, [3], [], 7)
    locksroot2 = pending_transfers_tree2.hash_of_packed_transfers
    locked_amount2 = get_locked_amount(pending_transfers_tree2.transfers)

    balance_proof_A = create_balance_proof(channel_identifier, A, 10,
                                           locked_amount1, 5, locksroot1)
    balance_proof_update_signature_B = create_balance_proof_countersignature(
        participant=B,
        channel_identifier=channel_identifier,
        msg_type=MessageTypeId.BALANCE_PROOF_UPDATE,
        **balance_proof_A._asdict(),
    )
    balance_proof_B = create_balance_proof(channel_identifier, B, 5,
                                           locked_amount2, 3, locksroot2)
    closing_sig_A = create_balance_proof_countersignature(
        participant=A,
        channel_identifier=channel_identifier,
        msg_type=MessageTypeId.BALANCE_PROOF,
        **balance_proof_B._asdict(),
    )

    for lock in pending_transfers_tree1.unlockable:
        txn_hash = call_and_transact(
            secret_registry_contract.functions.registerSecret(lock[3]),
            {"from": A})
    print_gas(txn_hash, CONTRACT_SECRET_REGISTRY + ".registerSecret")

    for lock in pending_transfers_tree2.unlockable:
        txn_hash = call_and_transact(
            secret_registry_contract.functions.registerSecret(lock[3]),
            {"from": A})
    print_gas(txn_hash, CONTRACT_SECRET_REGISTRY + ".registerSecret")

    txn_hash = call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier, B, A,
            *balance_proof_B._asdict().values(), closing_sig_A),
        {"from": A},
    )
    print_gas(txn_hash, CONTRACT_TOKEN_NETWORK + ".closeChannel")

    txn_hash = call_and_transact(
        token_network.functions.updateNonClosingBalanceProof(
            channel_identifier,
            A,
            B,
            *balance_proof_A._asdict().values(),
            balance_proof_update_signature_B,
        ),
        {"from": B},
    )
    print_gas(txn_hash,
              CONTRACT_TOKEN_NETWORK + ".updateNonClosingBalanceProof")

    mine_blocks(web3, settle_timeout)
    txn_hash = call_and_transact(
        token_network.functions.settleChannel(
            channel_identifier,
            B,
            5,
            locked_amount2,
            locksroot2,
            A,
            10,
            locked_amount1,
            locksroot1,
        ))
    print_gas(txn_hash, CONTRACT_TOKEN_NETWORK + ".settleChannel")

    txn_hash = call_and_transact(
        token_network.functions.unlock(
            channel_identifier, A, B,
            pending_transfers_tree2.packed_transfers))
    print_gas(
        txn_hash,
        "{0}.unlock {1} locks".format(CONTRACT_TOKEN_NETWORK,
                                      len(pending_transfers_tree2.transfers)),
    )

    txn_hash = call_and_transact(
        token_network.functions.unlock(
            channel_identifier, B, A,
            pending_transfers_tree1.packed_transfers))
    print_gas(
        txn_hash,
        "{0}.unlock {1} locks".format(CONTRACT_TOKEN_NETWORK,
                                      len(pending_transfers_tree1.transfers)),
    )
Esempio n. 15
0
def print_gas_monitoring_service(
    token_network: Contract,
    monitoring_service_external: Contract,
    get_accounts: Callable,
    create_channel: Callable,
    create_balance_proof: Callable,
    create_balance_proof_countersignature: Callable,
    service_registry: Contract,
    custom_token: Contract,
    deposit_to_udc: Callable,
    print_gas: Callable,
    get_private_key: Callable,
    create_service_account: Callable,
    web3: Web3,
) -> None:
    """Abusing pytest to print gas cost of MonitoringService functions"""
    # setup: two parties + MS
    (A, MS) = get_accounts(2)
    B = create_service_account()
    reward_amount = TokenAmount(10)
    deposit_to_udc(B, reward_amount)

    # register MS in the ServiceRegistry contract
    call_and_transact(custom_token.functions.mint(SERVICE_DEPOSIT * 2),
                      {"from": MS})
    call_and_transact(
        custom_token.functions.approve(service_registry.address,
                                       SERVICE_DEPOSIT),
        {"from": MS},
    )
    call_and_transact(service_registry.functions.deposit(SERVICE_DEPOSIT),
                      {"from": MS})

    # open a channel (c1, c2)
    channel_identifier = create_channel(A, B)[0]

    # create balance and reward proofs
    balance_proof_A = create_balance_proof(channel_identifier,
                                           B,
                                           transferred_amount=10,
                                           nonce=1)
    closing_sig_A = create_balance_proof_countersignature(
        participant=A,
        channel_identifier=channel_identifier,
        msg_type=MessageTypeId.BALANCE_PROOF,
        **balance_proof_A._asdict(),
    )
    balance_proof_B = create_balance_proof(channel_identifier,
                                           A,
                                           transferred_amount=20,
                                           nonce=2)
    non_closing_signature_B = create_balance_proof_countersignature(
        participant=B,
        channel_identifier=channel_identifier,
        msg_type=MessageTypeId.BALANCE_PROOF_UPDATE,
        **balance_proof_B._asdict(),
    )
    reward_proof_signature = sign_reward_proof(
        privatekey=get_private_key(B),
        monitoring_service_contract_address=monitoring_service_external.
        address,
        chain_id=token_network.functions.chain_id().call(),
        token_network_address=token_network.address,
        non_closing_participant=B,
        reward_amount=reward_amount,
        non_closing_signature=non_closing_signature_B,
    )

    # c1 closes channel
    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier, B, A,
            *balance_proof_A._asdict().values(), closing_sig_A),
        {"from": A},
    )
    mine_blocks(web3, 4)

    # MS calls `MSC::monitor()` using c1's BP and reward proof
    txn_hash = call_and_transact(
        monitoring_service_external.functions.monitor(
            A,
            B,
            balance_proof_B.balance_hash,
            balance_proof_B.nonce,
            balance_proof_B.additional_hash,
            balance_proof_B.original_signature,
            non_closing_signature_B,  # non-closing signature
            reward_amount,
            token_network.address,  # token network address
            reward_proof_signature,
        ),
        {"from": MS},
    )
    print_gas(txn_hash, CONTRACT_MONITORING_SERVICE + ".monitor")

    mine_blocks(web3, 1)

    # MS claims the reward
    txn_hash = call_and_transact(
        monitoring_service_external.functions.claimReward(
            channel_identifier, token_network.address, A, B),
        {"from": MS},
    )
    print_gas(txn_hash, CONTRACT_MONITORING_SERVICE + ".claimReward")
def test_deprecation_switch_settle(
    web3: Web3,
    get_accounts: Callable,
    token_network: Contract,
    custom_token: Contract,
    reveal_secrets: Callable,
    create_channel: Callable,
    channel_deposit: Callable,
    close_and_update_channel: Callable,
) -> None:
    """Channel close and settlement still work after the depracation switch is turned on"""
    controller = token_network.functions.controller().call()
    (A, B) = get_accounts(2)
    deposit = 100

    (vals_A, vals_B) = (
        ChannelValues(
            deposit=deposit,
            withdrawn=0,
            transferred=5,
            locked_amounts=LockedAmounts(claimable_locked=2,
                                         unclaimable_locked=4),
        ),
        ChannelValues(
            deposit=deposit,
            withdrawn=0,
            transferred=10,
            locked_amounts=LockedAmounts(claimable_locked=4,
                                         unclaimable_locked=6),
        ),
    )

    pre_balance_A = custom_token.functions.balanceOf(A).call()
    pre_balance_B = custom_token.functions.balanceOf(B).call()
    pre_balance_contract = custom_token.functions.balanceOf(
        token_network.address).call()

    channel_identifier = create_channel(A, B)[0]
    channel_deposit(channel_identifier, A, vals_A.deposit, B)
    channel_deposit(channel_identifier, B, vals_B.deposit, A)

    # Mock pending transfers data for A -> B
    pending_transfers_tree_A = get_pending_transfers_tree_with_generated_lists(
        web3,
        unlockable_amount=vals_A.locked_amounts.claimable_locked,
        expired_amount=vals_A.locked_amounts.unclaimable_locked,
    )
    vals_A.locksroot = pending_transfers_tree_A.hash_of_packed_transfers
    # Reveal A's secrets.
    reveal_secrets(A, pending_transfers_tree_A.unlockable)

    # Mock pending transfers data for B -> A
    pending_transfers_tree_B = get_pending_transfers_tree_with_generated_lists(
        web3,
        unlockable_amount=vals_B.locked_amounts.claimable_locked,
        expired_amount=vals_B.locked_amounts.unclaimable_locked,
    )
    vals_B.locksroot = pending_transfers_tree_B.hash_of_packed_transfers
    # Reveal B's secrets
    reveal_secrets(B, pending_transfers_tree_B.unlockable)

    # Set the deprecation switch to true
    call_and_transact(token_network.functions.deprecate(),
                      {"from": controller})
    assert token_network.functions.safety_deprecation_switch().call() is True

    # We need to make sure we can still close, settle & unlock the channels
    close_and_update_channel(channel_identifier, A, vals_A, B, vals_B)
    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)

    call_settle(token_network, channel_identifier, A, vals_A, B, vals_B)

    # Unlock B's pending transfers that were sent to A
    call_and_transact(
        token_network.functions.unlock(
            channel_identifier, A, B,
            pending_transfers_tree_B.packed_transfers))

    # Unlock A's pending transfers that were sent to B
    call_and_transact(
        token_network.functions.unlock(
            channel_identifier, B, A,
            pending_transfers_tree_A.packed_transfers))

    assert custom_token.functions.balanceOf(A).call() == pre_balance_A + 107
    assert custom_token.functions.balanceOf(B).call() == pre_balance_B + 93
    assert custom_token.functions.balanceOf(
        token_network.address).call() == pre_balance_contract
def test_update_replay_reopened_channel(
    web3: Web3,
    get_accounts: Callable,
    token_network: Contract,
    create_channel: Callable,
    channel_deposit: Callable,
    create_balance_proof: Callable,
    create_balance_proof_countersignature: Callable,
    create_close_signature_for_no_balance_proof: Callable,
) -> None:
    """updateNonClosingBalanceProof() should refuse a balance proof with a stale channel id"""
    (A, B) = get_accounts(2)
    nonce_B = 5
    values_A = ChannelValues(deposit=10, transferred=0)
    values_B = ChannelValues(deposit=20, transferred=15)

    channel_identifier1 = create_channel(A, B)[0]
    channel_deposit(channel_identifier1, B, values_B.deposit, A)
    balance_proof_B = create_balance_proof(
        channel_identifier1,
        B,
        values_B.transferred,
        values_B.locked_amounts.locked,
        nonce_B,
        values_B.locksroot,
    )
    balance_proof_update_signature_A = create_balance_proof_countersignature(
        participant=A,
        channel_identifier=channel_identifier1,
        msg_type=MessageTypeId.BALANCE_PROOF_UPDATE,
        **balance_proof_B._asdict(),
    )

    closing_sig = create_close_signature_for_no_balance_proof(
        B, channel_identifier1)
    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier1,
            A,
            B,
            EMPTY_BALANCE_HASH,
            0,
            EMPTY_ADDITIONAL_HASH,
            EMPTY_SIGNATURE,
            closing_sig,
        ),
        {"from": B},
    )

    call_and_transact(
        token_network.functions.updateNonClosingBalanceProof(
            channel_identifier1,
            B,
            A,
            *balance_proof_B._asdict().values(),
            balance_proof_update_signature_A,
        ),
        {"from": A},
    )

    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)
    call_and_transact(
        token_network.functions.settleChannel(
            channel_identifier1,
            A,
            values_A.transferred,
            values_A.locked_amounts.locked,
            values_A.locksroot,
            B,
            values_B.transferred,
            values_B.locked_amounts.locked,
            values_B.locksroot,
        ),
        {"from": A},
    )

    # Make sure we cannot update balance proofs after settleChannel is called
    with pytest.raises(TransactionFailed,
                       match="TN/update: channel id mismatch"):
        token_network.functions.updateNonClosingBalanceProof(
            channel_identifier1,
            B,
            A,
            *balance_proof_B._asdict().values(),
            balance_proof_update_signature_A,
        ).call({"from": A})

    # Reopen the channel and make sure we cannot use the old balance proof
    channel_identifier2 = create_channel(A, B)[0]
    channel_deposit(channel_identifier2, B, values_B.deposit, A)
    closing_sig = create_close_signature_for_no_balance_proof(
        B, channel_identifier2)
    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier2,
            A,
            B,
            EMPTY_BALANCE_HASH,
            0,
            EMPTY_ADDITIONAL_HASH,
            EMPTY_SIGNATURE,
            closing_sig,
        ),
        {"from": B},
    )

    assert channel_identifier1 != channel_identifier2
    with pytest.raises(TransactionFailed,
                       match="TN/update: invalid non-closing sig"):
        token_network.functions.updateNonClosingBalanceProof(
            channel_identifier2,
            B,
            A,
            *balance_proof_B._asdict().values(),
            balance_proof_update_signature_A,
        ).call({"from": A})

    # Correct channel_identifier must work
    balance_proof_B2 = create_balance_proof(
        channel_identifier2,
        B,
        values_B.transferred,
        values_B.locked_amounts.locked,
        nonce_B,
        values_B.locksroot,
    )
    balance_proof_update_signature_A2 = create_balance_proof_countersignature(
        participant=A,
        channel_identifier=channel_identifier2,
        msg_type=MessageTypeId.BALANCE_PROOF_UPDATE,
        **balance_proof_B2._asdict(),
    )

    call_and_transact(
        token_network.functions.updateNonClosingBalanceProof(
            channel_identifier2,
            B,
            A,
            *balance_proof_B2._asdict().values(),
            balance_proof_update_signature_A2,
        ),
        {"from": A},
    )
def test_settle_wrong_balance_hash(
    web3: Web3,
    get_accounts: Callable,
    token_network: Contract,
    create_channel_and_deposit: Callable,
    close_and_update_channel: Callable,
    reveal_secrets: Callable,
) -> None:
    """Calling settleChannel() with various wrong arguments and see failures"""
    (A, B) = get_accounts(2)
    vals_A = ChannelValues(
        deposit=35,
        withdrawn=0,
        transferred=5,
        locked_amounts=LockedAmounts(claimable_locked=10,
                                     unclaimable_locked=2),
    )
    vals_B = ChannelValues(
        deposit=40,
        withdrawn=0,
        transferred=15,
        locked_amounts=LockedAmounts(claimable_locked=5, unclaimable_locked=4),
    )
    channel_identifier = create_channel_and_deposit(A, B, vals_A.deposit,
                                                    vals_B.deposit)

    # Mock pending transfers data for A -> B
    pending_transfers_tree_A = get_pending_transfers_tree_with_generated_lists(
        web3,
        unlockable_amount=vals_A.locked_amounts.claimable_locked,
        expired_amount=vals_A.locked_amounts.unclaimable_locked,
    )
    vals_A.locksroot = pending_transfers_tree_A.hash_of_packed_transfers
    # Reveal A's secrets.
    reveal_secrets(A, pending_transfers_tree_A.unlockable)

    # Mock pending transfers data for B -> A
    pending_transfers_tree_B = get_pending_transfers_tree_with_generated_lists(
        web3,
        unlockable_amount=vals_B.locked_amounts.claimable_locked,
        expired_amount=vals_B.locked_amounts.unclaimable_locked,
    )
    vals_B.locksroot = pending_transfers_tree_B.hash_of_packed_transfers
    # Reveal B's secrets
    reveal_secrets(B, pending_transfers_tree_B.unlockable)

    close_and_update_channel(channel_identifier, A, vals_A, B, vals_B)

    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)

    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, B, vals_A, A, vals_B)

    vals_A_fail = deepcopy(vals_A)
    vals_A_fail.transferred += 1
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A_fail, B,
                    vals_B)

    vals_A_fail.transferred = 0
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A_fail, B,
                    vals_B)

    vals_A_fail.transferred = UINT256_MAX
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, B, vals_B, A,
                    vals_A_fail)

    vals_A_fail = deepcopy(vals_A)
    vals_A_fail.locked_amounts.claimable_locked += 1
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A_fail, B,
                    vals_B)

    vals_A_fail.locked_amounts.claimable_locked = 0
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A_fail, B,
                    vals_B)

    vals_A_fail.locked_amounts.unclaimable_locked = 0
    vals_A_fail.locked_amounts.claimable_locked = UINT256_MAX
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, B, vals_B, A,
                    vals_A_fail)

    vals_A_fail = deepcopy(vals_A)
    vals_A_fail.locksroot = LOCKSROOT_OF_NO_LOCKS
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A_fail, B,
                    vals_B)

    vals_A_fail.locksroot = fake_bytes(32, "01")
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A_fail, B,
                    vals_B)

    vals_B_fail = deepcopy(vals_B)
    vals_B_fail.transferred += 1
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A, B,
                    vals_B_fail)

    vals_B_fail.transferred = 0
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, B, vals_B_fail, A,
                    vals_A)

    vals_B_fail.transferred = UINT256_MAX
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A, B,
                    vals_B_fail)

    vals_B_fail = deepcopy(vals_B)
    vals_B_fail.locked_amounts.claimable_locked += 1
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A, B,
                    vals_B_fail)

    vals_B_fail.locked_amounts.claimable_locked = 0
    with pytest.raises(AssertionError):
        call_settle(token_network, channel_identifier, B, vals_B_fail, A,
                    vals_A)

    vals_B_fail.locked_amounts.unclaimable_locked = 0
    vals_B_fail.locked_amounts.claimable_locked = UINT256_MAX
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A, B,
                    vals_B_fail)

    vals_B_fail = deepcopy(vals_B)
    vals_B_fail.locksroot = LOCKSROOT_OF_NO_LOCKS
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A, B,
                    vals_B_fail)

    vals_B_fail.locksroot = fake_bytes(32, "01")
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A, B,
                    vals_B_fail)

    # Channel is settled
    call_settle(token_network, channel_identifier, A, vals_A, B, vals_B)
    def f(
        participants: Tuple,
        channel_values: Tuple,
        expected_final_balance_A0: int,
        expected_final_balance_B0: int,
    ) -> None:
        (A, B) = participants
        (vals_A, vals_B, balance_proof_type) = channel_values
        assert were_balance_proofs_valid(vals_A, vals_B)

        # Start channel lifecycle
        channel_identifier = create_channel_and_deposit(
            A, B, vals_A.deposit, vals_B.deposit)
        withdraw_channel(channel_identifier, A, vals_A.withdrawn, UINT256_MAX,
                         B)
        withdraw_channel(channel_identifier, B, vals_B.withdrawn, UINT256_MAX,
                         A)

        # For the purpose of this test, it is not important when the secrets are revealed,
        # as long as the secrets connected to pending transfers that should be finalized,
        # are revealed before their expiration.

        # Mock pending transfers data for A -> B
        pending_transfers_tree_A = get_pending_transfers_tree_with_generated_lists(
            web3,
            unlockable_amount=vals_A.locked_amounts.claimable_locked,
            expired_amount=vals_A.locked_amounts.unclaimable_locked,
        )
        vals_A.locksroot = pending_transfers_tree_A.hash_of_packed_transfers
        # Reveal A's secrets.
        reveal_secrets(A, pending_transfers_tree_A.unlockable)

        # Mock pending transfers data for B -> A
        pending_transfers_tree_B = get_pending_transfers_tree_with_generated_lists(
            web3,
            unlockable_amount=vals_B.locked_amounts.claimable_locked,
            expired_amount=vals_B.locked_amounts.unclaimable_locked,
        )
        vals_B.locksroot = pending_transfers_tree_B.hash_of_packed_transfers
        # Reveal B's secrets
        reveal_secrets(B, pending_transfers_tree_B.unlockable)

        close_and_update_channel(channel_identifier, A, vals_A, B, vals_B)

        mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN)

        pre_balance_A = custom_token.functions.balanceOf(A).call()
        pre_balance_B = custom_token.functions.balanceOf(B).call()
        pre_balance_contract = custom_token.functions.balanceOf(
            token_network.address).call()

        call_settle(token_network, channel_identifier, A, vals_A, B, vals_B)

        # We do the balance & state tests here for each channel and also compare with
        # the expected settlement amounts
        settle_state_tests(
            channel_identifier,
            A,
            vals_A,
            B,
            vals_B,
            pre_balance_A,
            pre_balance_B,
            pre_balance_contract,
        )

        # We compute again the settlement amounts here to compare with the other channel
        # settlement test values, which should be equal

        # Calculate how much A and B should receive
        settlement_equivalent = get_settlement_amounts(vals_A, vals_B)

        # Calculate how much A and B receive according to onchain computation
        settlement_onchain_equivalent = get_onchain_settlement_amounts(
            vals_A, vals_B)

        assert (settlement_equivalent.participant1_balance ==
                settlement_onchain_equivalent.participant1_balance)
        assert (settlement_equivalent.participant2_balance ==
                settlement_onchain_equivalent.participant2_balance)
        assert (settlement_equivalent.participant1_locked ==
                settlement_onchain_equivalent.participant1_locked)
        assert (settlement_equivalent.participant2_locked ==
                settlement_onchain_equivalent.participant2_locked)

        assert (get_unlocked_amount(secret_registry_contract,
                                    pending_transfers_tree_B.packed_transfers)
                == vals_B.locked_amounts.claimable_locked)

        # A unlocks B's pending transfers
        info_B = token_network.functions.getChannelParticipantInfo(
            channel_identifier, B, A).call()
        assert (settlement_equivalent.participant2_locked == info_B[
            ParticipantInfoIndex.LOCKED_AMOUNT])

        if info_B[ParticipantInfoIndex.LOCKED_AMOUNT] == 0:
            with pytest.raises(TransactionFailed):
                token_network.functions.unlock(
                    channel_identifier, A, B,
                    pending_transfers_tree_B.packed_transfers).call()
        else:
            call_and_transact(
                token_network.functions.unlock(
                    channel_identifier, A, B,
                    pending_transfers_tree_B.packed_transfers))

        # The locked amount should have been removed from contract storage
        info_B = token_network.functions.getChannelParticipantInfo(
            channel_identifier, B, A).call()
        assert info_B[ParticipantInfoIndex.LOCKED_AMOUNT] == 0
        assert info_B[ParticipantInfoIndex.LOCKSROOT] == NONEXISTENT_LOCKSROOT

        # B unlocks A's pending transfers
        info_A = token_network.functions.getChannelParticipantInfo(
            channel_identifier, A, B).call()
        assert (settlement_equivalent.participant1_locked == info_A[
            ParticipantInfoIndex.LOCKED_AMOUNT])

        if info_A[ParticipantInfoIndex.LOCKED_AMOUNT] == 0:
            with pytest.raises(TransactionFailed):
                token_network.functions.unlock(
                    channel_identifier, B, A,
                    pending_transfers_tree_A.packed_transfers).call()
        else:
            call_and_transact(
                token_network.functions.unlock(
                    channel_identifier, B, A,
                    pending_transfers_tree_A.packed_transfers))

        # The locked amount should have been removed from contract storage
        info_A = token_network.functions.getChannelParticipantInfo(
            channel_identifier, A, B).call()
        assert info_A[ParticipantInfoIndex.LOCKED_AMOUNT] == 0
        assert info_A[ParticipantInfoIndex.LOCKSROOT] == NONEXISTENT_LOCKSROOT

        # Do the post settlement and unlock tests for valid balance proofs
        balance_A = custom_token.functions.balanceOf(A).call()
        balance_B = custom_token.functions.balanceOf(B).call()

        # We MUST ensure balance correctness for valid last balance proofs
        if balance_proof_type == "valid":
            # Calculate how much A and B should receive after the channel is settled and
            # unlock is called by both.
            (
                expected_final_balance_A,
                expected_final_balance_B,
            ) = get_expected_after_settlement_unlock_amounts(vals_A, vals_B)
            expected_balance_A = pre_balance_A + expected_final_balance_A
            expected_balance_B = pre_balance_B + expected_final_balance_B

            assert balance_A == expected_balance_A
            assert balance_B <= expected_balance_B

        # For balance proofs where one of them is old, we need to compare with the expected
        # final balances for the valid last balance proofs
        expected_balance_A = pre_balance_A + expected_final_balance_A0
        expected_balance_B = pre_balance_B + expected_final_balance_B0

        # Tests for when B has submitted an old balance proof for A
        # A must not receive less tokens than expected with a valid last balance proof
        # B must not receive more tokens than expected with a valid last balance proof
        if balance_proof_type == "old_last":
            assert balance_A >= expected_balance_A
            assert balance_B <= expected_balance_B

        # Tests for when A has submitted an old balance proof for B
        # A must not receive more tokens than expected with a valid last balance proof
        # B must not receive less tokens than expected with a valid last balance proof
        if balance_proof_type == "last_old":
            assert balance_A <= expected_balance_A
            assert balance_B >= expected_balance_B

        # Regardless of the tokens received by the two participants, we must make sure tokens
        # are not stolen from the other channels. And we must make sure tokens are not locked in
        # the contract after the entire channel cycle is finalized.
        final_contract_balance = custom_token.functions.balanceOf(
            token_network.address).call()
        assert final_contract_balance == pre_balance_contract - get_total_available_deposit(
            vals_A, vals_B)
        assert custom_token.functions.balanceOf(
            token_network.address).call() == (
                pre_balance_contract -
                (expected_final_balance_A0 + expected_final_balance_B0))
def test_settlement_with_unauthorized_token_transfer(
    web3: Web3,
    get_accounts: Callable,
    custom_token: Contract,
    token_network: Contract,
    assign_tokens: Callable,
    create_channel_and_deposit: Callable,
    withdraw_channel: Callable,
    close_and_update_channel: Callable,
) -> None:
    """A participant transfers some tokens to the contract and so loses them"""
    externally_transferred_amount = 5
    (A, B) = get_accounts(2)
    (vals_A, vals_B) = (
        ChannelValues(deposit=35, withdrawn=10, transferred=0),
        ChannelValues(deposit=40, withdrawn=10, transferred=0),
    )
    vals_A.locksroot = fake_bytes(32, "02")
    vals_B.locksroot = fake_bytes(32, "03")

    channel_identifier = create_channel_and_deposit(A, B, vals_A.deposit,
                                                    vals_B.deposit)

    withdraw_channel(channel_identifier, A, vals_A.withdrawn, UINT256_MAX, B)
    withdraw_channel(channel_identifier, B, vals_B.withdrawn, UINT256_MAX, A)

    close_and_update_channel(channel_identifier, A, vals_A, B, vals_B)

    # Assign additional tokens to A
    assign_tokens(A, externally_transferred_amount)
    assert custom_token.functions.balanceOf(
        A).call() >= externally_transferred_amount

    # Fetch onchain balances after settlement
    pre_balance_A = custom_token.functions.balanceOf(A).call()
    pre_balance_B = custom_token.functions.balanceOf(B).call()
    pre_balance_contract = custom_token.functions.balanceOf(
        token_network.address).call()

    # A does a transfer to the token_network without appropriate function call - tokens are lost
    call_and_transact(
        custom_token.functions.transfer(token_network.address,
                                        externally_transferred_amount),
        {"from": A},
    )
    assert custom_token.functions.balanceOf(
        token_network.address).call() == (pre_balance_contract +
                                          externally_transferred_amount)

    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)

    # Compute expected settlement amounts
    settlement = get_settlement_amounts(vals_A, vals_B)

    # Channel is settled
    call_settle(token_network, channel_identifier, A, vals_A, B, vals_B)

    # Fetch onchain balances after settlement
    post_balance_A = custom_token.functions.balanceOf(A).call()
    post_balance_B = custom_token.functions.balanceOf(B).call()
    post_balance_contract = custom_token.functions.balanceOf(
        token_network.address).call()

    # A has lost the externally_transferred_amount
    assert (pre_balance_A + settlement.participant1_balance -
            externally_transferred_amount) == post_balance_A

    # B's settlement works correctly
    assert pre_balance_B + settlement.participant2_balance == post_balance_B

    # The externally_transferred_amount stays in the contract
    assert (pre_balance_contract - settlement.participant1_balance -
            settlement.participant2_balance +
            externally_transferred_amount) == post_balance_contract
def test_close_settled_channel_fail(
    web3: Web3,
    token_network: Contract,
    create_channel: Callable,
    channel_deposit: Callable,
    get_accounts: Callable,
    create_close_signature_for_no_balance_proof: Callable,
) -> None:
    """Test getChannelInfo and closeChannel on an already settled channel"""
    (A, B) = get_accounts(2)
    channel_identifier = create_channel(A, B, TEST_SETTLE_TIMEOUT_MIN)[0]
    channel_deposit(channel_identifier, A, 5, B)

    (_,
     state) = token_network.functions.getChannelInfo(channel_identifier, A,
                                                     B).call()
    assert state == ChannelState.OPENED
    closing_sig = create_close_signature_for_no_balance_proof(
        A, channel_identifier)

    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier=channel_identifier,
            non_closing_participant=B,
            closing_participant=A,
            balance_hash=EMPTY_BALANCE_HASH,
            nonce=0,
            additional_hash=EMPTY_ADDITIONAL_HASH,
            non_closing_signature=EMPTY_SIGNATURE,
            closing_signature=closing_sig,
        ),
        {"from": A},
    )
    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)
    call_and_transact(
        token_network.functions.settleChannel(
            channel_identifier=channel_identifier,
            participant1=A,
            participant1_transferred_amount=0,
            participant1_locked_amount=0,
            participant1_locksroot=NONEXISTENT_LOCKSROOT,
            participant2=B,
            participant2_transferred_amount=0,
            participant2_locked_amount=0,
            participant2_locksroot=NONEXISTENT_LOCKSROOT,
        ),
        {"from": A},
    )

    (settle_block_number,
     state) = token_network.functions.getChannelInfo(channel_identifier, A,
                                                     B).call()
    assert state == ChannelState.REMOVED
    assert settle_block_number == 0

    with pytest.raises(TransactionFailed, match=" TN: channel not open"):
        token_network.functions.closeChannel(
            channel_identifier=channel_identifier,
            non_closing_participant=B,
            closing_participant=A,
            balance_hash=EMPTY_BALANCE_HASH,
            nonce=0,
            additional_hash=EMPTY_ADDITIONAL_HASH,
            non_closing_signature=EMPTY_SIGNATURE,
            closing_signature=closing_sig,
        ).call({"from": A})
def test_deposit_wrong_state_fail(
    web3: Web3,
    get_accounts: Callable,
    token_network: Contract,
    create_channel: Callable,
    assign_tokens: Callable,
    create_close_signature_for_no_balance_proof: Callable,
) -> None:
    """ setTotalDeposit() fails on Closed or Settled channels. """
    (A, B) = get_accounts(2)
    vals_A = ChannelValues(deposit=2, transferred=0)
    vals_B = ChannelValues(deposit=2, transferred=0)
    channel_identifier = create_channel(A, B, TEST_SETTLE_TIMEOUT_MIN)[0]
    assign_tokens(A, vals_A.deposit)
    assign_tokens(B, vals_B.deposit)
    call_and_transact(
        token_network.functions.setTotalDeposit(channel_identifier, A,
                                                vals_A.deposit, B),
        {"from": A},
    )
    call_and_transact(
        token_network.functions.setTotalDeposit(channel_identifier, B,
                                                vals_B.deposit, A),
        {"from": B},
    )
    assert (
        vals_A.deposit == token_network.functions.getChannelParticipantInfo(
            channel_identifier, A, B).call()[0])
    assert (
        vals_B.deposit == token_network.functions.getChannelParticipantInfo(
            channel_identifier, B, A).call()[0])

    closing_sig = create_close_signature_for_no_balance_proof(
        A, channel_identifier)

    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier=channel_identifier,
            non_closing_participant=B,
            closing_participant=A,
            balance_hash=EMPTY_BALANCE_HASH,
            nonce=0,
            additional_hash=EMPTY_ADDITIONAL_HASH,
            non_closing_signature=EMPTY_SIGNATURE,
            closing_signature=closing_sig,
        ),
        {"from": A},
    )

    assign_tokens(A, 10)
    assign_tokens(B, 10)
    vals_A.deposit += 5
    vals_B.deposit += 5
    with pytest.raises(TransactionFailed):
        token_network.functions.setTotalDeposit(channel_identifier, A,
                                                vals_A.deposit,
                                                B).call({"from": A})
    with pytest.raises(TransactionFailed):
        token_network.functions.setTotalDeposit(channel_identifier, B,
                                                vals_B.deposit,
                                                A).call({"from": B})

    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)
    call_settle(token_network, channel_identifier, A, vals_A, B, vals_B)
    with pytest.raises(TransactionFailed):
        token_network.functions.setTotalDeposit(channel_identifier, A,
                                                vals_A.deposit,
                                                B).call({"from": A})
    with pytest.raises(TransactionFailed):
        token_network.functions.setTotalDeposit(channel_identifier, B,
                                                vals_B.deposit,
                                                A).call({"from": B})
def test_settle_timeout_inrange(
    token_network: Contract,
    get_accounts: Callable,
    web3: Web3,
    create_close_signature_for_no_balance_proof: Callable,
) -> None:
    """The TokenNetwork constructor must enforce that settle timeout is in
    the valid range.

    Also asserts that the constants.py and the netting channel contract values
    are synched.
    """
    (A, B) = get_accounts(2)

    small_settle_timeout = TEST_SETTLE_TIMEOUT_MIN - 1
    large_settle_timeout = TEST_SETTLE_TIMEOUT_MAX + 1

    with pytest.raises(TransactionFailed):
        token_network.functions.openChannel(A, B, small_settle_timeout).call()

    with pytest.raises(TransactionFailed):
        token_network.functions.openChannel(A, B, large_settle_timeout).call()

    call_and_transact(token_network.functions.openChannel(A, B, TEST_SETTLE_TIMEOUT_MIN))
    channel_identifier = token_network.functions.getChannelIdentifier(A, B).call()
    (settle_block_number, _) = token_network.functions.getChannelInfo(
        channel_identifier, A, B
    ).call()

    assert settle_block_number == TEST_SETTLE_TIMEOUT_MIN

    closing_sig = create_close_signature_for_no_balance_proof(A, channel_identifier)
    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier=channel_identifier,
            non_closing_participant=B,
            closing_participant=A,
            balance_hash=fake_bytes(32),
            nonce=0,
            additional_hash=fake_bytes(32),
            non_closing_signature=fake_bytes(65),
            closing_signature=closing_sig,
        ),
        {"from": A},
    )
    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)
    call_and_transact(
        token_network.functions.settleChannel(
            channel_identifier,
            A,
            0,
            0,
            LOCKSROOT_OF_NO_LOCKS,
            B,
            0,
            0,
            LOCKSROOT_OF_NO_LOCKS,
        ),
        {"from": A},
    )
    call_and_transact(token_network.functions.openChannel(A, B, TEST_SETTLE_TIMEOUT_MAX))
    channel_identifier = token_network.functions.getChannelIdentifier(A, B).call()
    (settle_block_number, _) = token_network.functions.getChannelInfo(
        channel_identifier, A, B
    ).call()

    assert settle_block_number == TEST_SETTLE_TIMEOUT_MAX
def test_withdraw_wrong_state(
    web3: Web3,
    token_network: Contract,
    create_channel_and_deposit: Callable,
    get_accounts: Callable,
    withdraw_channel: Callable,
    create_close_signature_for_no_balance_proof: Callable,
) -> None:
    """setTotalWithdraw() should fail on a closed or settled channel"""
    (A, B) = get_accounts(2)
    withdraw_A = 1

    assert token_network.functions.getChannelIdentifier(A, B).call() == 0

    channel_identifier = create_channel_and_deposit(A, B, 10, 14,
                                                    TEST_SETTLE_TIMEOUT_MIN)
    (_,
     state) = token_network.functions.getChannelInfo(channel_identifier, A,
                                                     B).call()
    assert state == ChannelState.OPENED

    # Channel is open, withdraw must work
    withdraw_channel(channel_identifier, A, withdraw_A, UINT256_MAX, B)

    closing_sig = create_close_signature_for_no_balance_proof(
        A, channel_identifier)
    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier=channel_identifier,
            non_closing_participant=B,
            closing_participant=A,
            balance_hash=EMPTY_BALANCE_HASH,
            nonce=0,
            additional_hash=EMPTY_ADDITIONAL_HASH,
            non_closing_signature=EMPTY_SIGNATURE,
            closing_signature=closing_sig,
        ),
        {"from": A},
    )
    (_,
     state) = token_network.functions.getChannelInfo(channel_identifier, A,
                                                     B).call()
    assert state == ChannelState.CLOSED

    with pytest.raises(TransactionFailed):
        withdraw_channel(channel_identifier, A, withdraw_A, UINT256_MAX, B)

    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)
    call_and_transact(
        token_network.functions.settleChannel(
            channel_identifier,
            A,
            0,
            0,
            LOCKSROOT_OF_NO_LOCKS,
            B,
            0,
            0,
            LOCKSROOT_OF_NO_LOCKS,
        ),
        {"from": A},
    )
    (_,
     state) = token_network.functions.getChannelInfo(channel_identifier, A,
                                                     B).call()
    assert state == ChannelState.REMOVED

    with pytest.raises(TransactionFailed):
        withdraw_channel(channel_identifier, A, withdraw_A, UINT256_MAX, B)
def test_settle_wrong_state_fail(
    web3: Web3,
    get_accounts: Callable,
    token_network: Contract,
    create_channel_and_deposit: Callable,
    get_block: Callable,
    create_close_signature_for_no_balance_proof: Callable,
) -> None:
    """settleChannel() fails on OPENED state and on CLOSED state before the settlement block"""
    (A, B) = get_accounts(2)
    vals_A = ChannelValues(deposit=35)
    vals_B = ChannelValues(deposit=40)
    channel_identifier = create_channel_and_deposit(A, B, vals_A.deposit,
                                                    vals_B.deposit)

    (settle_timeout,
     state) = token_network.functions.getChannelInfo(channel_identifier, A,
                                                     B).call()
    assert state == ChannelState.OPENED
    assert settle_timeout == TEST_SETTLE_TIMEOUT_MIN

    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A, B, vals_B)

    closing_sig = create_close_signature_for_no_balance_proof(
        A, channel_identifier)
    txn_hash = call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier,
            B,
            A,
            EMPTY_BALANCE_HASH,
            0,
            EMPTY_ADDITIONAL_HASH,
            EMPTY_SIGNATURE,
            closing_sig,
        ),
        {"from": A},
    )

    (settle_block_number,
     state) = token_network.functions.getChannelInfo(channel_identifier, A,
                                                     B).call()
    assert state == ChannelState.CLOSED
    assert settle_block_number == TEST_SETTLE_TIMEOUT_MIN + get_block(txn_hash)
    assert web3.eth.block_number < settle_block_number

    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A, B, vals_B)

    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)
    assert web3.eth.block_number > settle_block_number

    # Channel is settled
    call_settle(token_network, channel_identifier, A, vals_A, B, vals_B)

    (settle_block_number,
     state) = token_network.functions.getChannelInfo(channel_identifier, A,
                                                     B).call()
    assert state == ChannelState.REMOVED
    assert settle_block_number == 0
Esempio n. 26
0
def test_claimReward_with_settle_call(
    token_network: Contract,
    monitoring_service_external: Contract,
    user_deposit_contract: Contract,
    event_handler: Callable,
    monitor_data: Dict,
    ms_address: HexAddress,
    web3: Web3,
    with_settle: bool,
) -> None:
    A, B = monitor_data["participants"]
    channel_identifier = monitor_data["channel_identifier"]

    # wait until MS is allowed to monitor
    mine_blocks(web3, monitor_data["first_allowed"] - web3.eth.block_number)

    # MS updates closed channel on behalf of B
    txn_hash = call_and_transact(
        monitoring_service_external.functions.monitor(
            A,
            B,
            *monitor_data["balance_proof_B"]._asdict().values(),
            monitor_data["non_closing_signature"],
            REWARD_AMOUNT,
            token_network.address,
            monitor_data["reward_proof_signature"],
        ),
        {"from": ms_address},
    )

    # claiming before settlement timeout must fail
    with pytest.raises(TransactionFailed, match="channel not settled yet"):
        monitoring_service_external.functions.claimReward(
            channel_identifier, token_network.address, A, B
        ).call({"from": ms_address})

    # Settle channel after settle_timeout elapsed
    mine_blocks(web3, 4)
    if with_settle:
        call_and_transact(
            token_network.functions.settleChannel(
                channel_identifier,
                B,  # participant_B
                10,  # participant_B_transferred_amount
                0,  # participant_B_locked_amount
                LOCKSROOT_OF_NO_LOCKS,  # participant_B_locksroot
                A,  # participant_A
                20,  # participant_A_transferred_amount
                0,  # participant_A_locked_amount
                LOCKSROOT_OF_NO_LOCKS,  # participant_A_locksroot
            )
        )

    # Claim reward for MS
    call_and_transact(
        monitoring_service_external.functions.claimReward(
            channel_identifier, token_network.address, A, B
        ),
        {"from": ms_address},
    )

    # Check REWARD_CLAIMED event
    reward_identifier = Web3.keccak(
        encode_single("uint256", channel_identifier) + Web3.toBytes(hexstr=token_network.address)
    )
    ms_ev_handler = event_handler(monitoring_service_external)
    ms_ev_handler.assert_event(
        txn_hash,
        MonitoringServiceEvent.REWARD_CLAIMED,
        dict(
            ms_address=ms_address,
            amount=REWARD_AMOUNT,
            reward_identifier=reward_identifier,
        ),
    )

    # Check that MS balance has increased by claiming the reward
    ms_balance_after_reward = user_deposit_contract.functions.balances(ms_address).call()
    assert ms_balance_after_reward == REWARD_AMOUNT
def test_settle_channel_event(
    web3: Web3,
    get_accounts: Callable,
    token_network: Contract,
    create_channel: Callable,
    channel_deposit: Callable,
    create_balance_proof: Callable,
    create_balance_proof_countersignature: Callable,
    event_handler: Callable,
) -> None:
    """A successful settleChannel() call causes a SETTLED event"""
    ev_handler = event_handler(token_network)
    (A, B) = get_accounts(2)
    deposit_A = 10
    settle_timeout = TEST_SETTLE_TIMEOUT_MIN

    channel_identifier = create_channel(A, B)[0]
    channel_deposit(channel_identifier, A, deposit_A, B)

    balance_proof_A = create_balance_proof(channel_identifier, A, 10, 0, 1,
                                           LOCKSROOT_OF_NO_LOCKS)
    balance_proof_B = create_balance_proof(channel_identifier, B, 5, 0, 3,
                                           LOCKSROOT_OF_NO_LOCKS)
    balance_proof_update_signature_B = create_balance_proof_countersignature(
        participant=B,
        channel_identifier=channel_identifier,
        msg_type=MessageTypeId.BALANCE_PROOF_UPDATE,
        **balance_proof_A._asdict(),
    )
    close_sig_A = create_balance_proof_countersignature(
        participant=A,
        channel_identifier=channel_identifier,
        msg_type=MessageTypeId.BALANCE_PROOF,
        **balance_proof_B._asdict(),
    )

    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier, B, A,
            *balance_proof_B._asdict().values(), close_sig_A),
        {"from": A},
    )
    call_and_transact(
        token_network.functions.updateNonClosingBalanceProof(
            channel_identifier,
            A,
            B,
            *balance_proof_A._asdict().values(),
            balance_proof_update_signature_B,
        ),
        {"from": B},
    )

    mine_blocks(web3, settle_timeout + 1)
    txn_hash = call_and_transact(
        token_network.functions.settleChannel(
            channel_identifier=channel_identifier,
            participant1=B,
            participant1_transferred_amount=5,
            participant1_locked_amount=0,
            participant1_locksroot=LOCKSROOT_OF_NO_LOCKS,
            participant2=A,
            participant2_transferred_amount=10,
            participant2_locked_amount=0,
            participant2_locksroot=LOCKSROOT_OF_NO_LOCKS,
        ),
        {"from": A},
    )

    ev_handler.add(txn_hash, ChannelEvent.SETTLED,
                   check_channel_settled(channel_identifier, 5, 5))
    ev_handler.check()
Esempio n. 28
0
def test_monitor(
    token_network: Contract,
    monitoring_service_external: Contract,
    monitor_data: Dict,
    ms_address: HexAddress,
    event_handler: Callable,
    web3: Web3,
) -> None:
    A, B = monitor_data["participants"]

    # UpdateNonClosingBalanceProof is tested speparately, so we assume that all
    # parameters passed to it are handled correctly.

    # changing reward amount must lead to a failure during reward signature check
    with pytest.raises(TransactionFailed, match="Reward proof with wrong non_closing_participant"):
        txn_hash = monitoring_service_external.functions.monitor(
            A,
            B,
            *monitor_data["balance_proof_B"]._asdict().values(),
            monitor_data["non_closing_signature"],
            REWARD_AMOUNT + 1,
            token_network.address,
            monitor_data["reward_proof_signature"],
        ).call({"from": ms_address})

    # monitoring too early must fail
    with pytest.raises(TransactionFailed, match="not allowed to monitor"):
        assert web3.eth.block_number < monitor_data["first_allowed"]
        txn_hash = call_and_transact(
            monitoring_service_external.functions.monitor(
                A,
                B,
                *monitor_data["balance_proof_B"]._asdict().values(),
                monitor_data["non_closing_signature"],
                REWARD_AMOUNT,
                token_network.address,
                monitor_data["reward_proof_signature"],
            ),
            {"from": ms_address},
        )

    # wait until MS is allowed to monitor
    mine_blocks(web3, monitor_data["first_allowed"] - web3.eth.block_number)

    # successful monitor call
    txn_hash = call_and_transact(
        monitoring_service_external.functions.monitor(
            A,
            B,
            *monitor_data["balance_proof_B"]._asdict().values(),
            monitor_data["non_closing_signature"],
            REWARD_AMOUNT,
            token_network.address,
            monitor_data["reward_proof_signature"],
        ),
        {"from": ms_address},
    )

    # NEW_BALANCE_PROOF_RECEIVED must get emitted
    ms_ev_handler = event_handler(monitoring_service_external)
    ms_ev_handler.assert_event(
        txn_hash,
        MonitoringServiceEvent.NEW_BALANCE_PROOF_RECEIVED,
        dict(
            token_network_address=token_network.address,
            channel_identifier=monitor_data["channel_identifier"],
            reward_amount=REWARD_AMOUNT,
            nonce=monitor_data["balance_proof_B"].nonce,
            ms_address=ms_address,
            raiden_node_address=B,
        ),
    )
def test_close_replay_reopened_channel(
    web3: Web3,
    get_accounts: Callable,
    token_network: Contract,
    create_channel: Callable,
    channel_deposit: Callable,
    create_balance_proof: Callable,
    create_balance_proof_countersignature: Callable,
) -> None:
    """The same balance proof cannot close another channel between the same participants"""
    (A, B) = get_accounts(2)
    nonce = 3
    values_A = ChannelValues(deposit=10, transferred=0)
    values_B = ChannelValues(deposit=20, transferred=15)
    channel_identifier1 = create_channel(A, B)[0]
    channel_deposit(channel_identifier1, B, values_B.deposit, A)

    balance_proof_B = create_balance_proof(
        channel_identifier1,
        B,
        values_B.transferred,
        values_B.locked_amounts.locked,
        nonce,
        values_B.locksroot,
    )
    closing_sig_A = create_balance_proof_countersignature(
        participant=A,
        channel_identifier=channel_identifier1,
        msg_type=MessageTypeId.BALANCE_PROOF,
        **balance_proof_B._asdict(),
    )
    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier1,
            B,
            A,
            *balance_proof_B._asdict().values(),
            closing_sig_A,
        ),
        {"from": A},
    )
    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)
    call_and_transact(
        token_network.functions.settleChannel(
            channel_identifier=channel_identifier1,
            participant1=A,
            participant1_transferred_amount=values_A.transferred,
            participant1_locked_amount=values_A.locked_amounts.locked,
            participant1_locksroot=values_A.locksroot,
            participant2=B,
            participant2_transferred_amount=values_B.transferred,
            participant2_locked_amount=values_B.locked_amounts.locked,
            participant2_locksroot=values_B.locksroot,
        ),
        {"from": A},
    )

    # Reopen the channel and make sure we cannot use the old balance proof
    channel_identifier2 = create_channel(A, B)[0]
    channel_deposit(channel_identifier2, B, values_B.deposit, A)

    assert channel_identifier1 != channel_identifier2
    with pytest.raises(TransactionFailed,
                       match="TN/close: invalid closing sig"):
        token_network.functions.closeChannel(
            channel_identifier2,
            B,
            A,
            *balance_proof_B._asdict().values(),
            closing_sig_A,
        ).call({"from": A})

    # Balance proof with correct channel_identifier must work
    balance_proof_B2 = create_balance_proof(
        channel_identifier2,
        B,
        values_B.transferred,
        values_B.locked_amounts.locked,
        nonce,
        values_B.locksroot,
    )
    closing_sig_A2 = create_balance_proof_countersignature(
        participant=A,
        channel_identifier=channel_identifier2,
        msg_type=MessageTypeId.BALANCE_PROOF,
        **balance_proof_B2._asdict(),
    )
    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier2,
            B,
            A,
            *balance_proof_B2._asdict().values(),
            closing_sig_A2,
        ),
        {"from": A},
    )
def test_withdraw_replay_reopened_channel(
    web3: Web3,
    token_network: Contract,
    create_channel: Callable,
    channel_deposit: Callable,
    get_accounts: Callable,
    create_withdraw_signatures: Callable,
    create_close_signature_for_no_balance_proof: Callable,
) -> None:
    (A, B) = get_accounts(2)
    deposit_A = 20
    withdraw_A = 5

    channel_identifier1 = create_channel(A, B)[0]
    channel_deposit(channel_identifier1, A, deposit_A, B)
    (signature_A_for_A,
     signature_B_for_A) = create_withdraw_signatures([A, B],
                                                     channel_identifier1, A,
                                                     withdraw_A, UINT256_MAX)
    call_and_transact(
        token_network.functions.setTotalWithdraw(
            channel_identifier1,
            A,
            withdraw_A,
            UINT256_MAX,
            signature_A_for_A,
            signature_B_for_A,
        ),
        {"from": A},
    )

    closing_sig = create_close_signature_for_no_balance_proof(
        B, channel_identifier1)
    call_and_transact(
        token_network.functions.closeChannel(
            channel_identifier=channel_identifier1,
            non_closing_participant=A,
            closing_participant=B,
            balance_hash=EMPTY_BALANCE_HASH,
            nonce=0,
            additional_hash=EMPTY_ADDITIONAL_HASH,
            non_closing_signature=EMPTY_SIGNATURE,
            closing_signature=closing_sig,
        ),
        {"from": B},
    )
    mine_blocks(web3, TEST_SETTLE_TIMEOUT_MIN + 1)
    call_and_transact(
        token_network.functions.settleChannel(
            channel_identifier1,
            A,
            0,
            0,
            LOCKSROOT_OF_NO_LOCKS,
            B,
            0,
            0,
            LOCKSROOT_OF_NO_LOCKS,
        ),
        {"from": A},
    )

    # Reopen the channel and make sure we cannot use the old withdraw proof
    channel_identifier2 = create_channel(A, B)[0]
    channel_deposit(channel_identifier2, A, deposit_A, B)

    assert channel_identifier1 != channel_identifier2
    with pytest.raises(TransactionFailed):
        token_network.functions.setTotalWithdraw(
            channel_identifier2,
            A,
            withdraw_A,
            UINT256_MAX,
            signature_A_for_A,
            signature_B_for_A,
        ).call({"from": A})

    # Signed message with correct channel_identifier must work
    (signature_A_for_A2,
     signature_B_for_A2) = create_withdraw_signatures([A, B],
                                                      channel_identifier2, A,
                                                      withdraw_A, UINT256_MAX)
    call_and_transact(
        token_network.functions.setTotalWithdraw(
            channel_identifier2,
            A,
            withdraw_A,
            UINT256_MAX,
            signature_A_for_A2,
            signature_B_for_A2,
        ),
        {"from": A},
    )