Exemplo n.º 1
0
def test_three():
    def sort_join(first, second):
        return ''.join(sorted([first, second]))

    hash_0 = 'a' * 32
    hash_1 = 'b' * 32
    hash_2 = 'c' * 32

    leaves = [hash_0, hash_1, hash_2]
    tree = Merkletree(leaves)
    merkle_root = tree.merkleroot

    hash_01 = (
        b'me\xef\x9c\xa9=5\x16\xa4\xd3\x8a\xb7\xd9\x89\xc2\xb5\x00'
        b'\xe2\xfc\x89\xcc\xdc\xf8x\xf9\xc4m\xaa\xf6\xad\r['
    )
    assert keccak(hash_0 + hash_1) == hash_01
    calculated_root = keccak(hash_2 + hash_01)

    merkle_proof0 = tree.make_proof(hash_0)
    assert merkle_proof0 == [hash_1, hash_2]
    assert merkle_root == calculated_root
    assert check_proof(merkle_proof0, merkle_root, hash_0)

    merkle_proof1 = tree.make_proof(hash_1)
    assert merkle_proof1 == [hash_0, hash_2]
    assert merkle_root == calculated_root
    assert check_proof(merkle_proof1, merkle_root, hash_1)

    # with an odd number of values, the last value wont appear by itself in the
    # proof since it isn't hashed with another value
    merkle_proof2 = tree.make_proof(hash_2)
    assert merkle_proof2 == [keccak(hash_0 + hash_1)]
    assert merkle_root == calculated_root
    assert check_proof(merkle_proof2, merkle_root, hash_2)
def test_merkle_proof_missing_byte(tree, tester_state,
                                   tester_nettingchannel_library_address):
    """ computeMerkleRoot must fail if the proof is missing a byte. """

    auxiliary = deploy_auxiliary_tester(tester_state,
                                        tester_nettingchannel_library_address)

    hashes = [sha3(element) for element in tree]
    merkle_tree = Merkletree(hashes)

    element = hashes[-1]
    merkle_proof = merkle_tree.make_proof(element)

    # for each element of the proof, remove a byte from the start and the end and test it
    for element_to_tamper in range(len(merkle_proof)):
        tampered_proof = list(merkle_proof)
        tampered_proof[element_to_tamper] = tampered_proof[
            element_to_tamper][:-1]

        with pytest.raises(TransactionFailed):
            auxiliary.computeMerkleRoot(
                element,
                ''.join(tampered_proof),
            )

        tampered_proof = list(merkle_proof)
        tampered_proof[element_to_tamper] = tampered_proof[element_to_tamper][
            1:]

        with pytest.raises(TransactionFailed):
            auxiliary.computeMerkleRoot(
                element,
                ''.join(tampered_proof),
            )
Exemplo n.º 3
0
def test_withdraw_tampered_lock_amount(tree, tester_channels, tester_state,
                                       tester_token, settle_timeout):
    """ withdraw must fail if the lock amonut is tampered. """
    pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0]

    current_block = tester_state.block.number
    expiration = current_block + settle_timeout - 1
    locks = [
        make_lock(
            hashlock=hashlock,
            expiration=expiration,
        ) for hashlock in tree
    ]

    merkle_tree = Merkletree(sha3(lock.as_bytes) for lock in locks)

    opened_block = nettingchannel.opened(sender=pkey0)
    nonce = 1 + (opened_block * (2**32))
    direct_transfer = make_direct_transfer(
        nonce=nonce,
        channel=channel0.channel_address,
        locksroot=merkle_tree.merkleroot,
        token=tester_token.address,
        recipient=privatekey_to_address(pkey1))

    address = privatekey_to_address(pkey0)
    sign_key = PrivateKey(pkey0)
    direct_transfer.sign(sign_key, address)

    direct_transfer_hash = sha3(direct_transfer.packed().data[:-65])
    nettingchannel.close(
        direct_transfer.nonce,
        direct_transfer.transferred_amount,
        direct_transfer.locksroot,
        direct_transfer_hash,
        direct_transfer.signature,
        sender=pkey1,
    )

    for lock in locks:
        secret = HASHLOCKS_SECRESTS[lock.hashlock]

        lock_encoded = lock.as_bytes
        merkle_proof = merkle_tree.make_proof(sha3(lock_encoded))

        tampered_lock = make_lock(
            amount=lock.amount * 100,
            hashlock=lock.hashlock,
            expiration=lock.expiration,
        )
        tampered_lock_encoded = sha3(tampered_lock.as_bytes)

        with pytest.raises(TransactionFailed):
            nettingchannel.withdraw(
                tampered_lock_encoded,
                ''.join(merkle_proof),
                secret,
                sender=pkey1,
            )
Exemplo n.º 4
0
def test_duplicates():
    hash_0 = keccak('x')
    hash_1 = keccak('y')

    with pytest.raises(ValueError):
        Merkletree([hash_0, hash_0])

    with pytest.raises(ValueError):
        Merkletree([hash_0, hash_1, hash_0])
Exemplo n.º 5
0
def test_withdraw_fails_with_partial_merkle_proof(tree, tester_channels,
                                                  tester_state,
                                                  settle_timeout):
    """ withdraw must fail if informed proof is not complete. """
    pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0]

    current_block = tester_state.block.number
    expiration = current_block + settle_timeout - 1
    locks = [
        make_lock(
            hashlock=hashlock,
            expiration=expiration,
        ) for hashlock in tree
    ]

    merkle_tree = Merkletree(sha3(lock.as_bytes) for lock in locks)

    opened_block = nettingchannel.opened(sender=pkey0)
    nonce = 1 + (opened_block * (2**32))
    direct_transfer = make_direct_transfer(
        nonce=nonce,
        channel=channel0.channel_address,
        locksroot=merkle_tree.merkleroot,
        recipient=privatekey_to_address(pkey1))

    address = privatekey_to_address(pkey0)
    sign_key = PrivateKey(pkey0)
    direct_transfer.sign(sign_key, address)

    direct_transfer_hash = sha3(direct_transfer.packed().data[:-65])
    nettingchannel.close(
        direct_transfer.nonce,
        direct_transfer.transferred_amount,
        direct_transfer.locksroot,
        direct_transfer_hash,
        direct_transfer.signature,
        sender=pkey1,
    )

    for lock in locks:
        secret = HASHLOCKS_SECRESTS[lock.hashlock]
        lock_encoded = lock.as_bytes
        merkle_proof = merkle_tree.make_proof(sha3(lock_encoded))

        # withdraw must fail regardless of which part of the proof is removed
        for hash_ in merkle_proof:
            tampered_proof = list(merkle_proof)
            tampered_proof.remove(hash_)

            with pytest.raises(TransactionFailed):
                nettingchannel.withdraw(
                    lock_encoded,
                    ''.join(tampered_proof),
                    secret,
                    sender=pkey1,
                )
Exemplo n.º 6
0
def test_one():
    hash_0 = 'a' * 32

    leaves = [hash_0]
    tree = Merkletree(leaves)
    merkle_root = tree.merkleroot
    merkle_proof = tree.make_proof(hash_0)

    assert merkle_proof == []
    assert merkle_root == hash_0
    assert check_proof(merkle_proof, merkle_root, hash_0) is True
Exemplo n.º 7
0
def test_many(tree_up_to=10):
    for number_of_leaves in range(tree_up_to):
        leaves = [sha3(str(value)) for value in range(number_of_leaves)]
        tree = Merkletree(leaves)
        merkleroot = tree.merkleroot

        for value in leaves:
            merkle_proof = tree.make_proof(value)
            assert check_proof(merkle_proof, merkleroot, value)

        assert merkleroot == Merkletree(reversed(leaves)).merkleroot
Exemplo n.º 8
0
def test_withdraw_tampered_merkle_proof(tree, tester_channels, tester_state,
                                        settle_timeout):
    """ withdraw must fail if the proof is tampered. """
    pkey0, pkey1, nettingchannel, _, _ = tester_channels[0]

    current_block = tester_state.block.number
    expiration = current_block + settle_timeout - 1
    locks = [
        make_lock(
            hashlock=hashlock,
            expiration=expiration,
        ) for hashlock in tree
    ]

    merkle_tree = Merkletree(sha3(lock.as_bytes) for lock in locks)

    opened_block = nettingchannel.opened(sender=pkey0)
    nonce = 1 + (opened_block * (2**32))
    direct_transfer = make_direct_transfer(
        nonce=nonce,
        locksroot=merkle_tree.merkleroot,
        recipient=privatekey_to_address(pkey1))

    address = privatekey_to_address(pkey0)
    sign_key = PrivateKey(pkey0)
    direct_transfer.sign(sign_key, address)

    direct_transfer_data = str(direct_transfer.packed().data)
    nettingchannel.close(direct_transfer_data, sender=pkey1)

    for lock in locks:
        secret = HASHLOCKS_SECRESTS[lock.hashlock]

        lock_encoded = lock.as_bytes
        merkle_proof = merkle_tree.make_proof(sha3(lock_encoded))

        # withdraw must fail regardless of which part of the proof is tampered
        for pos, hash_ in enumerate(merkle_proof):
            # changing arbitrary bytes from the proof
            tampered_hash = bytearray(hash_)
            tampered_hash[5], tampered_hash[6] = tampered_hash[
                6], tampered_hash[5]

            tampered_proof = list(merkle_proof)
            tampered_proof[pos] = str(tampered_hash)

            with pytest.raises(TransactionFailed):
                nettingchannel.withdraw(
                    lock_encoded,
                    ''.join(tampered_proof),
                    secret,
                    sender=pkey1,
                )
Exemplo n.º 9
0
    def create_secret(self, identifier, secret):
        hashlock = sha3(secret)

        from_ = self.our_state

        lock = from_.balance_proof.get_lock_by_hashlock(hashlock)
        lockhashed = sha3(lock.as_bytes)
        leafs = from_.balance_proof.unclaimed_merkletree()
        leafs.remove(lockhashed)

        locksroot_with_pending_lock_removed = Merkletree(
            leafs).merkleroot or EMPTY_MERKLE_ROOT
        transferred_amount = from_.transferred_amount + lock.amount

        nonce = self.get_next_nonce()

        secret = Secret(
            identifier,
            nonce,
            self.channel_address,
            transferred_amount,
            locksroot_with_pending_lock_removed,
            secret,
        )
        return secret
Exemplo n.º 10
0
    def compute_proof_for_lock(self, secret, lock):
        alllocks = chain(self.hashlock_pendinglocks.values(),
                         self.hashlock_unclaimedlocks.values(),
                         self.hashlock_unlockedlocks.values())

        # forcing bytes because ethereum.abi doesnt work with bytearray
        lock_encoded = bytes(lock.as_bytes)
        lock_hash = sha3(lock_encoded)

        tree = Merkletree(lock.lockhashed for lock in alllocks)
        merkle_proof = tree.make_proof(lock_hash)

        return UnlockProof(
            merkle_proof,
            lock_encoded,
            secret,
        )
Exemplo n.º 11
0
    def compute_merkleroot_with(self, include):
        """ Compute the resulting merkle root if the lock `include` is added in
        the tree.
        """
        leafs = self.balance_proof.unclaimed_merkletree()
        leafs.append(sha3(include.as_bytes))
        locksroot = Merkletree(leafs).merkleroot

        return locksroot
Exemplo n.º 12
0
def test_two():
    hash_0 = 'a' * 32
    hash_1 = 'b' * 32

    leaves = [hash_0, hash_1]

    tree = Merkletree(leaves)
    merkle_root = tree.merkleroot
    merkle_proof0 = tree.make_proof(hash_0)

    assert merkle_proof0 == [hash_1]
    assert merkle_root == keccak(hash_0 + hash_1)
    assert check_proof(merkle_proof0, merkle_root, hash_0)

    merkle_proof1 = tree.make_proof(hash_1)

    assert merkle_proof1 == [hash_0]
    assert merkle_root == keccak(hash_0 + hash_1)
    assert check_proof(merkle_proof1, merkle_root, hash_1)
def test_merkle_proof(tree, tester_state,
                      tester_nettingchannel_library_address):
    """ computeMerkleRoot and the python implementation must compute the same value. """

    auxiliary = deploy_auxiliary_tester(tester_state,
                                        tester_nettingchannel_library_address)

    hashes = [sha3(element) for element in tree]
    merkle_tree = Merkletree(hashes)

    for element in tree:
        proof = merkle_tree.make_proof(sha3(element))

        smart_contact_root = auxiliary.computeMerkleRoot(
            element,
            ''.join(proof),
        )

        assert smart_contact_root == merkle_tree.merkleroot
Exemplo n.º 14
0
def do_test_speed(rounds=100, num_hashes=1000):
    values = [keccak(str(i)) for i in range(num_hashes)]

    start_time = time.time()
    for __ in range(rounds):
        Merkletree(values).merkleroot

    elapsed = time.time() - start_time

    print '%d additions per second' % (num_hashes * rounds / elapsed)
Exemplo n.º 15
0
def assert_locked(channel0, outstanding_locks):
    """ Assert the locks create from `channel`. """
    # a locked transfer is registered in the _partner_ state
    hashroot = Merkletree(sha3(lock.as_bytes) for lock in outstanding_locks).merkleroot

    assert len(channel0.our_state.balance_proof.hashlock_pendinglocks) == len(outstanding_locks)
    assert channel0.our_state.balance_proof.merkleroot_for_unclaimed() == hashroot
    assert channel0.our_state.locked() == sum(lock.amount for lock in outstanding_locks)
    assert channel0.outstanding == sum(lock.amount for lock in outstanding_locks)

    for lock in outstanding_locks:
        assert lock.hashlock in channel0.our_state.balance_proof.hashlock_pendinglocks
Exemplo n.º 16
0
def assert_locked(from_channel, pending_locks):
    """ Assert the locks created from `from_channel`. """
    # a locked transfer is registered in the _partner_ state
    leafs = [sha3(lock.as_bytes) for lock in pending_locks]
    hashroot = Merkletree(leafs).merkleroot

    assert len(from_channel.our_state.balance_proof.hashlocks_to_pendinglocks) == len(
        pending_locks
    )
    assert from_channel.our_state.balance_proof.merkleroot_for_unclaimed() == hashroot
    assert from_channel.our_state.locked() == sum(lock.amount for lock in pending_locks)
    assert from_channel.locked == sum(lock.amount for lock in pending_locks)

    for lock in pending_locks:
        assert lock.hashlock in from_channel.our_state.balance_proof.hashlocks_to_pendinglocks
Exemplo n.º 17
0
    def register_balanceproof_with_lock(self, balance_proof, lock):
        lockhashed = sha3(lock.as_bytes)

        if not isinstance(balance_proof, BalanceProofState):
            raise ValueError('balance_proof must be a BalanceProof instance')

        if self.is_known(lock.hashlock):
            raise ValueError('hashlock is already registered')

        leafs = self.unclaimed_merkletree()
        leafs.append(lockhashed)
        new_locksroot = Merkletree(leafs).merkleroot

        if balance_proof.locksroot != new_locksroot:
            raise InvalidLocksRoot(new_locksroot, balance_proof.locksroot)

        self.hashlocks_to_pendinglocks[lock.hashlock] = PendingLock(
            lock, lockhashed)
        self.balance_proof = balance_proof
Exemplo n.º 18
0
    def register_balanceproof_without_lock(self, balance_proof, lock):
        lockhashed = sha3(lock.as_bytes)

        if not isinstance(balance_proof, BalanceProofState):
            raise ValueError('balance_proof must be a BalanceProof instance')

        if not self.is_known(lock.hashlock):
            raise ValueError('hashlock is not registered')

        leaves = self.unclaimed_merkletree()
        leaves.remove(lockhashed)
        new_locksroot = Merkletree(leaves).merkleroot

        if balance_proof.locksroot != new_locksroot:
            raise InvalidLocksRoot(new_locksroot, balance_proof.locksroot)

        if lock.hashlock in self.hashlocks_to_pendinglocks:
            del self.hashlocks_to_pendinglocks[lock.hashlock]
        else:
            del self.hashlocks_to_unclaimedlocks[lock.hashlock]

        self.balance_proof = balance_proof
Exemplo n.º 19
0
    def register_locked_transfer(self, locked_transfer):
        if not isinstance(locked_transfer, LockedTransfer):
            raise ValueError('transfer must be a LockedTransfer')

        lock = locked_transfer.lock
        lockhashed = sha3(lock.as_bytes)

        if self.is_known(lock.hashlock):
            raise ValueError('hashlock is already registered')

        leafs = self.unclaimed_merkletree()
        leafs.append(lockhashed)
        new_locksroot = Merkletree(leafs).merkleroot

        if locked_transfer.locksroot != new_locksroot:
            raise ValueError('locksroot mismatch expected:{} got:{}'.format(
                pex(new_locksroot),
                pex(locked_transfer.locksroot),
            ))

        self.hashlocks_to_pendinglocks[lock.hashlock] = PendingLock(
            lock, lockhashed)
        self.transfer = locked_transfer
        self.hashlocks_to_unlockedlocks = dict()
Exemplo n.º 20
0
def test_empty():
    assert Merkletree([]).merkleroot == EMPTY_MERKLE_ROOT
Exemplo n.º 21
0
 def generate_merkle_tree(self):
     alllocks = chain(self.hashlocks_to_pendinglocks.values(),
                      self.hashlocks_to_unclaimedlocks.values(),
                      self.hashlocks_to_unlockedlocks.values())
     return Merkletree(lock.lockhashed for lock in alllocks)
Exemplo n.º 22
0
    def merkleroot_for_unclaimed(self):
        alllocks = chain(self.hashlocks_to_pendinglocks.values(),
                         self.hashlocks_to_unclaimedlocks.values())

        tree = Merkletree(lock.lockhashed for lock in alllocks)
        return tree.merkleroot
Exemplo n.º 23
0
def test_sender_cannot_overspend():
    token_address = make_address()
    privkey1, address1 = make_privkey_address()
    address2 = make_address()

    balance1 = 70
    balance2 = 110

    reveal_timeout = 5
    settle_timeout = 15
    block_number = 10

    our_state = ChannelEndState(address1, balance1, BalanceProof(None))
    partner_state = ChannelEndState(address2, balance2, BalanceProof(None))
    external_state = make_external_state()

    test_channel = Channel(
        our_state,
        partner_state,
        external_state,
        token_address,
        reveal_timeout,
        settle_timeout,
    )

    amount = balance1
    expiration = block_number + settle_timeout
    sent_mediated_transfer0 = test_channel.create_mediatedtransfer(
        address1,
        address2,
        fee=0,
        amount=amount,
        identifier=1,
        expiration=expiration,
        hashlock=sha3('test_locked_amount_cannot_be_spent'),
    )
    sent_mediated_transfer0.sign(privkey1, address1)

    test_channel.register_transfer(
        block_number,
        sent_mediated_transfer0,
    )

    lock2 = Lock(
        amount=amount,
        expiration=expiration,
        hashlock=sha3('test_locked_amount_cannot_be_spent2'),
    )
    locksroot2 = Merkletree([
        sha3(sent_mediated_transfer0.lock.as_bytes),
        sha3(lock2.as_bytes),
    ]).merkleroot

    sent_mediated_transfer1 = MediatedTransfer(
        identifier=2,
        nonce=sent_mediated_transfer0.nonce + 1,
        token=token_address,
        channel=test_channel.channel_address,
        transferred_amount=0,
        recipient=address2,
        locksroot=locksroot2,
        lock=lock2,
        target=address2,
        initiator=address1,
        fee=0,
    )
    sent_mediated_transfer1.sign(privkey1, address1)

    # address1 balance is all locked
    with pytest.raises(InsufficientBalance):
        test_channel.register_transfer(
            block_number,
            sent_mediated_transfer1,
        )
Exemplo n.º 24
0
def test_empty():
    assert Merkletree([]).merkleroot == ''
Exemplo n.º 25
0
def test_receiver_cannot_spend_locked_amount():
    token_address = make_address()
    privkey1, address1 = make_privkey_address()
    privkey2, address2 = make_privkey_address()

    balance1 = 33
    balance2 = 11

    reveal_timeout = 7
    settle_timeout = 21
    block_number = 7

    our_state = ChannelEndState(address1, balance1, BalanceProof(None))
    partner_state = ChannelEndState(address2, balance2, BalanceProof(None))
    external_state = make_external_state()

    test_channel = Channel(
        our_state,
        partner_state,
        external_state,
        token_address,
        reveal_timeout,
        settle_timeout,
    )

    amount1 = balance2
    expiration = block_number + settle_timeout
    receive_mediated_transfer0 = test_channel.create_mediatedtransfer(
        address1,
        address2,
        fee=0,
        amount=amount1,
        identifier=1,
        expiration=expiration,
        hashlock=sha3('test_locked_amount_cannot_be_spent'),
    )
    receive_mediated_transfer0.sign(privkey2, address2)

    test_channel.register_transfer(
        block_number,
        receive_mediated_transfer0,
    )

    # trying to send one unit of the locked token
    amount2 = balance1 + 1
    lock2 = Lock(
        amount=amount2,
        expiration=expiration,
        hashlock=sha3('test_locked_amount_cannot_be_spent2'),
    )
    locksroot2 = Merkletree([sha3(lock2.as_bytes)]).merkleroot

    send_mediated_transfer0 = MediatedTransfer(
        identifier=1,
        nonce=1,
        token=token_address,
        channel=test_channel.channel_address,
        transferred_amount=0,
        recipient=address2,
        locksroot=locksroot2,
        lock=lock2,
        target=address2,
        initiator=address1,
        fee=0,
    )
    send_mediated_transfer0.sign(privkey1, address1)

    # address1 balance is all locked
    with pytest.raises(InsufficientBalance):
        test_channel.register_transfer(
            block_number,
            send_mediated_transfer0,
        )
Exemplo n.º 26
0
 def generate_merkle_tree(self):
     all_lockhashes = self.unclaimed_merkletree()
     return Merkletree(all_lockhashes)
Exemplo n.º 27
0
def test_non_hash():
    with pytest.raises(HashLengthNot32):
        Merkletree(['not32bytes', 'neither'])

    with pytest.raises(HashLengthNot32):
        assert Merkletree(['']).merkleroot == ''
Exemplo n.º 28
0
def test_single():
    hash_0 = keccak('x')
    assert Merkletree([hash_0]).merkleroot == hash_0