示例#1
0
def test_merkle_root_1_item_unlockable(
        web3,
        get_accounts,
        token_network_test_utils,
        secret_registry_contract,
):
    A = get_accounts(1)[0]
    pending_transfers_tree = get_pending_transfers_tree(web3, [6])

    secret_registry_contract.functions.registerSecret(
        pending_transfers_tree.unlockable[0][TestLockIndex.SECRET],
    ).transact({'from': A})
    assert secret_registry_contract.functions.getSecretRevealBlockHeight(
        pending_transfers_tree.unlockable[0][TestLockIndex.SECRETHASH],
    ).call() == web3.eth.blockNumber

    (
        locksroot,
        unlocked_amount,
    ) = token_network_test_utils.functions.getMerkleRootAndUnlockedAmountPublic(
        pending_transfers_tree.packed_transfers,
    ).call()

    merkle_root = pending_transfers_tree.merkle_root
    assert locksroot == merkle_root
    assert unlocked_amount == 6
示例#2
0
def test_merkle_tree_length_fail(
        web3,
        get_accounts,
        token_network_test_utils,
        secret_registry_contract,
):
    network_utils = token_network_test_utils
    A = get_accounts(1)[0]
    pending_transfers_tree = get_pending_transfers_tree(web3, [2, 3, 6], [5])

    secret_registry_contract.functions.registerSecret(
        pending_transfers_tree.unlockable[0][TestLockIndex.SECRET],
    ).transact({'from': A})
    assert secret_registry_contract.functions.getSecretRevealBlockHeight(
        pending_transfers_tree.unlockable[0][TestLockIndex.SECRETHASH],
    ).call() == web3.eth.blockNumber

    packed = pending_transfers_tree.packed_transfers

    # packed length must be a multiple of 96
    with pytest.raises(TransactionFailed):
        network_utils.functions.getMerkleRootAndUnlockedAmountPublic(packed[0:-1]).call()
    # last merkle tree component only contains expiration + locked_amount
    with pytest.raises(TransactionFailed):
        network_utils.functions.getMerkleRootAndUnlockedAmountPublic(packed[0:-32]).call()
    # last merkle tree component only contains expiration
    with pytest.raises(TransactionFailed):
        network_utils.functions.getMerkleRootAndUnlockedAmountPublic(packed[0:-64]).call()

    assert len(packed) % 96 == 0
    network_utils.functions.getMerkleRootAndUnlockedAmountPublic(packed).call()
    network_utils.functions.getMerkleRootAndUnlockedAmountPublic(packed[0:-96]).call()
示例#3
0
def test_unlock_wrong_locksroot(
        web3,
        token_network,
        create_settled_channel,
        get_accounts,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    pending_transfers_tree_A = get_pending_transfers_tree(web3, [1, 3, 5], [], settle_timeout)
    pending_transfers_tree_A_fake = get_pending_transfers_tree(web3, [1, 3, 6], [], settle_timeout)

    channel_identifier = create_settled_channel(
        A,
        pending_transfers_tree_A.locked_amount,
        pending_transfers_tree_A.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )

    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            B,
            A,
            pending_transfers_tree_A_fake.packed_transfers,
        ).transact()

    # Fails for an empty merkle tree
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            B,
            A,
            b'',
        ).transact()

    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree_A.packed_transfers,
    ).transact()
示例#4
0
def test_channel_unlock_smaller_locked_amount(
        web3,
        token_network,
        custom_token,
        secret_registry_contract,
        create_settled_channel,
        get_accounts,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    # Mock pending transfers data
    pending_transfers_tree_A = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    reveal_secrets(A, pending_transfers_tree_A.unlockable)
    unlocked_amount = get_unlocked_amount(
        secret_registry_contract,
        pending_transfers_tree_A.packed_transfers,
    )

    # We settle the channel with a smaller locked amount than we will need for the
    # actual merkle tree of pending transfers
    channel_identifier = create_settled_channel(
        A,
        pending_transfers_tree_A.locked_amount - 1,
        pending_transfers_tree_A.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )

    pre_balance_A = custom_token.functions.balanceOf(A).call()
    pre_balance_B = custom_token.functions.balanceOf(B).call()
    balance_contract = custom_token.functions.balanceOf(token_network.address).call()
    assert balance_contract == pending_transfers_tree_A.locked_amount - 1

    # This should pass, even though the locked amount in storage is smaller.
    # B will receive less tokens.
    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree_A.packed_transfers,
    ).transact()

    balance_A = custom_token.functions.balanceOf(A).call()
    balance_B = custom_token.functions.balanceOf(B).call()
    balance_contract = custom_token.functions.balanceOf(token_network.address).call()
    assert balance_A == (
        pre_balance_A +
        pending_transfers_tree_A.locked_amount -
        unlocked_amount - 1
    )
    assert balance_B == pre_balance_B + unlocked_amount
    assert balance_contract == 0
示例#5
0
def test_channel_unlock_bigger_unlocked_amount(
        web3,
        token_network,
        custom_token,
        secret_registry_contract,
        create_settled_channel,
        get_accounts,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    # Mock pending transfers data
    pending_transfers_tree_A = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    reveal_secrets(A, pending_transfers_tree_A.unlockable)
    unlocked_amount = get_unlocked_amount(
        secret_registry_contract,
        pending_transfers_tree_A.packed_transfers,
    )
    assert unlocked_amount < pending_transfers_tree_A.locked_amount

    # We settle the channel with a smaller locked amount than the amount that can be unlocked
    channel_identifier = create_settled_channel(
        A,
        unlocked_amount - 1,
        pending_transfers_tree_A.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )

    pre_balance_A = custom_token.functions.balanceOf(A).call()
    pre_balance_B = custom_token.functions.balanceOf(B).call()
    balance_contract = custom_token.functions.balanceOf(token_network.address).call()
    assert balance_contract == unlocked_amount - 1

    # This should pass, even though the locked amount in storage is smaller.
    # A will receive the entire locked amount, corresponding to the locks that have been unlocked
    # and B will receive nothing.
    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree_A.packed_transfers,
    ).transact()

    balance_A = custom_token.functions.balanceOf(A).call()
    balance_B = custom_token.functions.balanceOf(B).call()
    balance_contract = custom_token.functions.balanceOf(token_network.address).call()
    assert balance_A == pre_balance_A
    assert balance_B == pre_balance_B + unlocked_amount - 1
    assert balance_contract == 0
示例#6
0
def test_merkle_root_odd_even_components(
        web3,
        get_accounts,
        token_network_test_utils,
        secret_registry_contract,
        reveal_secrets,
):
    (A, B) = get_accounts(2)

    # Even number of merkle tree components
    pending_transfers_tree = get_pending_transfers_tree(web3, [1, 3, 5], [2, 8, 3])
    reveal_secrets(A, pending_transfers_tree.unlockable)

    (
        locksroot,
        unlocked_amount,
    ) = token_network_test_utils.functions.getMerkleRootAndUnlockedAmountPublic(
        pending_transfers_tree.packed_transfers,
    ).call()
    merkle_root = pending_transfers_tree.merkle_root

    assert locksroot == merkle_root
    assert unlocked_amount == 9

    # Odd number of merkle tree components
    pending_transfers_tree = get_pending_transfers_tree(web3, [1, 3, 5], [2, 8])
    reveal_secrets(A, pending_transfers_tree.unlockable)

    (
        locksroot,
        unlocked_amount,
    ) = token_network_test_utils.functions.getMerkleRootAndUnlockedAmountPublic(
        pending_transfers_tree.packed_transfers,
    ).call()
    merkle_root = pending_transfers_tree.merkle_root

    assert locksroot == merkle_root
    assert unlocked_amount == 9
示例#7
0
def test_channel_unlock_unregistered_locks(
        web3,
        token_network,
        get_accounts,
        create_channel_and_deposit,
        withdraw_channel,
        close_and_update_channel,
        custom_token,
):
    (A, B) = get_accounts(2)
    settle_timeout = TEST_SETTLE_TIMEOUT_MIN

    pending_transfers_tree = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    locked_A = pending_transfers_tree.locked_amount
    (vals_A, vals_B) = (
        ChannelValues(deposit=35, withdrawn=10, transferred=0, locked=locked_A),
        ChannelValues(deposit=40, withdrawn=10, transferred=20, locked=0),
    )

    vals_A.locksroot = '0x' + get_merkle_root(pending_transfers_tree.merkle_tree).hex()
    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, B)
    withdraw_channel(channel_identifier, B, vals_B.withdrawn, A)

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

    # Secret hasn't been registered before settlement timeout
    web3.testing.mine(TEST_SETTLE_TIMEOUT_MIN)
    call_settle(token_network, channel_identifier, A, vals_A, B, vals_B)

    # Someone unlocks A's pending transfers - all tokens should be refunded
    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree.packed_transfers,
    ).transact({'from': A})

    # A gets back locked tokens
    assert (
        custom_token.functions.balanceOf(A).call() ==
        vals_A.deposit - vals_A.transferred + vals_B.transferred
    )
示例#8
0
def test_unlock_tampered_merkle_proof_fails(
        web3,
        token_network,
        get_accounts,
        create_settled_channel,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    # Regular channel life-cycle: open -> settle -> unlock -> open -> settle -> unlock

    # Mock pending transfers data
    pending_transfers_tree = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    reveal_secrets(A, pending_transfers_tree.unlockable)

    # Settle the channel
    channel_identifier = create_settled_channel(
        A,
        pending_transfers_tree.locked_amount,
        pending_transfers_tree.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )

    # Unlock with tampered locks does not work
    types = ['uint256', 'uint256', 'bytes32']
    for index in range(len(pending_transfers_tree.transfers)):
        pending_transfers = list(pending_transfers_tree.transfers)
        pending_transfers[index][2:] = random_secret()
        packed_transfers_tampered = get_packed_transfers(tuple(pending_transfers), types)
        with pytest.raises(TransactionFailed):
            token_network.functions.unlock(
                channel_identifier,
                B,
                A,
                packed_transfers_tampered,
            ).transact({'from': A})

    # Unlock with correct merkle tree does work
    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree.packed_transfers,
    ).transact({'from': A})
示例#9
0
def test_unlock_fails_with_partial_merkle_proof(
        web3,
        token_network,
        get_accounts,
        create_settled_channel,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    # Mock pending transfers data
    pending_transfers_tree = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    reveal_secrets(A, pending_transfers_tree.unlockable)

    # Settle the channel
    channel_identifier = create_settled_channel(
        A,
        pending_transfers_tree.locked_amount,
        pending_transfers_tree.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )

    # Unlock with one leave missing does not work
    types = ['uint256', 'uint256', 'bytes32']
    for index in range(len(pending_transfers_tree.transfers)):
        pending_transfers = list(pending_transfers_tree.transfers)
        del pending_transfers[index]
        packed_transfers_tampered = get_packed_transfers(tuple(pending_transfers), types)
        with pytest.raises(TransactionFailed):
            token_network.functions.unlock(
                channel_identifier,
                B,
                A,
                packed_transfers_tampered,
            ).transact({'from': A})

    # Unlock with full merkle tree does work
    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree.packed_transfers,
    ).transact({'from': A})
示例#10
0
def test_unlock_twice_fails(
        web3,
        token_network,
        get_accounts,
        create_settled_channel,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    # Regular channel life-cycle: open -> settle -> unlock -> open -> settle -> unlock

    # Mock pending transfers data
    pending_transfers_tree_1 = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    reveal_secrets(A, pending_transfers_tree_1.unlockable)

    # Settle the channel
    channel_identifier = create_settled_channel(
        A,
        pending_transfers_tree_1.locked_amount,
        pending_transfers_tree_1.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )
    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree_1.packed_transfers,
    ).transact({'from': A})

    # Calling unlock twice does not work
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            B,
            A,
            pending_transfers_tree_1.packed_transfers,
        ).transact({'from': A})
示例#11
0
def test_channel_unlock_no_locked_amount_fail(
        web3,
        token_network,
        custom_token,
        secret_registry_contract,
        create_settled_channel,
        get_accounts,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    # Mock pending transfers data
    pending_transfers_tree_A = get_pending_transfers_tree(web3, [2, 5], [4], settle_timeout)
    reveal_secrets(A, pending_transfers_tree_A.unlockable)

    channel_identifier = create_settled_channel(
        A,
        0,
        EMPTY_LOCKSROOT,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )

    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            B,
            A,
            b'',
        ).transact()
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            B,
            A,
            pending_transfers_tree_A.packed_transfers,
        ).transact()
示例#12
0
def test_channel_unlock_with_a_large_expiration(
        web3,
        custom_token,
        token_network,
        secret_registry_contract,
        create_channel,
        channel_deposit,
        get_accounts,
        close_and_update_channel,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    values_A = ChannelValues(
        deposit=20,
        transferred=5,
        locked=0,
        locksroot=EMPTY_LOCKSROOT,
    )
    values_B = ChannelValues(
        deposit=30,
        transferred=40,
    )

    # Create channel and deposit
    channel_identifier = create_channel(A, B, settle_timeout)[0]
    channel_deposit(channel_identifier, A, values_A.deposit, B)
    channel_deposit(channel_identifier, B, values_B.deposit, A)

    # Mock pending transfers data with large expiration date
    pending_transfers_tree = get_pending_transfers_tree(
        web3,
        [1, 3, 5],
        [2, 4],
        settle_timeout + 100,
    )
    values_B.locksroot = pending_transfers_tree.merkle_root
    values_B.locked = get_locked_amount(pending_transfers_tree.transfers)

    # Reveal secrets before settlement window ends
    reveal_secrets(A, pending_transfers_tree.unlockable)

    close_and_update_channel(
        channel_identifier,
        A,
        values_A,
        B,
        values_B,
    )

    # Settle channel after a "long" time
    web3.testing.mine(settle_timeout + 50)

    call_settle(token_network, channel_identifier, A, values_A, B, values_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()

    # Unlock the tokens must still work
    token_network.functions.unlock(
        channel_identifier,
        A,
        B,
        pending_transfers_tree.packed_transfers,
    ).transact()

    balance_A = custom_token.functions.balanceOf(A).call()
    balance_B = custom_token.functions.balanceOf(B).call()
    balance_contract = custom_token.functions.balanceOf(token_network.address).call()
    assert balance_A == pre_balance_A + 9
    assert balance_B == pre_balance_B + 6
    assert balance_contract == pre_balance_contract - values_B.locked
def test_settle_wrong_balance_hash(
        web3,
        get_accounts,
        token_network,
        create_channel_and_deposit,
        close_and_update_channel,
        get_block,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    vals_A = ChannelValues(
        deposit=35,
        withdrawn=0,
        transferred=5,
        claimable_locked=10,
        unclaimable_locked=2,
    )
    vals_B = ChannelValues(
        deposit=40,
        withdrawn=0,
        transferred=15,
        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(
        web3,
        unlockable_amount=vals_A.claimable_locked,
        expired_amount=vals_A.unclaimable_locked,
    )
    vals_A.locksroot = pending_transfers_tree_A.merkle_root
    # 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(
        web3,
        unlockable_amount=vals_B.claimable_locked,
        expired_amount=vals_B.unclaimable_locked,
    )
    vals_B.locksroot = pending_transfers_tree_B.merkle_root
    # Reveal B's secrets
    reveal_secrets(B, pending_transfers_tree_B.unlockable)

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

    web3.testing.mine(TEST_SETTLE_TIMEOUT_MIN)

    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 = MAX_UINT256
    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 += 1
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A_fail, B, vals_B)

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

    vals_A_fail.locked = MAX_UINT256
    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 = EMPTY_LOCKSROOT
    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 = MAX_UINT256
    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 += 1
    with pytest.raises(TransactionFailed):
        call_settle(token_network, channel_identifier, A, vals_A, B, vals_B_fail)

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

    vals_B_fail.locked = MAX_UINT256
    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 = EMPTY_LOCKSROOT
    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 test_channel_settle_invalid_balance_proof_values(
        web3,
        get_accounts,
        custom_token,
        token_network,
        create_channel_and_deposit,
        withdraw_channel,
        close_and_update_channel,
        settle_state_tests,
        reveal_secrets,
        channel_test_values,
):
    (A, B, C, D) = get_accounts(4)
    (vals_A, vals_B) = channel_test_values

    # We just need to test that settleChannel does not fail
    # We cannot ensure correctly computed final balances if the balance proofs
    # are invalid.
    # We can just test that participants do not get more tokens than the channel deposit

    # We make sure the contract has more tokens than A, B will deposit
    create_channel_and_deposit(C, D, 40, 60)

    # Start channel lifecycle for A, B
    channel_identifier = create_channel_and_deposit(A, B, vals_A.deposit, vals_B.deposit)
    withdraw_channel(channel_identifier, A, vals_A.withdrawn, B)
    withdraw_channel(channel_identifier, B, vals_B.withdrawn, 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(
        web3,
        unlockable_amount=vals_A.claimable_locked,
        expired_amount=vals_A.unclaimable_locked,
    )
    vals_A.locksroot = pending_transfers_tree_A.merkle_root
    # 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(
        web3,
        unlockable_amount=vals_B.claimable_locked,
        expired_amount=vals_B.unclaimable_locked,
    )
    vals_B.locksroot = pending_transfers_tree_B.merkle_root
    # Reveal B's secrets
    reveal_secrets(B, pending_transfers_tree_B.unlockable)

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

    web3.testing.mine(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,
    )
def test_deprecation_switch_settle(
    web3,
    get_accounts,
    token_network,
    custom_token,
    reveal_secrets,
    create_channel,
    channel_deposit,
    close_and_update_channel,
):
    deprecation_executor = token_network.functions.deprecation_executor().call(
    )
    (A, B) = get_accounts(2)
    deposit = 100

    (vals_A, vals_B) = (
        ChannelValues(
            deposit=deposit,
            withdrawn=0,
            transferred=5,
            claimable_locked=2,
            unclaimable_locked=4,
        ),
        ChannelValues(
            deposit=deposit,
            withdrawn=0,
            transferred=10,
            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(
        web3,
        unlockable_amount=vals_A.claimable_locked,
        expired_amount=vals_A.unclaimable_locked,
    )
    vals_A.locksroot = pending_transfers_tree_A.merkle_root
    # 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(
        web3,
        unlockable_amount=vals_B.claimable_locked,
        expired_amount=vals_B.unclaimable_locked,
    )
    vals_B.locksroot = pending_transfers_tree_B.merkle_root
    # Reveal B's secrets
    reveal_secrets(B, pending_transfers_tree_B.unlockable)

    # Set the deprecation switch to true
    token_network.functions.deprecate().transact({
        'from': deprecation_executor,
    })
    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,
    )
    web3.testing.mine(TEST_SETTLE_TIMEOUT_MIN)

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

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

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

    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_settle_channel_state(
        web3,
        get_accounts,
        custom_token,
        token_network,
        create_channel_and_deposit,
        withdraw_channel,
        close_and_update_channel,
        settle_state_tests,
):
    (A, B) = get_accounts(2)
    vals_A = ChannelValues(
        deposit=40,
        withdrawn=10,
        transferred=20020,
        claimable_locked=3,
        unclaimable_locked=4,
    )
    vals_B = ChannelValues(
        deposit=35,
        withdrawn=5,
        transferred=20030,
        claimable_locked=2,
        unclaimable_locked=3,
    )

    pending_transfers_tree_A = get_pending_transfers_tree(
        web3,
        unlockable_amount=vals_A.claimable_locked,
        expired_amount=vals_A.unclaimable_locked,
    )
    pending_transfers_tree_B = get_pending_transfers_tree(
        web3,
        unlockable_amount=vals_B.claimable_locked,
        expired_amount=vals_B.unclaimable_locked,
    )
    vals_A.locksroot = pending_transfers_tree_A.merkle_root
    vals_B.locksroot = pending_transfers_tree_B.merkle_root

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

    web3.testing.mine(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)

    # 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

    # FIXME after setTotalWithdraw is implemented again
    # we add the withdrawn amount here, because it was never withdrawn due to the
    # removal of setTotalWithdraw
    assert custom_token.functions.balanceOf(A).call() == post_balance_A + 10
    assert custom_token.functions.balanceOf(B).call() == post_balance_B + 5
    assert custom_token.functions.balanceOf(
        token_network.address,
    ).call() == post_balance_contract - 15
    def f(
            participants,
            channel_values,
            expected_settlement0,
            expected_settlement_onchain0,
            expected_final_balance_A0,
            expected_final_balance_B0,
    ):
        (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, B)
        withdraw_channel(channel_identifier, B, vals_B.withdrawn, 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(
            web3,
            unlockable_amount=vals_A.claimable_locked,
            expired_amount=vals_A.unclaimable_locked,
        )
        vals_A.locksroot = pending_transfers_tree_A.merkle_root
        # 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(
            web3,
            unlockable_amount=vals_B.claimable_locked,
            expired_amount=vals_B.unclaimable_locked,
        )
        vals_B.locksroot = pending_transfers_tree_B.merkle_root
        # Reveal B's secrets
        reveal_secrets(B, pending_transfers_tree_B.unlockable)

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

        web3.testing.mine(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.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,
                ).transact()
        else:
            token_network.functions.unlock(
                channel_identifier,
                A,
                B,
                pending_transfers_tree_B.packed_transfers,
            ).transact()

        # 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] == EMPTY_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,
                ).transact()
        else:
            token_network.functions.unlock(
                channel_identifier,
                B,
                A,
                pending_transfers_tree_A.packed_transfers,
            ).transact()

        # 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] == EMPTY_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 is '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 is '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 is '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)
        )
示例#18
0
def find_max_pending_transfers(gas_limit):
    """Measure gas consumption of TokenNetwork.unlock() depending on number of
    pending transfers and find the maximum number of pending transfers so
    gas_limit is not exceeded."""

    tester = ContractTester(generate_keys=2)

    tester.deploy_contract('SecretRegistry')

    tester.deploy_contract(
        'HumanStandardToken',
        _initialAmount=100000,
        _decimalUnits=3,
        _tokenName='SomeToken',
        _tokenSymbol='SMT',
    )

    tester.deploy_contract(
        'TokenNetwork',
        _token_address=tester.contract_address('HumanStandardToken'),
        _secret_registry=tester.contract_address('SecretRegistry'),
        _chain_id=1,
        _settlement_timeout_min=100,
        _settlement_timeout_max=200,
    )

    tester.call_transaction(
        'HumanStandardToken',
        'transfer',
        _to=tester.accounts[1],
        _value=10000,
    )

    receipt = tester.call_transaction(
        'TokenNetwork',
        'openChannel',
        participant1=tester.accounts[0],
        participant2=tester.accounts[1],
        settle_timeout=150,
    )

    channel_identifier = int(hexlify(receipt['logs'][0]['topics'][1]), 16)

    tester.call_transaction(
        'HumanStandardToken',
        'approve',
        sender=tester.accounts[0],
        _spender=tester.contract_address('TokenNetwork'),
        _value=10000,
    )

    tester.call_transaction(
        'HumanStandardToken',
        'approve',
        sender=tester.accounts[1],
        _spender=tester.contract_address('TokenNetwork'),
        _value=5000,
    )

    tester.call_transaction(
        'TokenNetwork',
        'setTotalDeposit',
        channel_identifier=channel_identifier,
        participant=tester.accounts[0],
        total_deposit=5000,
        partner=tester.accounts[1],
    )

    tester.call_transaction(
        'TokenNetwork',
        'setTotalDeposit',
        channel_identifier=channel_identifier,
        participant=tester.accounts[1],
        total_deposit=2000,
        partner=tester.accounts[0],
    )

    print(
        "Measuring unlock()'s gas cost for different Merkle tree widths, can take a while..."
    )

    before_closing = tester.tester.take_snapshot()
    enough = 0
    too_much = 1024

    nonce = 10
    additional_hash = urandom(32)
    token_network_identifier = tester.contract_address('TokenNetwork')

    while enough + 1 < too_much:
        tree_size = (enough + too_much) // 2
        tester.tester.revert_to_snapshot(before_closing)

        pending_transfers_tree = get_pending_transfers_tree(
            tester.web3,
            unlockable_amounts=[1] * tree_size,
        )

        balance_hash = hash_balance_data(3000, 2000,
                                         pending_transfers_tree.merkle_root)
        data_to_sign = pack_balance_proof(
            nonce=nonce,
            balance_hash=balance_hash,
            additional_hash=additional_hash,
            channel_identifier=channel_identifier,
            token_network_identifier=token_network_identifier,
            chain_id=1,
        )
        signature = eth_sign(privkey=tester.private_keys[1], data=data_to_sign)

        tester.call_transaction(
            'TokenNetwork',
            'closeChannel',
            channel_identifier=channel_identifier,
            partner=tester.accounts[1],
            balance_hash=balance_hash,
            nonce=nonce,
            additional_hash=additional_hash,
            signature=signature,
        )

        tester.tester.mine_blocks(160)  # close settlement window

        tester.call_transaction(
            'TokenNetwork',
            'settleChannel',
            channel_identifier=channel_identifier,
            participant1=tester.accounts[0],
            participant1_transferred_amount=0,
            participant1_locked_amount=0,
            participant1_locksroot=b'\x00' * 32,
            participant2=tester.accounts[1],
            participant2_transferred_amount=3000,
            participant2_locked_amount=2000,
            participant2_locksroot=pending_transfers_tree.merkle_root,
        )

        receipt = tester.call_transaction(
            'TokenNetwork',
            'unlock',
            channel_identifier=channel_identifier,
            participant=tester.accounts[0],
            partner=tester.accounts[1],
            merkle_tree_leaves=pending_transfers_tree.packed_transfers,
        )
        gas_used = receipt['gasUsed']

        if gas_used <= gas_limit:
            enough = tree_size
            print(
                f'{tree_size} pending transfers work ({gas_used} gas needed to unlock)'
            )
        else:
            too_much = tree_size
            print(
                f'{tree_size} pending transfers are too much ({gas_used} gas needed to unlock)'
            )
示例#19
0
def test_channel_unlock_both_participants(
        web3,
        custom_token,
        token_network,
        secret_registry_contract,
        create_channel,
        channel_deposit,
        get_accounts,
        close_and_update_channel,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    values_A = ChannelValues(
        deposit=100,
        transferred=5,
    )
    values_B = ChannelValues(
        deposit=100,
        transferred=40,
    )

    # Create channel and deposit
    channel_identifier = create_channel(A, B, settle_timeout)[0]
    channel_deposit(channel_identifier, A, values_A.deposit, B)
    channel_deposit(channel_identifier, B, values_B.deposit, A)

    # Mock pending transfers data for A
    pending_transfers_tree_A = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    values_A.locksroot = pending_transfers_tree_A.merkle_root
    values_A.locked = get_locked_amount(pending_transfers_tree_A.transfers)

    # Reveal A's secrets before settlement window ends
    reveal_secrets(A, pending_transfers_tree_A.unlockable)

    # Mock pending transfers data for B
    pending_transfers_tree_B = get_pending_transfers_tree(web3, [2, 4, 6], [5, 10], settle_timeout)
    values_B.locksroot = pending_transfers_tree_B.merkle_root
    values_B.locked = get_locked_amount(pending_transfers_tree_B.transfers)

    # Reveal B's secrets before settlement window ends
    reveal_secrets(B, pending_transfers_tree_B.unlockable)

    close_and_update_channel(
        channel_identifier,
        A,
        values_A,
        B,
        values_B,
    )

    # Settle channel
    web3.testing.mine(settle_timeout)

    call_settle(token_network, channel_identifier, A, values_A, B, values_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()

    # A unlock's
    token_network.functions.unlock(
        channel_identifier,
        A,
        B,
        pending_transfers_tree_B.packed_transfers,
    ).transact()

    # B unlock's
    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree_A.packed_transfers,
    ).transact()

    balance_A = custom_token.functions.balanceOf(A).call()
    balance_B = custom_token.functions.balanceOf(B).call()
    balance_contract = custom_token.functions.balanceOf(token_network.address).call()

    # Unlocked pending transfers A -> B, that belong to B
    unlockable_A = get_unlocked_amount(
        secret_registry_contract,
        pending_transfers_tree_A.packed_transfers,
    )

    # Expired pending transfers A -> B, that belong to A
    expired_A = get_locked_amount(pending_transfers_tree_A.expired)

    # Unlocked pending transfers B -> A, that belong to A
    unlockable_B = get_unlocked_amount(
        secret_registry_contract,
        pending_transfers_tree_B.packed_transfers,
    )

    # Expired pending transfers B -> A, that belong to B
    expired_B = get_locked_amount(pending_transfers_tree_B.expired)

    # check that A and B both received the expected amounts
    assert balance_contract == pre_balance_contract - values_B.locked - values_A.locked
    assert balance_A == pre_balance_A + unlockable_B + expired_A
    assert balance_B == pre_balance_B + unlockable_A + expired_B
示例#20
0
def test_channel_unlock(
        web3,
        custom_token,
        token_network,
        secret_registry_contract,
        create_channel,
        channel_deposit,
        get_accounts,
        close_and_update_channel,
        reveal_secrets,
        event_handler,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    values_A = ChannelValues(
        deposit=20,
        transferred=5,
        locked=0,
        locksroot=EMPTY_LOCKSROOT,
    )
    values_B = ChannelValues(
        deposit=30,
        transferred=40,
    )

    # Create channel and deposit
    channel_identifier = create_channel(A, B, settle_timeout)[0]
    channel_deposit(channel_identifier, A, values_A.deposit, B)
    channel_deposit(channel_identifier, B, values_B.deposit, A)

    # Mock pending transfers data
    pending_transfers_tree = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    values_B.locksroot = pending_transfers_tree.merkle_root
    values_B.locked = get_locked_amount(pending_transfers_tree.transfers)

    # Reveal secrets before settlement window ends
    reveal_secrets(A, pending_transfers_tree.unlockable)

    close_and_update_channel(
        channel_identifier,
        A,
        values_A,
        B,
        values_B,
    )

    # Settlement window must be over before settling the channel
    web3.testing.mine(settle_timeout)

    call_settle(token_network, channel_identifier, A, values_A, B, values_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()

    info_B = token_network.functions.getChannelParticipantInfo(
        channel_identifier,
        B,
        A,
    ).call()
    assert info_B[ParticipantInfoIndex.LOCKSROOT] == values_B.locksroot
    assert info_B[ParticipantInfoIndex.LOCKED_AMOUNT] == values_B.locked

    # Unlock the tokens
    token_network.functions.unlock(
        channel_identifier,
        A,
        B,
        pending_transfers_tree.packed_transfers,
    ).transact()

    info_B = token_network.functions.getChannelParticipantInfo(
        channel_identifier,
        B,
        A,
    ).call()
    assert info_B[ParticipantInfoIndex.LOCKSROOT] == EMPTY_LOCKSROOT
    assert info_B[ParticipantInfoIndex.LOCKED_AMOUNT] == 0

    balance_A = custom_token.functions.balanceOf(A).call()
    balance_B = custom_token.functions.balanceOf(B).call()
    balance_contract = custom_token.functions.balanceOf(token_network.address).call()
    assert balance_A == pre_balance_A + 9
    assert balance_B == pre_balance_B + 6
    assert balance_contract == pre_balance_contract - values_B.locked
示例#21
0
def test_channel_settle_and_unlock(
        web3,
        token_network,
        get_accounts,
        create_settled_channel,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    # Regular channel life-cycle: open -> settle -> unlock -> open -> settle -> unlock

    # Mock pending transfers data
    pending_transfers_tree_1 = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    reveal_secrets(A, pending_transfers_tree_1.unlockable)

    # Settle the channel
    channel_identifier1 = create_settled_channel(
        A,
        pending_transfers_tree_1.locked_amount,
        pending_transfers_tree_1.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )
    token_network.functions.unlock(
        channel_identifier1,
        B,
        A,
        pending_transfers_tree_1.packed_transfers,
    ).transact({'from': A})

    # Mock pending transfers data for a reopened channel
    pending_transfers_tree_2 = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    reveal_secrets(A, pending_transfers_tree_2.unlockable)

    # Settle the channel again
    channel_identifier2 = create_settled_channel(
        A,
        pending_transfers_tree_2.locked_amount,
        pending_transfers_tree_2.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )

    # 2nd unlocks should go through
    token_network.functions.unlock(
        channel_identifier2,
        B,
        A,
        pending_transfers_tree_2.packed_transfers,
    ).transact({'from': A})

    # Edge channel life-cycle: open -> settle -> open -> settle ->  unlock1 -> unlock2

    # Mock pending transfers data
    pending_transfers_tree_1 = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    reveal_secrets(A, pending_transfers_tree_1.unlockable)

    # Settle the channel
    channel_identifier3 = create_settled_channel(
        A,
        pending_transfers_tree_1.locked_amount,
        pending_transfers_tree_1.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )

    # Mock pending transfers data for a reopened channel
    pending_transfers_tree_2 = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    reveal_secrets(A, pending_transfers_tree_2.unlockable)

    # Settle the channel again
    channel_identifier4 = create_settled_channel(
        A,
        pending_transfers_tree_2.locked_amount,
        pending_transfers_tree_2.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )

    # Both old and new unlocks should go through
    token_network.functions.unlock(
        channel_identifier4,
        B,
        A,
        pending_transfers_tree_2.packed_transfers,
    ).transact({'from': A})
    token_network.functions.unlock(
        channel_identifier3,
        B,
        A,
        pending_transfers_tree_1.packed_transfers,
    ).transact({'from': A})
示例#22
0
def test_merkle_tree_components_order(
        web3,
        get_accounts,
        token_network_test_utils,
        secret_registry_contract,
        reveal_secrets,
        token_network,
        create_settled_channel,
):
    network_utils = token_network_test_utils
    (A, B) = get_accounts(2)
    types = ['uint256', 'uint256', 'bytes32']

    pending_transfers_tree = get_pending_transfers_tree(web3, [1, 3, 5], [2, 8, 3])
    reveal_secrets(A, pending_transfers_tree.unlockable)

    channel_identifier = create_settled_channel(
        A,
        pending_transfers_tree.locked_amount,
        pending_transfers_tree.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
    )

    # Merkle tree lockhashes are ordered lexicographicaly.
    # If we change the order, we change the computed merkle root.
    # However, the getMerkleRootAndUnlockedAmount orders neighbouring lockhashes
    # lexicographicaly, so simple item[i], item[i + 1] swap
    # will still result in the same merkle root.
    wrong_order = pending_transfers_tree.transfers
    wrong_order[1], wrong_order[0] = wrong_order[0], wrong_order[1]
    wrong_order_packed = get_packed_transfers(wrong_order, types)
    (
        locksroot,
        unlocked_amount,
    ) = network_utils.functions.getMerkleRootAndUnlockedAmountPublic(
        wrong_order_packed,
    ).call()
    # Same merkle root this time
    assert locksroot == pending_transfers_tree.merkle_root
    assert unlocked_amount == 9
    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        wrong_order_packed,
    ).call()

    wrong_order = pending_transfers_tree.transfers
    wrong_order[2], wrong_order[0] = wrong_order[0], wrong_order[2]
    wrong_order_packed = get_packed_transfers(wrong_order, types)
    (
        locksroot,
        unlocked_amount,
    ) = network_utils.functions.getMerkleRootAndUnlockedAmountPublic(
        wrong_order_packed,
    ).call()
    assert locksroot != pending_transfers_tree.merkle_root
    assert unlocked_amount == 9
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            B,
            A,
            wrong_order_packed,
        ).transact()

    wrong_order = pending_transfers_tree.transfers
    wrong_order[0], wrong_order[-1] = wrong_order[-1], wrong_order[0]
    wrong_order_packed = get_packed_transfers(wrong_order, types)
    (
        locksroot,
        unlocked_amount,
    ) = network_utils.functions.getMerkleRootAndUnlockedAmountPublic(
        wrong_order_packed,
    ).call()
    assert locksroot != pending_transfers_tree.merkle_root
    assert unlocked_amount == 9
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            B,
            A,
            wrong_order_packed,
        ).transact()

    (
        locksroot,
        unlocked_amount,
    ) = network_utils.functions.getMerkleRootAndUnlockedAmountPublic(
        pending_transfers_tree.packed_transfers,
    ).call()
    assert locksroot == pending_transfers_tree.merkle_root
    assert unlocked_amount == 9
    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree.packed_transfers,
    ).transact()
示例#23
0
def test_reverse_participants_unlock(
        web3,
        token_network,
        get_accounts,
        create_settled_channel,
        reveal_secrets,
):
    (A, B, C) = get_accounts(3)
    settle_timeout = 12

    # Mock pending transfers data
    pending_transfers_tree_A = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    pending_transfers_tree_B = get_pending_transfers_tree(web3, [3, 4, 6], [4], settle_timeout)
    assert pending_transfers_tree_A.merkle_root != pending_transfers_tree_B.merkle_root

    # Reveal secrets
    reveal_secrets(A, pending_transfers_tree_A.unlockable)
    reveal_secrets(B, pending_transfers_tree_B.unlockable)

    # Settle the channel
    channel_identifier = create_settled_channel(
        A,
        pending_transfers_tree_A.locked_amount,
        pending_transfers_tree_A.merkle_root,
        B,
        pending_transfers_tree_B.locked_amount,
        pending_transfers_tree_B.merkle_root,
        settle_timeout,
    )

    # A trying to unlock its own locksroot & locked amount MUST fail
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            A,
            B,
            pending_transfers_tree_A.packed_transfers,
        ).transact({'from': A})

    # Delegate trying to unlock A's own locksroot & locked amount on behalf of A MUST fail
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            A,
            B,
            pending_transfers_tree_A.packed_transfers,
        ).transact({'from': C})

    # B trying to unlock its own locksroot & locked amount MUST fail
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            B,
            A,
            pending_transfers_tree_B.packed_transfers,
        ).transact({'from': B})

    # Delegate trying to unlock B's own locksroot & locked amount on behalf of B MUST fail
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            B,
            A,
            pending_transfers_tree_B.packed_transfers,
        ).transact({'from': B})

    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            A,
            A,
            pending_transfers_tree_A.packed_transfers,
        ).transact({'from': A})

    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            B,
            B,
            pending_transfers_tree_B.packed_transfers,
        ).transact({'from': B})

    # Someone trying to unlock B's locksroot & locked amount on behalf of A MUST succeed
    token_network.functions.unlock(
        channel_identifier,
        A,
        B,
        pending_transfers_tree_B.packed_transfers,
    ).transact({'from': C})

    # Someone trying to unlock A's locksroot & locked amount on behalf of B MUST succeed
    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree_A.packed_transfers,
    ).transact({'from': C})
示例#24
0
def test_channel_unlock_registered_expired_lock_refunds(
        web3,
        custom_token,
        token_network,
        secret_registry_contract,
        create_channel,
        channel_deposit,
        get_accounts,
        reveal_secrets,
        close_and_update_channel,
):
    (A, B) = get_accounts(2)
    max_lock_expiration = 3
    settle_timeout = 8

    values_A = ChannelValues(
        deposit=20,
        transferred=5,
        locked=0,
        locksroot=EMPTY_LOCKSROOT,
    )
    values_B = ChannelValues(
        deposit=30,
        transferred=40,
    )

    # Create channel and deposit
    channel_identifier = create_channel(A, B, settle_timeout)[0]
    channel_deposit(channel_identifier, A, values_A.deposit, B)
    channel_deposit(channel_identifier, B, values_B.deposit, A)

    # Mock pending transfers data
    pending_transfers_tree = get_pending_transfers_tree(
        web3,
        [1, 3, 5],
        [2, 4],
        min_expiration_delta=max_lock_expiration - 2,
        max_expiration_delta=max_lock_expiration,
    )
    values_B.locksroot = pending_transfers_tree.merkle_root
    values_B.locked = get_locked_amount(pending_transfers_tree.transfers)

    # Locks expire
    web3.testing.mine(max_lock_expiration)

    # Secrets are revealed before settlement window, but after expiration
    for (_, _, secrethash, secret) in pending_transfers_tree.unlockable:
        secret_registry_contract.functions.registerSecret(secret).transact({'from': A})
        assert secret_registry_contract.functions.getSecretRevealBlockHeight(
            secrethash,
        ).call() == web3.eth.blockNumber

    close_and_update_channel(
        channel_identifier,
        A,
        values_A,
        B,
        values_B,
    )
    web3.testing.mine(settle_timeout)

    # settle channel
    call_settle(token_network, channel_identifier, A, values_A, B, values_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()

    # Unlock works after channel is settled
    token_network.functions.unlock(
        channel_identifier,
        A,
        B,
        pending_transfers_tree.packed_transfers,
    ).transact()

    balance_A = custom_token.functions.balanceOf(A).call()
    balance_B = custom_token.functions.balanceOf(B).call()
    balance_contract = custom_token.functions.balanceOf(token_network.address).call()

    # check that all tokens have been refunded, as locks have expired already
    assert balance_A == pre_balance_A
    assert balance_B == pre_balance_B + values_B.locked
    assert balance_contract == pre_balance_contract - values_B.locked
示例#25
0
def test_unlock_different_channel_same_participants_fail(
        web3,
        token_network,
        get_accounts,
        create_settled_channel,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    # Mock pending transfers data
    pending_transfers_tree_1 = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    reveal_secrets(A, pending_transfers_tree_1.unlockable)
    channel_identifier = create_settled_channel(
        A,
        pending_transfers_tree_1.locked_amount,
        pending_transfers_tree_1.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )

    # The first channel is settled, so we create another one
    pending_transfers_tree_2 = get_pending_transfers_tree(web3, [3, 5], [2, 4, 3], settle_timeout)
    reveal_secrets(A, pending_transfers_tree_2.unlockable)
    channel_identifier2 = create_settled_channel(
        A,
        pending_transfers_tree_2.locked_amount,
        pending_transfers_tree_2.merkle_root,
        B,
        0,
        EMPTY_LOCKSROOT,
        settle_timeout,
    )

    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            B,
            A,
            pending_transfers_tree_2.packed_transfers,
        ).transact({'from': A})
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier2,
            B,
            A,
            pending_transfers_tree_1.packed_transfers,
        ).transact({'from': A})

    token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree_1.packed_transfers,
    ).transact({'from': A})
    token_network.functions.unlock(
        channel_identifier2,
        B,
        A,
        pending_transfers_tree_2.packed_transfers,
    ).transact({'from': A})
示例#26
0
def test_channel_unlock_before_settlement_fails(
        web3,
        custom_token,
        token_network,
        secret_registry_contract,
        create_channel,
        channel_deposit,
        get_accounts,
        close_and_update_channel,
        reveal_secrets,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    values_A = ChannelValues(
        deposit=20,
        transferred=5,
        locked=0,
        locksroot=EMPTY_LOCKSROOT,
    )
    values_B = ChannelValues(
        deposit=30,
        transferred=40,
    )

    # Create channel and deposit
    channel_identifier = create_channel(A, B, settle_timeout)[0]

    # Mock pending transfers data
    pending_transfers_tree = get_pending_transfers_tree(web3, [1, 3, 5], [2, 4], settle_timeout)
    values_B.locksroot = pending_transfers_tree.merkle_root
    values_B.locked = get_locked_amount(pending_transfers_tree.transfers)

    # Reveal secrets before settlement window ends
    reveal_secrets(A, pending_transfers_tree.unlockable)

    # Unlock fails before channel is not settled
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            A,
            B,
            pending_transfers_tree.packed_transfers,
        ).transact()

    channel_deposit(channel_identifier, A, values_A.deposit, B)
    channel_deposit(channel_identifier, B, values_B.deposit, A)

    # Unlock fails before channel is not settled
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            A,
            B,
            pending_transfers_tree.packed_transfers,
        ).transact()

    close_and_update_channel(
        channel_identifier,
        A,
        values_A,
        B,
        values_B,
    )

    # Unlock fails before settlement window is over and channel is not settled
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            A,
            B,
            pending_transfers_tree.packed_transfers,
        ).transact()

    # Settlement window must be over before settling the channel
    web3.testing.mine(settle_timeout)

    # Unlock fails before settle is called
    with pytest.raises(TransactionFailed):
        token_network.functions.unlock(
            channel_identifier,
            A,
            B,
            pending_transfers_tree.packed_transfers,
        ).transact()

    # settle channel
    call_settle(token_network, channel_identifier, A, values_A, B, values_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()

    # Unlock works after channel is settled
    token_network.functions.unlock(
        channel_identifier,
        A,
        B,
        pending_transfers_tree.packed_transfers,
    ).transact()

    balance_A = custom_token.functions.balanceOf(A).call()
    balance_B = custom_token.functions.balanceOf(B).call()
    balance_contract = custom_token.functions.balanceOf(token_network.address).call()
    assert balance_A == pre_balance_A + 9
    assert balance_B == pre_balance_B + 6
    assert balance_contract == pre_balance_contract - values_B.locked
示例#27
0
def test_unlock_channel_event(
        web3,
        token_network,
        secret_registry_contract,
        create_channel,
        channel_deposit,
        get_accounts,
        close_and_update_channel,
        reveal_secrets,
        event_handler,
):
    (A, B) = get_accounts(2)
    settle_timeout = 8

    values_A = ChannelValues(
        deposit=20,
        transferred=5,
        locked=0,
        locksroot=EMPTY_LOCKSROOT,
    )
    values_B = ChannelValues(
        deposit=30,
        transferred=40,
    )

    # Create channel and deposit
    channel_identifier = create_channel(A, B, settle_timeout)[0]
    channel_deposit(channel_identifier, A, values_A.deposit, B)
    channel_deposit(channel_identifier, B, values_B.deposit, A)

    # Mock pending transfers data
    pending_transfers_tree = get_pending_transfers_tree(
        web3,
        [1, 3, 5],
        [2, 4],
        settle_timeout + 100,
    )
    values_B.locksroot = pending_transfers_tree.merkle_root
    values_B.locked = get_locked_amount(pending_transfers_tree.transfers)

    # Reveal secrets before settlement window ends
    reveal_secrets(A, pending_transfers_tree.unlockable)

    close_and_update_channel(
        channel_identifier,
        A,
        values_A,
        B,
        values_B,
    )

    # Settlement window must be over before settling the channel
    web3.testing.mine(settle_timeout)

    call_settle(token_network, channel_identifier, A, values_A, B, values_B)

    ev_handler = event_handler(token_network)

    # Unlock the tokens
    txn_hash = token_network.functions.unlock(
        channel_identifier,
        A,
        B,
        pending_transfers_tree.packed_transfers,
    ).transact()

    unlocked_amount = get_unlocked_amount(
        secret_registry_contract,
        pending_transfers_tree.packed_transfers,
    )

    # Add event
    ev_handler.add(txn_hash, ChannelEvent.UNLOCKED, check_channel_unlocked(
        channel_identifier,
        A,
        B,
        values_B.locksroot,
        unlocked_amount,
        values_B.locked - unlocked_amount,
    ))

    # Check that event was properly emitted
    ev_handler.check()
示例#28
0
def find_max_pending_transfers(gas_limit):
    """Measure gas consumption of TokenNetwork.unlock() depending on number of
    pending transfers and find the maximum number of pending transfers so
    gas_limit is not exceeded."""

    tester = ContractTester(generate_keys=2)

    tester.deploy_contract('SecretRegistry')

    tester.deploy_contract(
        'HumanStandardToken',
        _initialAmount=100000,
        _decimalUnits=3,
        _tokenName='SomeToken',
        _tokenSymbol='SMT',
    )

    tester.deploy_contract(
        'TokenNetwork',
        _token_address=tester.contract_address('HumanStandardToken'),
        _secret_registry=tester.contract_address('SecretRegistry'),
        _chain_id=1,
        _settlement_timeout_min=100,
        _settlement_timeout_max=200,
    )

    tester.call_transaction(
        'HumanStandardToken',
        'transfer',
        _to=tester.accounts[1],
        _value=10000,
    )

    receipt = tester.call_transaction(
        'TokenNetwork',
        'openChannel',
        participant1=tester.accounts[0],
        participant2=tester.accounts[1],
        settle_timeout=150,
    )

    channel_identifier = int(encode_hex(receipt['logs'][0]['topics'][1]), 16)

    tester.call_transaction(
        'HumanStandardToken',
        'approve',
        sender=tester.accounts[0],
        _spender=tester.contract_address('TokenNetwork'),
        _value=10000,
    )

    tester.call_transaction(
        'HumanStandardToken',
        'approve',
        sender=tester.accounts[1],
        _spender=tester.contract_address('TokenNetwork'),
        _value=5000,
    )

    tester.call_transaction(
        'TokenNetwork',
        'setTotalDeposit',
        channel_identifier=channel_identifier,
        participant=tester.accounts[0],
        total_deposit=5000,
        partner=tester.accounts[1],
    )

    tester.call_transaction(
        'TokenNetwork',
        'setTotalDeposit',
        channel_identifier=channel_identifier,
        participant=tester.accounts[1],
        total_deposit=2000,
        partner=tester.accounts[0],
    )

    print("Measuring unlock()'s gas cost for different Merkle tree widths, can take a while...")

    before_closing = tester.tester.take_snapshot()
    enough = 0
    too_much = 1024

    nonce = 10
    additional_hash = urandom(32)
    token_network_identifier = tester.contract_address('TokenNetwork')

    while enough + 1 < too_much:
        tree_size = (enough + too_much) // 2
        tester.tester.revert_to_snapshot(before_closing)

        pending_transfers_tree = get_pending_transfers_tree(
            tester.web3,
            unlockable_amounts=[1] * tree_size,
        )

        balance_hash = hash_balance_data(3000, 2000, pending_transfers_tree.merkle_root)
        data_to_sign = pack_balance_proof(
            nonce=nonce,
            balance_hash=balance_hash,
            additional_hash=additional_hash,
            channel_identifier=channel_identifier,
            token_network_identifier=token_network_identifier,
            chain_id=1,
        )
        signature = eth_sign(privkey=tester.private_keys[1], data=data_to_sign)

        tester.call_transaction(
            'TokenNetwork',
            'closeChannel',
            channel_identifier=channel_identifier,
            partner=tester.accounts[1],
            balance_hash=balance_hash,
            nonce=nonce,
            additional_hash=additional_hash,
            signature=signature,
        )

        tester.tester.mine_blocks(160)  # close settlement window

        tester.call_transaction(
            'TokenNetwork',
            'settleChannel',
            channel_identifier=channel_identifier,
            participant1=tester.accounts[0],
            participant1_transferred_amount=0,
            participant1_locked_amount=0,
            participant1_locksroot=b'\x00' * 32,
            participant2=tester.accounts[1],
            participant2_transferred_amount=3000,
            participant2_locked_amount=2000,
            participant2_locksroot=pending_transfers_tree.merkle_root,
        )

        receipt = tester.call_transaction(
            'TokenNetwork',
            'unlock',
            channel_identifier=channel_identifier,
            participant=tester.accounts[0],
            partner=tester.accounts[1],
            merkle_tree_leaves=pending_transfers_tree.packed_transfers,
        )
        gas_used = receipt['gasUsed']

        if gas_used <= gas_limit:
            enough = tree_size
            print(f'{tree_size} pending transfers work ({gas_used} gas needed to unlock)')
        else:
            too_much = tree_size
            print(f'{tree_size} pending transfers are too much ({gas_used} gas needed to unlock)')
示例#29
0
def test_lock_data_from_merkle_tree(
        web3,
        get_accounts,
        token_network_test_utils,
        secret_registry_contract,
        reveal_secrets,
):
    network_utils = token_network_test_utils
    (A, B) = get_accounts(2)

    unlockable_amounts = [3, 5]
    expired_amounts = [2, 8, 7]
    pending_transfers_tree = get_pending_transfers_tree(
        web3,
        unlockable_amounts,
        expired_amounts,
        max_expiration_delta=5,
    )
    reveal_secrets(A, pending_transfers_tree.unlockable)

    def claimable(index):
        amount = pending_transfers_tree.transfers[index][1]
        return amount if amount in unlockable_amounts else 0

    def get_lockhash(index):
        return pending_transfers_tree.merkle_tree.layers[0][index]

    # Lock data is ordered lexicographically, regardless of expiration status
    (lockhash, claimable_amount) = network_utils.functions.getLockDataFromMerkleTreePublic(
        pending_transfers_tree.packed_transfers,
        32,
    ).call()
    assert lockhash == get_lockhash(0)
    assert claimable_amount == claimable(0)

    (lockhash, claimable_amount) = network_utils.functions.getLockDataFromMerkleTreePublic(
        pending_transfers_tree.packed_transfers,
        32 + 96,
    ).call()
    assert lockhash == get_lockhash(1)
    assert claimable_amount == claimable(1)

    (lockhash, claimable_amount) = network_utils.functions.getLockDataFromMerkleTreePublic(
        pending_transfers_tree.packed_transfers,
        32 + 2 * 96,
    ).call()
    assert lockhash == get_lockhash(2)
    assert claimable_amount == claimable(2)

    (lockhash, claimable_amount) = network_utils.functions.getLockDataFromMerkleTreePublic(
        pending_transfers_tree.packed_transfers,
        32 + 3 * 96,
    ).call()
    assert lockhash == get_lockhash(3)
    assert claimable_amount == claimable(3)

    (lockhash, claimable_amount) = network_utils.functions.getLockDataFromMerkleTreePublic(
        pending_transfers_tree.packed_transfers,
        32 + 4 * 96,
    ).call()
    assert lockhash == get_lockhash(4)
    assert claimable_amount == claimable(4)

    # Register last secret after expiration
    web3.testing.mine(5)
    last_lock = pending_transfers_tree.expired[-1]
    # expiration
    assert web3.eth.blockNumber > last_lock[0]
    # register secret
    secret_registry_contract.functions.registerSecret(last_lock[3]).transact()
    # ensure registration was done
    assert secret_registry_contract.functions.getSecretRevealBlockHeight(
        last_lock[2],
    ).call() == web3.eth.blockNumber

    # Check that last secret is still regarded as expired
    (lockhash, claimable_amount) = network_utils.functions.getLockDataFromMerkleTreePublic(
        pending_transfers_tree.packed_transfers,
        32 + 4 * 96,
    ).call()
    assert lockhash == get_lockhash(4)
    assert claimable_amount == claimable(4)

    # If the offset is bigger than the length of the merkle tree, return (0, 0)
    (lockhash, claimable_amount) = network_utils.functions.getLockDataFromMerkleTreePublic(
        pending_transfers_tree.packed_transfers,
        32 + 5 * 96,
    ).call()
    assert lockhash == b'\x00' * 32
    assert claimable_amount == 0
示例#30
0
def test_channel_cycle(
    web3,
    token_network,
    create_channel,
    channel_deposit,
    secret_registry_contract,
    get_accounts,
    print_gas,
    create_balance_proof,
    create_balance_proof_update_signature,
):
    (A, B) = get_accounts(2)
    settle_timeout = 11

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

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

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

    pending_transfers_tree2 = get_pending_transfers_tree(web3, [3], [], 7)
    locksroot2 = get_merkle_root(pending_transfers_tree2.merkle_tree)
    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_B = create_balance_proof(
        channel_identifier,
        B,
        5,
        locked_amount2,
        3,
        locksroot2,
    )
    balance_proof_update_signature_B = create_balance_proof_update_signature(
        B,
        channel_identifier,
        *balance_proof_A,
    )

    for lock in pending_transfers_tree1.unlockable:
        txn_hash = secret_registry_contract.functions.registerSecret(
            lock[3]).transact({'from': A})
    for lock in pending_transfers_tree2.unlockable:
        txn_hash = secret_registry_contract.functions.registerSecret(
            lock[3]).transact({'from': A})

    print_gas(txn_hash, CONTRACT_SECRET_REGISTRY + '.registerSecret')

    txn_hash = token_network.functions.closeChannel(
        channel_identifier,
        B,
        *balance_proof_B,
    ).transact({'from': A})
    print_gas(txn_hash, CONTRACT_TOKEN_NETWORK + '.closeChannel')

    txn_hash = token_network.functions.updateNonClosingBalanceProof(
        channel_identifier,
        A,
        B,
        *balance_proof_A,
        balance_proof_update_signature_B,
    ).transact({'from': B})
    print_gas(txn_hash,
              CONTRACT_TOKEN_NETWORK + '.updateNonClosingBalanceProof')

    web3.testing.mine(settle_timeout)
    txn_hash = token_network.functions.settleChannel(
        channel_identifier,
        B,
        5,
        locked_amount2,
        locksroot2,
        A,
        10,
        locked_amount1,
        locksroot1,
    ).transact()
    print_gas(txn_hash, CONTRACT_TOKEN_NETWORK + '.settleChannel')

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

    txn_hash = token_network.functions.unlock(
        channel_identifier,
        B,
        A,
        pending_transfers_tree1.packed_transfers,
    ).transact()
    print_gas(
        txn_hash, '{0}.unlock {1} locks'.format(
            CONTRACT_TOKEN_NETWORK,
            len(pending_transfers_tree1.transfers),
        ))
示例#31
0
def find_max_pending_transfers(gas_limit):
    """Measure gas consumption of TokenNetwork.unlock() depending on number of
    pending transfers and find the maximum number of pending transfers so
    gas_limit is not exceeded."""

    tester = ContractTester(generate_keys=2)

    tester.deploy_contract("SecretRegistry")

    tester.deploy_contract(
        "HumanStandardToken",
        _initialAmount=100000,
        _decimalUnits=3,
        _tokenName="SomeToken",
        _tokenSymbol="SMT",
    )

    tester.deploy_contract(
        "TokenNetwork",
        _token_address=tester.contract_address("HumanStandardToken"),
        _secret_registry=tester.contract_address("SecretRegistry"),
        _chain_id=1,
        _settlement_timeout_min=100,
        _settlement_timeout_max=200,
    )

    tester.call_transaction("HumanStandardToken",
                            "transfer",
                            _to=tester.accounts[1],
                            _value=10000)

    receipt = tester.call_transaction(
        "TokenNetwork",
        "openChannel",
        participant1=tester.accounts[0],
        participant2=tester.accounts[1],
        settle_timeout=150,
    )

    channel_identifier = int(encode_hex(receipt["logs"][0]["topics"][1]), 16)

    tester.call_transaction(
        "HumanStandardToken",
        "approve",
        sender=tester.accounts[0],
        _spender=tester.contract_address("TokenNetwork"),
        _value=10000,
    )

    tester.call_transaction(
        "HumanStandardToken",
        "approve",
        sender=tester.accounts[1],
        _spender=tester.contract_address("TokenNetwork"),
        _value=5000,
    )

    tester.call_transaction(
        "TokenNetwork",
        "setTotalDeposit",
        channel_identifier=channel_identifier,
        participant=tester.accounts[0],
        total_deposit=5000,
        partner=tester.accounts[1],
    )

    tester.call_transaction(
        "TokenNetwork",
        "setTotalDeposit",
        channel_identifier=channel_identifier,
        participant=tester.accounts[1],
        total_deposit=2000,
        partner=tester.accounts[0],
    )

    print(
        "Measuring unlock()'s gas cost for different Merkle tree widths, can take a while..."
    )

    before_closing = tester.tester.take_snapshot()
    enough = 0
    too_much = 1024

    nonce = 10
    additional_hash = urandom(32)
    token_network_identifier = tester.contract_address("TokenNetwork")

    while enough + 1 < too_much:
        tree_size = (enough + too_much) // 2
        tester.tester.revert_to_snapshot(before_closing)

        pending_transfers_tree = get_pending_transfers_tree(
            tester.web3, unlockable_amounts=[1] * tree_size)

        balance_hash = hash_balance_data(3000, 2000,
                                         pending_transfers_tree.merkle_root)
        # FIXME: outdated
        data_to_sign = pack_balance_proof(
            nonce=nonce,
            balance_hash=balance_hash,
            additional_hash=additional_hash,
            canonical_identifier=CanonicalIdentifier(
                chain_identifier=1,
                token_network_address=token_network_identifier,
                channel_identifier=channel_identifier,
            ),
        )
        signature = LocalSigner(tester.private_keys[1]).sign(data=data_to_sign)

        tester.call_transaction(
            "TokenNetwork",
            "closeChannel",
            channel_identifier=channel_identifier,
            partner=tester.accounts[1],
            balance_hash=balance_hash,
            nonce=nonce,
            additional_hash=additional_hash,
            signature=signature,
        )

        tester.tester.mine_blocks(160)  # close settlement window

        tester.call_transaction(
            "TokenNetwork",
            "settleChannel",
            channel_identifier=channel_identifier,
            participant1=tester.accounts[0],
            participant1_transferred_amount=0,
            participant1_locked_amount=0,
            participant1_locksroot=b"\x00" * 32,
            participant2=tester.accounts[1],
            participant2_transferred_amount=3000,
            participant2_locked_amount=2000,
            participant2_locksroot=pending_transfers_tree.merkle_root,
        )

        receipt = tester.call_transaction(
            "TokenNetwork",
            "unlock",
            channel_identifier=channel_identifier,
            participant=tester.accounts[0],
            partner=tester.accounts[1],
            merkle_tree_leaves=pending_transfers_tree.packed_transfers,
        )
        gas_used = receipt["gasUsed"]

        if gas_used <= gas_limit:
            enough = tree_size
            print(
                f"{tree_size} pending transfers work ({gas_used} gas needed to unlock)"
            )
        else:
            too_much = tree_size
            print(
                f"{tree_size} pending transfers are too much ({gas_used} gas needed to unlock)"
            )