mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Move common code to util module
This commit is contained in:
parent
6614f7a102
commit
b3b54e7529
@ -1,12 +1,11 @@
|
||||
import rethinkdb as r
|
||||
import time
|
||||
import random
|
||||
import json
|
||||
import rapidjson
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import bigchaindb
|
||||
from bigchaindb import util
|
||||
from bigchaindb import config_utils
|
||||
from bigchaindb import exceptions
|
||||
from bigchaindb.crypto import hash_data, PublicKey, PrivateKey, generate_key_pair
|
||||
@ -16,10 +15,6 @@ class GenesisBlockAlreadyExistsError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class KeypairNotFoundException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Bigchain(object):
|
||||
"""Bigchain API
|
||||
|
||||
@ -55,7 +50,7 @@ class Bigchain(object):
|
||||
self.federation_nodes = keyring or bigchaindb.config['keyring']
|
||||
|
||||
if not self.me or not self.me_private:
|
||||
raise KeypairNotFoundException()
|
||||
raise exceptions.KeypairNotFoundException()
|
||||
|
||||
self._conn = None
|
||||
|
||||
@ -100,7 +95,7 @@ class Bigchain(object):
|
||||
data = None
|
||||
if payload is not None:
|
||||
if isinstance(payload, dict):
|
||||
hash_payload = hash_data(self.serialize(payload))
|
||||
hash_payload = hash_data(util.serialize(payload))
|
||||
data = {
|
||||
'hash': hash_payload,
|
||||
'payload': payload
|
||||
@ -108,7 +103,7 @@ class Bigchain(object):
|
||||
else:
|
||||
raise TypeError('`payload` must be an dict instance')
|
||||
|
||||
hash_payload = hash_data(self.serialize(payload))
|
||||
hash_payload = hash_data(util.serialize(payload))
|
||||
data = {
|
||||
'hash': hash_payload,
|
||||
'payload': payload
|
||||
@ -119,12 +114,12 @@ class Bigchain(object):
|
||||
'new_owner': new_owner,
|
||||
'input': tx_input,
|
||||
'operation': operation,
|
||||
'timestamp': self.timestamp(),
|
||||
'timestamp': util.timestamp(),
|
||||
'data': data
|
||||
}
|
||||
|
||||
# serialize and convert to bytes
|
||||
tx_serialized = self.serialize(tx)
|
||||
tx_serialized = util.serialize(tx)
|
||||
tx_hash = hash_data(tx_serialized)
|
||||
|
||||
# create the transaction
|
||||
@ -149,7 +144,7 @@ class Bigchain(object):
|
||||
|
||||
"""
|
||||
private_key = PrivateKey(private_key)
|
||||
signature = private_key.sign(self.serialize(transaction))
|
||||
signature = private_key.sign(util.serialize(transaction))
|
||||
signed_transaction = transaction.copy()
|
||||
signed_transaction.update({'signature': signature})
|
||||
return signed_transaction
|
||||
@ -175,7 +170,7 @@ class Bigchain(object):
|
||||
signature = data.pop('signature')
|
||||
public_key_base58 = signed_transaction['transaction']['current_owner']
|
||||
public_key = PublicKey(public_key_base58)
|
||||
return public_key.verify(self.serialize(data), signature)
|
||||
return public_key.verify(util.serialize(data), signature)
|
||||
|
||||
def write_transaction(self, signed_transaction):
|
||||
"""Write the transaction to bigchain.
|
||||
@ -360,7 +355,7 @@ class Bigchain(object):
|
||||
transaction['transaction']['input']))
|
||||
|
||||
# Check hash of the transaction
|
||||
calculated_hash = hash_data(self.serialize(transaction['transaction']))
|
||||
calculated_hash = hash_data(util.serialize(transaction['transaction']))
|
||||
if calculated_hash != transaction['id']:
|
||||
raise exceptions.InvalidHash()
|
||||
|
||||
@ -405,14 +400,14 @@ class Bigchain(object):
|
||||
"""
|
||||
# Create the new block
|
||||
block = {
|
||||
'timestamp': self.timestamp(),
|
||||
'timestamp': util.timestamp(),
|
||||
'transactions': validated_transactions,
|
||||
'node_pubkey': self.me,
|
||||
'voters': self.federation_nodes + [self.me]
|
||||
}
|
||||
|
||||
# Calculate the hash of the new block
|
||||
block_data = self.serialize(block)
|
||||
block_data = util.serialize(block)
|
||||
block_hash = hash_data(block_data)
|
||||
block_signature = PrivateKey(self.me_private).sign(block_data)
|
||||
|
||||
@ -439,7 +434,7 @@ class Bigchain(object):
|
||||
"""
|
||||
|
||||
# 1. Check if current hash is correct
|
||||
calculated_hash = hash_data(self.serialize(block['block']))
|
||||
calculated_hash = hash_data(util.serialize(block['block']))
|
||||
if calculated_hash != block['id']:
|
||||
raise exceptions.InvalidHash()
|
||||
|
||||
@ -531,10 +526,10 @@ class Bigchain(object):
|
||||
'previous_block': previous_block_id,
|
||||
'is_block_valid': decision,
|
||||
'invalid_reason': invalid_reason,
|
||||
'timestamp': self.timestamp()
|
||||
'timestamp': util.timestamp()
|
||||
}
|
||||
|
||||
vote_data = self.serialize(vote)
|
||||
vote_data = util.serialize(vote)
|
||||
signature = PrivateKey(self.me_private).sign(vote_data)
|
||||
|
||||
vote_signed = {
|
||||
@ -597,26 +592,6 @@ class Bigchain(object):
|
||||
|
||||
return unvoted
|
||||
|
||||
@staticmethod
|
||||
def serialize(data):
|
||||
"""Static method used to serialize a dict into a JSON formatted string.
|
||||
|
||||
This method enforces rules like the separator and order of keys. This ensures that all dicts
|
||||
are serialized in the same way.
|
||||
|
||||
This is specially important for hashing data. We need to make sure that everyone serializes their data
|
||||
in the same way so that we do not have hash mismatches for the same structure due to serialization
|
||||
differences.
|
||||
|
||||
Args:
|
||||
data (dict): dict to serialize
|
||||
|
||||
Returns:
|
||||
str: JSON formatted string
|
||||
|
||||
"""
|
||||
return json.dumps(data, skipkeys=False, ensure_ascii=False,
|
||||
separators=(',', ':'), sort_keys=True)
|
||||
|
||||
@staticmethod
|
||||
def deserialize(data):
|
||||
@ -631,17 +606,6 @@ class Bigchain(object):
|
||||
"""
|
||||
return json.loads(data, encoding="utf-8")
|
||||
|
||||
@staticmethod
|
||||
def timestamp():
|
||||
"""Static method to calculate a UTC timestamp with microsecond precision.
|
||||
|
||||
Returns:
|
||||
str: UTC timestamp.
|
||||
|
||||
"""
|
||||
dt = datetime.utcnow()
|
||||
return "{0:.6f}".format(time.mktime(dt.timetuple()) + dt.microsecond / 1e6)
|
||||
|
||||
@staticmethod
|
||||
def generate_keys():
|
||||
"""Generates a key pair.
|
||||
|
@ -25,3 +25,7 @@ class DatabaseAlreadyExists(Exception):
|
||||
class DatabaseDoesNotExist(Exception):
|
||||
"""Raised when trying to delete the database but the db is not there"""
|
||||
|
||||
class KeypairNotFoundException(Exception):
|
||||
"""Raised if operation cannot proceed because the keypair was not given"""
|
||||
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
import multiprocessing as mp
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class ProcessGroup(object):
|
||||
@ -22,3 +25,35 @@ class ProcessGroup(object):
|
||||
proc.start()
|
||||
self.processes.append(proc)
|
||||
|
||||
|
||||
def serialize(data):
|
||||
"""Function used to serialize a dict into a JSON formatted string.
|
||||
|
||||
This function enforces rules like the separator and order of keys. This ensures that all dicts
|
||||
are serialized in the same way.
|
||||
|
||||
This is specially important for hashing data. We need to make sure that everyone serializes their data
|
||||
in the same way so that we do not have hash mismatches for the same structure due to serialization
|
||||
differences.
|
||||
|
||||
Args:
|
||||
data (dict): dict to serialize
|
||||
|
||||
Returns:
|
||||
str: JSON formatted string
|
||||
|
||||
"""
|
||||
return json.dumps(data, skipkeys=False, ensure_ascii=False,
|
||||
separators=(',', ':'), sort_keys=True)
|
||||
|
||||
|
||||
def timestamp():
|
||||
"""Function to calculate a UTC timestamp with microsecond precision.
|
||||
|
||||
Returns:
|
||||
str: UTC timestamp.
|
||||
|
||||
"""
|
||||
dt = datetime.utcnow()
|
||||
return "{0:.6f}".format(time.mktime(dt.timetuple()) + dt.microsecond / 1e6)
|
||||
|
||||
|
@ -6,6 +6,7 @@ import pytest
|
||||
import rethinkdb as r
|
||||
|
||||
import bigchaindb
|
||||
from bigchaindb import util
|
||||
from bigchaindb import exceptions
|
||||
from bigchaindb import Bigchain
|
||||
from bigchaindb.crypto import hash_data, PrivateKey, PublicKey, generate_key_pair
|
||||
@ -69,7 +70,7 @@ class TestBigchainApi(object):
|
||||
'operation': 'd',
|
||||
'timestamp': tx['transaction']['timestamp'],
|
||||
'data': {
|
||||
'hash': hash_data(b.serialize(payload)),
|
||||
'hash': hash_data(util.serialize(payload)),
|
||||
'payload': payload
|
||||
}
|
||||
}
|
||||
@ -86,7 +87,7 @@ class TestBigchainApi(object):
|
||||
|
||||
def test_serializer(self, b):
|
||||
tx = b.create_transaction('a', 'b', 'c', 'd')
|
||||
assert b.deserialize(b.serialize(tx)) == tx
|
||||
assert b.deserialize(util.serialize(tx)) == tx
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_write_transaction(self, b, user_public_key, user_private_key):
|
||||
@ -114,7 +115,7 @@ class TestBigchainApi(object):
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
response = b.get_transaction(tx_signed["id"])
|
||||
assert b.serialize(tx_signed) == b.serialize(response)
|
||||
assert util.serialize(tx_signed) == util.serialize(response)
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_assign_transaction_one_node(self, b, user_public_key, user_private_key):
|
||||
@ -210,11 +211,11 @@ class TestBigchainApi(object):
|
||||
|
||||
def test_create_new_block(self, b):
|
||||
new_block = b.create_block([])
|
||||
block_hash = hash_data(b.serialize(new_block['block']))
|
||||
block_hash = hash_data(util.serialize(new_block['block']))
|
||||
|
||||
assert new_block['block']['voters'] == [b.me]
|
||||
assert new_block['block']['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(new_block['block']), new_block['signature']) is True
|
||||
assert PublicKey(b.me).verify(util.serialize(new_block['block']), new_block['signature']) is True
|
||||
assert new_block['id'] == block_hash
|
||||
assert new_block['votes'] == []
|
||||
|
||||
@ -378,7 +379,7 @@ class TestBlockValidation(object):
|
||||
'voters': b.federation_nodes
|
||||
}
|
||||
|
||||
block_data = b.serialize(block)
|
||||
block_data = util.serialize(block)
|
||||
block_hash = hash_data(block_data)
|
||||
block_signature = PrivateKey(b.me_private).sign(block_data)
|
||||
|
||||
@ -491,7 +492,7 @@ class TestBigchainVoter(object):
|
||||
assert vote['vote']['is_block_valid'] is True
|
||||
assert vote['vote']['invalid_reason'] is None
|
||||
assert vote['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) is True
|
||||
assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
|
||||
|
||||
def test_invalid_block_voting(self, b, user_public_key):
|
||||
# create queue and voter
|
||||
@ -533,7 +534,7 @@ class TestBigchainVoter(object):
|
||||
assert vote['vote']['is_block_valid'] is False
|
||||
assert vote['vote']['invalid_reason'] is None
|
||||
assert vote['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) is True
|
||||
assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
|
||||
|
||||
def test_vote_creation_valid(self, b):
|
||||
# create valid block
|
||||
@ -547,7 +548,7 @@ class TestBigchainVoter(object):
|
||||
assert vote['vote']['is_block_valid'] is True
|
||||
assert vote['vote']['invalid_reason'] is None
|
||||
assert vote['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) is True
|
||||
assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
|
||||
|
||||
def test_vote_creation_invalid(self, b):
|
||||
# create valid block
|
||||
@ -561,7 +562,7 @@ class TestBigchainVoter(object):
|
||||
assert vote['vote']['is_block_valid'] is False
|
||||
assert vote['vote']['invalid_reason'] is None
|
||||
assert vote['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) is True
|
||||
assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
|
||||
|
||||
|
||||
class TestBigchainBlock(object):
|
||||
|
@ -4,6 +4,7 @@ import rethinkdb as r
|
||||
import multiprocessing as mp
|
||||
|
||||
from bigchaindb import Bigchain
|
||||
from bigchaindb import util
|
||||
from bigchaindb.voter import Voter, BlockStream
|
||||
from bigchaindb.crypto import PublicKey
|
||||
|
||||
@ -45,7 +46,7 @@ class TestBigchainVoter(object):
|
||||
assert vote['vote']['is_block_valid'] is True
|
||||
assert vote['vote']['invalid_reason'] is None
|
||||
assert vote['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) is True
|
||||
assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
|
||||
|
||||
|
||||
def test_invalid_block_voting(self, b, user_public_key):
|
||||
@ -86,7 +87,7 @@ class TestBigchainVoter(object):
|
||||
assert vote['vote']['is_block_valid'] is False
|
||||
assert vote['vote']['invalid_reason'] is None
|
||||
assert vote['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) is True
|
||||
assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
|
||||
|
||||
def test_vote_creation_valid(self, b):
|
||||
# create valid block
|
||||
@ -100,7 +101,7 @@ class TestBigchainVoter(object):
|
||||
assert vote['vote']['is_block_valid'] is True
|
||||
assert vote['vote']['invalid_reason'] is None
|
||||
assert vote['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) is True
|
||||
assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
|
||||
|
||||
def test_vote_creation_invalid(self, b):
|
||||
# create valid block
|
||||
@ -114,7 +115,7 @@ class TestBigchainVoter(object):
|
||||
assert vote['vote']['is_block_valid'] is False
|
||||
assert vote['vote']['invalid_reason'] is None
|
||||
assert vote['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) is True
|
||||
assert PublicKey(b.me).verify(util.serialize(vote['vote']), vote['signature']) is True
|
||||
|
||||
def test_voter_considers_unvoted_blocks_when_single_node(self, b):
|
||||
# simulate a voter going donw in a single node environment
|
||||
|
@ -3,6 +3,7 @@ import copy
|
||||
import pytest
|
||||
|
||||
import bigchaindb
|
||||
from bigchaindb import exceptions
|
||||
|
||||
|
||||
ORIGINAL_CONFIG = copy.deepcopy(bigchaindb.config)
|
||||
@ -34,5 +35,5 @@ def test_bigchain_instance_raises_when_not_configured(monkeypatch):
|
||||
# from existing configurations
|
||||
monkeypatch.setattr(config_utils, 'autoconfigure', lambda: 0)
|
||||
|
||||
with pytest.raises(bigchaindb.core.KeypairNotFoundException):
|
||||
with pytest.raises(exceptions.KeypairNotFoundException):
|
||||
bigchaindb.Bigchain()
|
||||
|
Loading…
x
Reference in New Issue
Block a user