This commit is contained in:
diminator 2016-03-18 20:20:18 +01:00
parent 9bd1e9ff8b
commit bdc2475bdd
4 changed files with 61 additions and 59 deletions

View File

@ -50,11 +50,11 @@ class Condition(metaclass=ABCMeta):
@staticmethod
def from_binary(reader):
"""
* Create a Condition object from a binary blob.
*
* This method will parse a stream of binary data and construct a
* corresponding Condition object.
*
Create a Condition object from a binary blob.
This method will parse a stream of binary data and construct a
corresponding Condition object.
Args:
reader (Reader): Binary stream implementing the Reader interface
Returns:
@ -207,14 +207,13 @@ class Condition(metaclass=ABCMeta):
writer.write_var_uint(self.max_fulfillment_length)
return b''.join(writer.components)
def parse_binary(self, reader):
"""
* Parse any condition in binary format.
*
* Will populate the condition object with data from the provided binary
* stream.
*
Parse any condition in binary format.
Will populate the condition object with data from the provided binary
stream.
Args:
reader (Reader): Binary stream containing the condition.
"""

View File

@ -52,7 +52,8 @@ class ThresholdSha256Fulfillment(BaseSha256Fulfillment):
This method returns the subconditions plus all subfulfillments, converted to conditions.
@return {Condition[]} Set of subconditions
Returns:
[Condition]: Set of subconditions
"""
return self.subconditions + [f.condition for f in self.subfulfillments]
@ -84,7 +85,8 @@ class ThresholdSha256Fulfillment(BaseSha256Fulfillment):
validate this fulfillment. Therefore, we need to calculate the bitwise OR
of this condition's TYPE_BIT and all subcondition's and subfulfillment's bitmasks.
@return {Number} Complete bitmask for this fulfillment.
Returns:
int: Complete bitmask for this fulfillment.
"""
bitmask = self._bitmask
@ -140,7 +142,8 @@ class ThresholdSha256Fulfillment(BaseSha256Fulfillment):
however, it does not need to provide the exact worst-case fulfillment
length, only an upper bound for it.
@return {Number} Maximum length of the fulfillment payload
Return:
int Maximum length of the fulfillment payload
"""
# TODO: Currently wrong
@ -243,7 +246,8 @@ class ThresholdSha256Fulfillment(BaseSha256Fulfillment):
This will validate the subfulfillments and verify that there are enough
subfulfillments to meet the threshold.
@return {Boolean} Whether this fulfillment is valid.
Returns:
boolean: Whether this fulfillment is valid.
"""
validations = [f.validate() for f in self.subfulfillments]
return len([v for v in validations]) >= self.threshold

View File

@ -9,10 +9,10 @@ from six import string_types
MSB = 0x80
REST = 0x7F
MSBALL = ~REST
INT = 2**31
INT = 2 ** 31
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
MAX_SAFE_INTEGER = 2**53-1
MAX_SAFE_INTEGER = 2 ** 53 - 1
class UnsignedLEB128:
@ -27,6 +27,7 @@ class UnsignedLEB128:
see http://grokbase.com/t/python/python-list/112e5jpc16/encoding
"""
@staticmethod
def encode(obj):
out = []
@ -51,7 +52,6 @@ class UnsignedLEB128:
class Writer:
def __init__(self):
self.components = []
@ -96,17 +96,13 @@ class Writer:
class Hasher(Writer):
def __init__(self):
self.hash = None
super().__init__()
def __init__(self, algorithm):
if algorithm == 'sha256':
self.hash = hashlib.sha256()
else:
raise NotImplementedError
super(Writer, self).__init__()
super().__init__()
def write(self, in_bytes):
"""
Adds bytes to the hash input.
@ -151,7 +147,6 @@ class Hasher(Writer):
class Predictor:
def __init__(self):
self.size = 0
@ -166,7 +161,7 @@ class Predictor:
Args:
val (int): Integer to be encoded
"""
if val == 0:
self.size += 1
elif val < 0:
@ -200,7 +195,6 @@ class Predictor:
class Reader:
def __init__(self, buffer):
self.buffer = buffer
self.cursor = 0
@ -294,18 +288,18 @@ class Reader:
"""
shift = 0
result = 0
while True:
in_byte = self.read_uint8()
result += (in_byte & REST) << shift if shift < 28 else (in_byte & REST) * (2 ** shift)
shift += 7
# Don't allow numbers greater than Number.MAX_SAFE_INTEGER
if shift > 45:
raise ValueError('Too large variable integer')
if not (in_byte & MSB):
break
@ -320,7 +314,7 @@ class Reader:
self.bookmark()
value = self.read_var_uint()
self.restore()
return value
def skip_var_uint(self):
@ -339,7 +333,7 @@ class Reader:
Return: {Buffer} Contents of the VARBYTES.
"""
return self.read(self.read_var_uint())
def peek_var_bytes(self):
"""
Read a VARBYTES, but do not advance cursor position.
@ -372,12 +366,12 @@ class Reader:
Contents of bytes read.
"""
self.ensure_available(num_bytes)
value = self.buffer[self.cursor:self.cursor + num_bytes]
self.cursor += num_bytes
return value
def peek(self, num_bytes):
"""
Read bytes, but do not advance cursor.
@ -403,7 +397,7 @@ class Reader:
num_bytes (int): Number of bytes to advance the cursor by.
"""
self.ensure_available(num_bytes)
self.cursor += num_bytes

View File

@ -1,6 +1,6 @@
import binascii
from math import floor, ceil
from math import ceil
import pytest
@ -125,6 +125,7 @@ class TestBigchainILPEd25519Sha256Fulfillment:
def test_deserialize_fulfillment(self):
fulfillment = Fulfillment.from_uri(self.FULFILLMENT_ED25519_ILP)
assert isinstance(fulfillment, Ed25519Sha256Fulfillment)
assert fulfillment.serialize_uri() == self.FULFILLMENT_ED25519_ILP
assert fulfillment.condition.serialize_uri() == self.CONDITION_ED25519_ILP
assert binascii.hexlify(fulfillment.condition.hash) == self.HASH_ED25519_HEX_ILP
@ -145,6 +146,7 @@ class TestBigchainILPEd25519Sha256Fulfillment:
assert fulfillment.validate()
deserialized_fulfillment = Fulfillment.from_uri(fulfillment.serialize_uri())
assert isinstance(deserialized_fulfillment, Ed25519Sha256Fulfillment)
assert deserialized_fulfillment.serialize_uri() == fulfillment.serialize_uri()
assert deserialized_fulfillment.condition.serialize_uri() == fulfillment.condition.serialize_uri()
assert deserialized_fulfillment.public_key.public_key.to_bytes() == fulfillment.public_key.public_key.to_bytes()
@ -195,14 +197,14 @@ class TestBigchainILPThresholdSha256Fulfillment:
assert ilp_fulfillment.validate() == True
assert ilp_fulfillment_2.validate() == True
THRESHOLD = 2
threshold = 2
# Create a threshold condition
fulfillment = ThresholdSha256Fulfillment()
fulfillment.add_subfulfillment(ilp_fulfillment)
fulfillment.add_subfulfillment(ilp_fulfillment_2)
fulfillment.add_subfulfillment(ilp_fulfillment_3)
fulfillment.threshold = THRESHOLD # defaults to subconditions.length
fulfillment.threshold = threshold # defaults to subconditions.length
assert fulfillment.condition.serialize_uri() == self.CONDITION_THRESHOLD_ED25519_ILP_2
# Note: If there are more than enough fulfilled subconditions, shorter
@ -212,13 +214,14 @@ class TestBigchainILPThresholdSha256Fulfillment:
assert fulfillment.validate()
def test_deserialize_fulfillment(self):
NUM_FULFILLMENTS = 3
THRESHOLD = 2
num_fulfillments = 3
threshold = 2
fulfillment = Fulfillment.from_uri(self.FULFILLMENT_THRESHOLD_ED25519_ILP_2)
assert fulfillment.threshold == THRESHOLD
assert len(fulfillment.subfulfillments) == THRESHOLD
assert len(fulfillment.get_all_subconditions()) == NUM_FULFILLMENTS
assert isinstance(fulfillment, ThresholdSha256Fulfillment)
assert fulfillment.threshold == threshold
assert len(fulfillment.subfulfillments) == threshold
assert len(fulfillment.get_all_subconditions()) == num_fulfillments
assert fulfillment.serialize_uri() == self.FULFILLMENT_THRESHOLD_ED25519_ILP_2
assert fulfillment.validate()
assert isinstance(fulfillment.subfulfillments[0], Sha256Fulfillment)
@ -228,35 +231,36 @@ class TestBigchainILPThresholdSha256Fulfillment:
def test_serialize_deserialize_fulfillment(self):
ilp_fulfillment = Fulfillment.from_uri(self.FULFILLMENT_ED25519_ILP)
NUM_FULFILLMENTS = 100
THRESHOLD = ceil(NUM_FULFILLMENTS * 2 / 3)
num_fulfillments = 100
threshold = ceil(num_fulfillments * 2 / 3)
# Create a threshold condition
fulfillment = ThresholdSha256Fulfillment()
for i in range(NUM_FULFILLMENTS):
for i in range(num_fulfillments):
fulfillment.add_subfulfillment(ilp_fulfillment)
fulfillment.threshold = THRESHOLD
fulfillment.threshold = threshold
fulfillment_uri = fulfillment.serialize_uri()
assert fulfillment.validate()
deserialized_fulfillment = Fulfillment.from_uri(fulfillment_uri)
assert deserialized_fulfillment.threshold == THRESHOLD
assert len(deserialized_fulfillment.subfulfillments) == THRESHOLD
assert len(deserialized_fulfillment.get_all_subconditions()) == NUM_FULFILLMENTS
assert isinstance(deserialized_fulfillment, ThresholdSha256Fulfillment)
assert deserialized_fulfillment.threshold == threshold
assert len(deserialized_fulfillment.subfulfillments) == threshold
assert len(deserialized_fulfillment.get_all_subconditions()) == num_fulfillments
assert deserialized_fulfillment.serialize_uri() == fulfillment_uri
assert deserialized_fulfillment.validate()
def test_fulfillment_didnt_reach_threshold(self):
ilp_fulfillment = Fulfillment.from_uri(self.FULFILLMENT_ED25519_ILP)
THRESHOLD = 10
threshold = 10
# Create a threshold condition
fulfillment = ThresholdSha256Fulfillment()
fulfillment.threshold = THRESHOLD
fulfillment.threshold = threshold
for i in range(THRESHOLD - 1):
for i in range(threshold - 1):
fulfillment.add_subfulfillment(ilp_fulfillment)
with pytest.raises(ValueError):
@ -271,8 +275,9 @@ class TestBigchainILPThresholdSha256Fulfillment:
deserialized_fulfillment = Fulfillment.from_uri(fulfillment_uri)
assert deserialized_fulfillment.threshold == THRESHOLD
assert len(deserialized_fulfillment.subfulfillments) == THRESHOLD
assert len(deserialized_fulfillment.get_all_subconditions()) == THRESHOLD
assert isinstance(deserialized_fulfillment, ThresholdSha256Fulfillment)
assert deserialized_fulfillment.threshold == threshold
assert len(deserialized_fulfillment.subfulfillments) == threshold
assert len(deserialized_fulfillment.get_all_subconditions()) == threshold
assert deserialized_fulfillment.serialize_uri() == fulfillment_uri
assert deserialized_fulfillment.validate()