def test_hash_block_stringify_error(self, mock_json_dumps): err_message = 'Could not encode block data to generate hash.' mock_json_dumps.side_effect = Mock(side_effect=BlockError(err_message)) with self.assertRaises(BlockError) as err: utils.hash_block(*self.arguments) self.assertTrue(mock_json_dumps.called) self.assertIsInstance(err, BlockError) self.assertIn(err_message, err.message)
def proof_of_work(cls, last_block: 'Block', block: dict): """ Consensus protocol requiring certain computational effort to mine a new block to be able to add it to the blockchain. The solution is then verified by the entire network. :param Block last_block: current last block of the blockchain. :param dict block: block attributes except the unknown block hash. :return dict: block data for the next block in the blockchain. """ block_values = block.values() hash = utils.hash_block(*block_values) while not utils.hex_to_binary(hash).startswith('0' * block['difficulty']): block['nonce'] += 1 block['timestamp'] = utils.get_utcnow_timestamp() block['difficulty'] = cls.adjust_difficulty(last_block, block['timestamp']) hash = utils.hash_block(*block_values) block['hash'] = hash return block
def valid_hash(cls, value: str, values: dict, field: Field): """ Validate hashes values. :param str value: provided last_hash or hash values. :param dict values: previous fields already validated. :param Field field: field name to validate its value. :return str: validated last_hash or hash value. :raise ValueError: if last_hash or hash values do not meet required conditions. """ match = re.match(r'^(?P<hash>[a-f0-9]{64})$', value) if len(value) != BLOCK_HASH_LENGTH or not match: message = f'Invalid pattern for {field.alias} value: {value}.' logger.error(f'[BlockSchema] Validation error. {message}') raise ValueError(message) if field.alias == 'hash': try: assert hex_to_binary(value).startswith('0' * values.get('difficulty')) assert value == hash_block(*values.values()) except AssertionError: message = f'Invalid hash: {value}.' logger.error(f'[BlockSchema] Validation error. {message}') raise ValueError(message) return value
from src.blockchain.models.utils import hash_block # Block BLOCK_HASH_LENGTH = 64 BLOCK_MINING_RATE = 10 * 1000 # milliseconds (10 secs) BLOCK_TIMESTAMP_LENGTH = 13 GENESIS_BLOCK = { 'index': 0, 'timestamp': 1, 'nonce': 0, 'difficulty': 1, 'data': [], 'last_hash': 'genesis_last_hash' } GENESIS_BLOCK['hash'] = hash_block(*GENESIS_BLOCK.values()) # API Server ORIGINS = [ "http://localhost:3000", ] CORS_MIDDLEWARE_PARAMS = { 'allow_origins': ORIGINS, 'allow_credentials': True, 'allow_methods': ['GET', 'POST'], 'allow_headers': ['*'] } # P2P Server HEARTBEAT_RATE = 5 # seconds
def test_hash_block_different_inputs(self): test_hash = utils.hash_block(*self.arguments) item = random.choice(self.arguments) self.arguments.remove(item) test_hash_remove = utils.hash_block(*self.arguments) self.assertNotEqual(test_hash, test_hash_remove)
def test_hash_block_same_unordered_inputs(self): test_hash = utils.hash_block(*self.arguments) test_hash_reverse = utils.hash_block(*reversed(self.arguments)) self.assertEqual(test_hash, test_hash_reverse)
def setUp(self): super(BlockUtilsTest, self).setUp() self.arguments = [ 'test_index', 'test_timestamp', 'test_data', 'test_hash' ] self.hash = utils.hash_block(self.arguments)