def create_block(self, moves, commit=True, click=None): """ Create a block. """ for move in moves: if not move.valid: raise InvalidMoveError(move) block = Block(version=PROTOCOL_VERSION) block.root_hash = h(''.join(sorted( (m.id for m in moves))).encode('utf-8')).hexdigest() block.creator = self.address block.created_at = datetime.datetime.utcnow() prev_block = self.session.query(Block).order_by( Block.id.desc()).first() if prev_block: block.id = prev_block.id + 1 block.prev_hash = prev_block.hash block.difficulty = prev_block.difficulty difficulty_check_block = self.session.query(Block).get( max(1, block.id - 10)) avg_timedelta = ( (block.created_at - difficulty_check_block.created_at) / (block.id - difficulty_check_block.id)) if click: click.echo( f'avg: {avg_timedelta}, difficulty: {block.difficulty}') if avg_timedelta <= datetime.timedelta(0, 5): block.difficulty = max(0, block.difficulty + 1) elif avg_timedelta > datetime.timedelta(0, 15): block.difficulty = max(0, block.difficulty - 1) else: #: Genesis block block.id = 1 block.prev_hash = None block.difficulty = 0 block.suffix = hashcash._mint(block.serialize(), bits=block.difficulty) if self.session.query(Block).get(block.id): return None block.hash = h(block.serialize() + block.suffix).hexdigest() for move in moves: move.block = block if not block.valid: raise InvalidBlockError if commit: try: self.session.add(block) self.session.commit() except IntegrityError: return None return block
def test_mint(challenge, bits): answer = _mint(challenge, bits) stamp = challenge + answer digest = hashlib.sha256(stamp) assert has_leading_zero_bits(digest.digest(), bits) assert check(stamp)