12 Commits

Author SHA1 Message Date
15cac7d390 Merge pull request #5 from datpy/move-to-generators
Move naming to generator
2019-10-08 22:45:45 +02:00
c470b70722 Remove base python restrictions 2019-10-08 22:36:03 +02:00
9a651a9d3d Clean up formatting on CoC 2019-10-08 22:36:03 +02:00
a293d4bada Move naming to Generator (reflect reality)
Closes https://github.com/datpy/merkle-tree-stream/issues/4.
2019-10-08 22:36:03 +02:00
71526e64aa Merge pull request #3 from datpy/cleanups-gardening
Meta/Docs cleanup and bytes fix
2019-10-06 16:19:47 +02:00
173c911f28 Inline tox defs 2019-10-06 16:12:49 +02:00
896afc7675 Handle versions better 2019-10-06 16:12:37 +02:00
af31c92fa6 Make towncrier work 2019-10-06 16:12:27 +02:00
3a0da1e2d6 Add example and fix links 2019-10-06 16:12:19 +02:00
de42d4f509 Simplify contrib docs 2019-10-06 16:12:11 +02:00
dd1c0776b2 Return bytes instead of str
Closes https://github.com/datpy/merkle-tree-stream/issues/2.
2019-10-06 16:11:49 +02:00
1c4fe9533f Mark envs with version only 2019-10-06 16:11:27 +02:00
13 changed files with 131 additions and 136 deletions

View File

@ -3,9 +3,9 @@ language: python
matrix:
include:
- python: 3.6
env: TOXENV=py36-test
env: TOXENV=py36
- python: 3.7
env: TOXENV=py37-test
env: TOXENV=py37
- python: 3.7
env: TOXENV=lint
- python: 3.7

View File

@ -1,3 +1,21 @@
Merkle_Tree_Stream 0.0.1a3 (2019-10-08)
=======================================
Bug Fixes
---------
- MerkleTreeIterator -> MerkleTreeGenerator
Merkle_Tree_Stream 0.0.1a2 (2019-10-06)
=======================================
Bug Fixes
---------
- MerkleTreeIterator leaf and parent functions now return bytes.
Merkle_Tree_Stream 0.0.1a1 (2019-08-07)
=======================================

View File

@ -1,28 +1,28 @@
Introduction
------------
The DatPy community is committed to providing an inclusive,
safe, and collaborative environment for all participants, regardless of their
gender, gender expression, race, ethnicity, religion, sexual orientation,
sexual characteristics, physical appearance, disability, or age. We encourage
every participant to be themselves, and must respect the rights of others. The
code of conduct is a set of guidelines that establishes shared values and
ensures that behaviors that may harm participants are avoided.
The DatPy community is committed to providing an inclusive, safe, and
collaborative environment for all participants, regardless of their gender,
gender expression, race, ethnicity, religion, sexual orientation, sexual
characteristics, physical appearance, disability, or age. We encourage every
participant to be themselves, and must respect the rights of others. The code
of conduct is a set of guidelines that establishes shared values and ensures
that behaviors that may harm participants are avoided.
The values of the DatPy community are focused on developing
both our individual and collective potential, supporting and empowering the
most marginalized, mutual respect, and an anti-violence approach that favors
support and collaboration among participants and the resolution of conflicts. A
code of conduct helps us co-exist in a more positive way and provides
individuals who are victims of negative behaviors with confidence that they
will be supported by the organization and the DatPy
community, who respects and stands behind the code of conduct.
The values of the DatPy community are focused on developing both our individual
and collective potential, supporting and empowering the most marginalized,
mutual respect, and an anti-violence approach that favors support and
collaboration among participants and the resolution of conflicts. A code of
conduct helps us co-exist in a more positive way and provides individuals who
are victims of negative behaviors with confidence that they will be supported
by the organization and the DatPy community, who respects and stands behind the
code of conduct.
The DatPy community works towards providing a welcoming
environment where participants are treated with dignity and respect and are
free to be themselves. We encourage all participants to approach the
Librehosters network with an open and positive attitude, engaging
constructively with others at all times.
The DatPy community works towards providing a welcoming environment where
participants are treated with dignity and respect and are free to be
themselves. We encourage all participants to approach the Librehosters network
with an open and positive attitude, engaging constructively with others at all
times.
Respect for Diversity & Inclusion
---------------------------------
@ -92,9 +92,9 @@ Enforcement
Overseeing the code of conduct
==============================
The DatPy community, composed of volunteers, oversees the
code of conduct, including addressing all incident reports. Breaking the code
of conduct may result in immediate expulsion from the Librehosters network.
The DatPy community, composed of volunteers, oversees the code of conduct,
including addressing all incident reports. Breaking the code of conduct may
result in immediate expulsion from the Librehosters network.
How to Report an Incident
=========================

View File

@ -1,14 +1,10 @@
Get started
-----------
Install `Tox`_ with:
Install `Tox`_.
.. _tox: http://tox.readthedocs.io/
.. code-block:: bash
$ pip install --user tox
Run tests
---------
@ -40,22 +36,6 @@ Type check source
Release Process
---------------
Add a change entry and re-generate the changelog:
.. code-block:: bash
$ towncrier
Make a new release tag:
.. code-block:: bash
$ git tag x.x.x
$ git push --tags
Then run the release process:
.. code-block:: bash
$ tox -e metadata-release
$ tox -e release

View File

@ -52,24 +52,49 @@ A note on naming
================
For the purposes of uniformity and easy of discovery alongside the reference
implementation, we use the same module name as `merkle-tree-stream`_. This may
cause confusion since it is not clear what exactly is referred to when using
the term "stream" in the context of Python. To be clear, this module provides a
`Python iterator`_ which appears to match the implementation and meaning of the
reference implementation.
implementation, we use the same module name as `merkle-tree-stream`_. However,
there is currently no stream implemented, only a generator is available. This
is because the reference implementation of Hypercore 7 makes use of the
generator only. A `stream`_ implementation may follow.
.. _merkle-tree-stream: https://github.com/mafintosh/merkle-tree-stream
.. _Python iterator: https://docs.python.org/3/c-api/iter.html
.. _stream: https://docs.python.org/3/library/asyncio-stream.html
.. _example:
.. code-block:: python
from hashlib import sha256
from merkle_tree_stream import MerkleTreeGenerator
def leaf(node, roots=None):
return sha256(node.data).digest()
def parent(first, second):
sha256 = hashlib.sha256()
sha256.update(first.data)
sha256.update(second.data)
return sha256.digest()
merkle = MerkleTreeGenerator(leaf=leaf, parent=parent)
merkle.write('hello')
merkle.write('hashed')
merkle.write('world')
.. _documentation:
Documentation
*************
* https://merkle-tree-stream.readthedocs.io/
* `merkle-tree-stream.readthedocs.io`_
.. _merkle-tree-stream.readthedocs.io: https://merkle-tree-stream.readthedocs.io/
Mirroring
*********
* https://hack.decentral1.se/datpy/merkle-tree-stream (primary)
* https://github.com/datpy/merkle-tree-stream
* `hack.decentral1.se/datpy/merkle-tree-stream`_
* `github.com/datpy/merkle-tree-stream`_
.. _hack.decentral1.se/datpy/merkle-tree-stream: https://hack.decentral1.se/datpy/merkle-tree-stream
.. _github.com/datpy/merkle-tree-stream: https://github.com/datpy/merkle-tree-stream

View File

@ -1,7 +1,7 @@
"""merkle-tree-stream module."""
from merkle_tree_stream.node import MerkleTreeNode # noqa
from merkle_tree_stream.tree import MerkleTreeIterator # noqa
from merkle_tree_stream.tree import MerkleTreeGenerator # noqa
try:
import pkg_resources

View File

@ -23,7 +23,7 @@ class MerkleTreeNode:
parent: int
size: int
data: bytes
hash: Optional[str] = attr.Factory(str)
hash: Optional[bytes] = attr.Factory(bytes)
def __attrs_post_init__(self) -> Any:
"""Initialise the parent index."""

View File

@ -1,4 +1,4 @@
"""A merkle tree iterator."""
"""A merkle tree generator."""
from typing import Any, Callable, Iterator, List
@ -7,27 +7,25 @@ from flat_tree import FlatTreeAccessor
from merkle_tree_stream.node import MerkleTreeNode
Hash = str
EMPTY_DATA = b''
EMPTY_HASH = None
__all__ = ['MerkleTreeIterator']
__all__ = ['MerkleTreeGenerator']
flat_tree = FlatTreeAccessor()
@attr.s(auto_attribs=True)
class MerkleTreeIterator:
"""A merkle tree iterator.
class MerkleTreeGenerator:
"""A merkle tree generator.
:param leaf: The leaf hash generation function
:param parent: The parent hash generation function
:param roots: The tree roots
"""
leaf: Callable[[MerkleTreeNode], Hash]
parent: Callable[[MerkleTreeNode, MerkleTreeNode], Hash]
leaf: Callable[[MerkleTreeNode], bytes]
parent: Callable[[MerkleTreeNode, MerkleTreeNode], bytes]
roots: List[MerkleTreeNode] = attr.Factory(list)
_position: int = 0

View File

@ -15,7 +15,7 @@ include = '\.pyi?$'
[tool.towncrier]
directory = "changelog/"
filename = "CHANGELOG.rst"
package = "merkle-tree-stream"
package = "merkle_tree_stream"
package_dir = "merkle_tree_stream"
[[tool.towncrier.type]]

View File

@ -37,7 +37,7 @@ install_requires =
[options]
use_scm_version = True
python_requires = !=2.7.*, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*
python_requires = >=3.6
setup_requires =
setuptools_scm
setuptools_scm_git_archive
@ -47,7 +47,7 @@ packages = find:
zip_safe = False
install_requires =
attrs >= 19.1.0, < 20.0
flat-tree == 0.0.1a3 # TODO(decentral1se): use bounds when 0.0.1 lands
flat-tree >= 0.0.1a3, < 1.0
[options.packages.find]
where = .

View File

@ -6,7 +6,7 @@ import pytest
@pytest.fixture
def leaf():
def _leaf(node, roots=None):
return hashlib.sha256(node.data).hexdigest()
return hashlib.sha256(node.data).digest()
return _leaf
@ -17,6 +17,6 @@ def parent():
sha256 = hashlib.sha256()
sha256.update(first.data)
sha256.update(second.data)
return sha256.hexdigest()
return sha256.digest()
return _parent

View File

@ -4,61 +4,53 @@ import hashlib
import pytest
from merkle_tree_stream import MerkleTreeIterator, MerkleTreeNode
from merkle_tree_stream import MerkleTreeGenerator, MerkleTreeNode
def test_hashes(leaf, parent):
merkle_iter = MerkleTreeIterator(leaf=leaf, parent=parent)
merkle = MerkleTreeGenerator(leaf=leaf, parent=parent)
merkle_iter.write(b'a')
merkle_iter.write(b'b')
merkle.write(b'a')
merkle.write(b'b')
expected_count = 2 + 1 # nodes plus parent
assert len(merkle_iter) == expected_count
assert len(merkle) == expected_count
assert next(merkle_iter) == MerkleTreeNode(
index=0,
parent=1,
hash=hashlib.sha256(b'a').hexdigest(),
size=1,
data=b'a',
assert next(merkle) == MerkleTreeNode(
index=0, parent=1, hash=hashlib.sha256(b'a').digest(), size=1, data=b'a'
)
assert next(merkle_iter) == MerkleTreeNode(
index=2,
parent=1,
hash=hashlib.sha256(b'b').hexdigest(),
size=1,
data=b'b',
assert next(merkle) == MerkleTreeNode(
index=2, parent=1, hash=hashlib.sha256(b'b').digest(), size=1, data=b'b'
)
hashed = hashlib.sha256(b'a')
hashed.update(b'b')
assert next(merkle_iter) == MerkleTreeNode(
index=1, parent=3, hash=hashed.hexdigest(), size=2, data=b''
assert next(merkle) == MerkleTreeNode(
index=1, parent=3, hash=hashed.digest(), size=2, data=b''
)
with pytest.raises(StopIteration):
next(merkle_iter)
next(merkle)
def test_single_root(leaf, parent):
merkle_iter = MerkleTreeIterator(leaf=leaf, parent=parent)
merkle = MerkleTreeGenerator(leaf=leaf, parent=parent)
merkle_iter.write(b'a')
merkle_iter.write(b'b')
merkle_iter.write(b'c')
merkle_iter.write(b'd')
merkle.write(b'a')
merkle.write(b'b')
merkle.write(b'c')
merkle.write(b'd')
assert len(merkle_iter.roots) == 1
assert len(merkle.roots) == 1
def multiple_roots(leaf, parent):
merkle_iter = MerkleTreeIterator(leaf=leaf, parent=parent)
merkle = MerkleTreeGenerator(leaf=leaf, parent=parent)
merkle_iter.write(b'a')
merkle_iter.write(b'b')
merkle_iter.write(b'c')
merkle.write(b'a')
merkle.write(b'b')
merkle.write(b'c')
assert len(merkle_iter.roots) > 1
assert len(merkle.roots) > 1

52
tox.ini
View File

@ -1,6 +1,6 @@
[tox]
envlist =
{py36,py37}-test
{py36,py37}
lint
sort
format
@ -17,70 +17,52 @@ deps =
pytest
pytest-cov
pytest-mock
commands =
pytest test/ --cov={toxinidir}/merkle_tree_stream/ --no-cov-on-fail {posargs}
commands = pytest test/ --cov={toxinidir}/merkle_tree_stream/ --no-cov-on-fail {posargs}
[testenv:lint]
description = lint the source
skipdist = True
deps =
flake8
commands =
flake8 {posargs} merkle_tree_stream/ test/
deps = flake8
commands = flake8 {posargs} merkle_tree_stream/ test/
[testenv:sort]
description = sort the source
skipdist = True
deps =
isort
commands =
isort {posargs:-rc -c} -sp setup.cfg merkle_tree_stream/ test/
deps = isort
commands = isort {posargs:-rc -c} -sp setup.cfg merkle_tree_stream/ test/
[testenv:format]
description = format the source
skipdist = True
basepython = python3.6
deps =
black
commands =
black {posargs:--check} merkle_tree_stream/ test/
deps = black
commands = black {posargs:--check} merkle_tree_stream/ test/
[testenv:type]
description = type check the source
basepython = python3.7
skipdist = True
deps =
mypy
commands =
mypy merkle_tree_stream/ test/
deps = mypy
commands = mypy merkle_tree_stream/ test/
[testenv:docs]
description = build the documentation
skipdist = True
extras =
docs
commands =
python -m setup build_sphinx
extras = docs
commands = python -m setup build_sphinx
[testenv:changelog]
description = draft the changelog
skipdist = True
extras =
changelog
commands =
towncrier --draft
extras = changelog
commands = towncrier --draft
[testenv:metadata-release]
description = validate the package metadata
deps =
twine
commands =
twine check .tox/dist/*
deps = twine
commands = twine check {toxworkdir}/dist/*
[testenv:release]
description = make a release
deps =
{[testenv:metadata-release]deps}
deps = {[testenv:metadata-release]deps}
commands =
python -m setup sdist bdist_wheel
twine upload {toxworkdir}/dist/*