def test_create(self, time_mock): b = BlockHeader.create(blocknumber=1, prev_headerhash=b'headerhash', prev_timestamp=10, hashedtransactions=b'some_data', fee_reward=1) self.assertIsNotNone(b) b = BlockHeader.create(blocknumber=1, prev_headerhash=b'headerhash', prev_timestamp=10, hashedtransactions=b'some_data', fee_reward=1) self.assertEqual(b.epoch, 0)
def test_init2(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) self.assertIsNotNone(block_header) # just to avoid warnings
def test_GetBlockMiningCompatible(self): p2p_factory = Mock(spec=P2PFactory) p2p_factory.sync_state = SyncState() p2p_factory.num_connections = 23 p2p_factory.pow = Mock() chain_manager = Mock(spec=ChainManager) chain_manager.height = 0 chain_manager.get_last_block = MagicMock(return_value=Block()) qrlnode = QRLNode(mining_address=b'') qrlnode.set_chain_manager(chain_manager) qrlnode._p2pfactory = p2p_factory qrlnode._pow = p2p_factory.pow block_header = BlockHeader.create(blocknumber=10, prev_headerhash=sha256(b'prevblock'), prev_timestamp=1234567890, hashedtransactions=sha256(b'tx1'), fee_reward=1) qrlnode.get_blockheader_and_metadata = MagicMock( return_value=[block_header, BlockMetadata()]) service = MiningAPIService(qrlnode) req = qrlmining_pb2.GetBlockMiningCompatibleReq(height=10) answer = service.GetBlockMiningCompatible(request=req, context=None) self.assertEqual(10, answer.blockheader.block_number) self.assertEqual(1, answer.blockheader.reward_fee)
def create(dev_config: DevConfig, block_number: int, prev_headerhash: bytes, prev_timestamp: int, transactions: list, miner_address: bytes, seed_height: Optional[int], seed_hash: Optional[bytes]): block = Block() # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee # Prepare coinbase tx total_reward_amount = BlockHeader.block_reward_calc( block_number, dev_config) + fee_reward coinbase_tx = CoinBase.create(dev_config, total_reward_amount, miner_address, block_number) hashedtransactions.append(coinbase_tx.txhash) Block._copy_tx_pbdata_into_block( block, coinbase_tx) # copy memory rather than sym link for tx in transactions: hashedtransactions.append(tx.txhash) Block._copy_tx_pbdata_into_block( block, tx) # copy memory rather than sym link txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create(dev_config=dev_config, blocknumber=block_number, prev_headerhash=prev_headerhash, prev_timestamp=prev_timestamp, hashedtransactions=txs_hash, fee_reward=fee_reward, seed_height=seed_height, seed_hash=seed_hash) block.blockheader = tmp_blockheader block._data.header.MergeFrom(tmp_blockheader.pbdata) block.set_nonces(dev_config, 0, 0) return block
def create(block_number: int, prev_block_headerhash: bytes, prev_block_timestamp: int, transactions: list, miner_address: bytes): block = Block() # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee # Prepare coinbase tx total_reward_amount = BlockHeader.block_reward_calc( block_number) + fee_reward coinbase_tx = CoinBase.create(total_reward_amount, miner_address, block_number) hashedtransactions.append(coinbase_tx.txhash) block._data.transactions.extend([coinbase_tx.pbdata ]) # copy memory rather than sym link for tx in transactions: hashedtransactions.append(tx.txhash) block._data.transactions.extend( [tx.pbdata]) # copy memory rather than sym link txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create( blocknumber=block_number, prev_block_headerhash=prev_block_headerhash, prev_block_timestamp=prev_block_timestamp, hashedtransactions=txs_hash, fee_reward=fee_reward) block.blockheader = tmp_blockheader block._data.header.MergeFrom(tmp_blockheader.pbdata) block.set_nonces(0, 0) return block
def test_blob(self, time_mock): block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) self.assertEquals( '00501846b24200c31fca7172a7f701ae50322579cfdf1d7777daab4ce6ead70b76debb2c51a1' 'c700000000000000000000000000000000002b80aecec05ad5c7c4f2259c8f69e2966a6ce102', bin2hstr(block_header.mining_blob)) self.assertEquals(config.dev.mining_blob_size, len(block_header.mining_blob))
def test_create(self, time_mock): b = BlockHeader.create(dev_config=config.dev, blocknumber=1, prev_headerhash=b'headerhash', prev_timestamp=10, hashedtransactions=b'some_data', fee_reward=1, seed_height=0, seed_hash=None) self.assertIsNotNone(b) b = BlockHeader.create(dev_config=config.dev, blocknumber=1, prev_headerhash=b'headerhash', prev_timestamp=10, hashedtransactions=b'some_data', fee_reward=1, seed_height=0, seed_hash=None)
def test_GetLastBlockHeader(self): self.block_header_params["blocknumber"] = 20 block_header = BlockHeader.create(**self.block_header_params) self.chain_manager.height = 200 self.qrlnode.get_blockheader_and_metadata = MagicMock( return_value=[block_header, BlockMetadata()]) req = qrlmining_pb2.GetLastBlockHeaderReq(height=20) answer = self.service.GetLastBlockHeader(request=req, context=None) self.assertEqual(180, answer.depth) self.assertEqual(200, answer.height)
def test_create_fails_when_prev_timestamp_is_negative(self, time_mock): # The only way to get it to fail in this mode is to pass a negative timestamp. Which should never happen IRL. time_mock.return_value = 0 b = BlockHeader.create(config.dev, 1, sha256(b'prev'), -10, sha256(b'txs'), 10, seed_height=0, seed_hash=None) self.assertIsNone(b)
def test_blob(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), sha256(b'txs'), 10) self.assertEquals( '74aa496ffe19107faaf418b720fb5b8446ba4b595c178fcf099c99b3dee99860d788c77910a9ed000000' '000000000000000000e0d022b37421b81b7bbcf5b497fb89408c05c7d713c5e1e5187b02aa9344cf83bb', bin2hstr(block_header.mining_blob)) self.assertEquals(config.dev.mining_blob_size, len(block_header.mining_blob))
def create(staking_address: bytes, block_number: int, reveal_hash: bytes, prevblock_headerhash: bytes, transactions: list, duplicate_transactions: OrderedDict, vote: VoteMetadata, signing_xmss: XMSS, nonce: int): block = Block() block._data.transactions.extend([qrl_pb2.Transaction() ]) # FIXME: Empty for coinbase? # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: if tx.subtype == qrl_pb2.Transaction.TRANSFER: fee_reward += tx.fee hashedtransactions.append(tx.txhash) block._data.transactions.extend( [tx.pbdata]) # copy memory rather than sym link if not hashedtransactions: hashedtransactions = [sha256(b'')] txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes for tx in duplicate_transactions.values( ): # TODO: Add merkle hash for dup txn block._data.duplicate_transactions.extend([tx.pbdata]) for staker in vote.stake_validator_vote: # TODO: Add merkle hash for vote block._data.vote.extend([vote.stake_validator_vote[staker].pbdata]) tmp_blockheader = BlockHeader.create( staking_address=staking_address, blocknumber=block_number, reveal_hash=reveal_hash, prev_blockheaderhash=prevblock_headerhash, hashedtransactions=txs_hash, fee_reward=fee_reward) block._data.header.MergeFrom(tmp_blockheader.pbdata) # Prepare coinbase tx coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss) coinbase_tx.pbdata.nonce = nonce coinbase_tx.sign(signing_xmss) # Sign after nonce has been set # Replace first tx block._data.transactions[0].CopyFrom(coinbase_tx.pbdata) return block
def test_blob(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) self.assertEquals( '00501846b24200c31fca7172a7f701ae50322579cfdf1d7777daab4ce6ead70b76debb2c51a1' 'c70000000000000000000000002b80aecec05ad5c7c4f2259c8f69e2966a6ce102d4609af2cd', bin2hstr(block_header.mining_blob)) self.assertEquals(config.dev.mining_blob_size, len(block_header.mining_blob))
def test_hash(self, time_mock): block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) header_hash = block_header.generate_headerhash() self.assertEquals( 'ac021e63df860ea930ea9de05e350d3f74af35341688134f92957f1dac3a62fb', bin2hstr(header_hash)) self.assertEquals(bin2hstr(header_hash), bin2hstr(block_header.headerhash)) self.assertEquals(32, len(block_header.headerhash))
def setUp(self): with mock.patch('qrl.core.misc.ntp.getTime', return_value=1615270948) as time_mock: self.block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) self.fee_reward = 10 self.coinbase_amount = self.block_header.block_reward + self.fee_reward # this variable is for validate_parent_child_relation() self.m_parent_block = Mock( name='mock Parent Block', block_number=self.block_header.block_number - 1, headerhash=self.block_header.prev_headerhash, timestamp=self.block_header.timestamp - 1 )
def update_mining_address(self, mining_address: bytes): self.transactions[0].update_mining_address(mining_address) hashedtransactions = [] for tx in self.transactions: hashedtransactions.append(tx.transaction_hash) tmp_blockheader = BlockHeader.create( blocknumber=self.block_number, prev_blockheaderhash=self.prev_headerhash, hashedtransactions=merkle_tx_hash(hashedtransactions), fee_reward=self.fee_reward) self._data.header.MergeFrom(tmp_blockheader.pbdata)
def test_hash(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), sha256(b'txs'), 10) header_hash = block_header.generate_headerhash() self.assertEquals( '584f898a54269d0651cca3403843d4cdb764e5a31655bf51db39bbf8c4883b01', bin2hstr(header_hash)) self.assertEquals(bin2hstr(header_hash), bin2hstr(block_header.headerhash)) self.assertEquals(32, len(block_header.headerhash))
def test_hash(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) header_hash = block_header.generate_headerhash() self.assertEquals( 'eb2364355673f1d4384008dbc53a19050c6d1aaea01c724943c9a8f5d01fdece', bin2hstr(header_hash)) self.assertEquals(bin2hstr(header_hash), bin2hstr(block_header.headerhash)) self.assertEquals(32, len(block_header.headerhash))
def test_hash(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) header_hash = block_header.generate_headerhash() self.assertEquals( '81dd8032691331fb9cb6d4b8c3cf82dfec7873eb96789a10076b70da45315a38', bin2hstr(header_hash)) self.assertEquals(bin2hstr(header_hash), bin2hstr(block_header.headerhash)) self.assertEquals(32, len(block_header.headerhash))
def test_hash_nonce(self, time_mock): block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) block_header.set_nonces(100, 0) header_hash = block_header.generate_headerhash() self.assertEquals( 'b6f937020f9876f3c6887e7a6759201411ed8826ed9ce4283ffe48e1aa90d692', bin2hstr(header_hash)) self.assertEquals(bin2hstr(header_hash), bin2hstr(block_header.headerhash)) self.assertEquals(32, len(block_header.headerhash))
def create(mining_nonce: int, block_number: int, prevblock_headerhash: bytes, transactions: list, signing_xmss: XMSS, master_address: bytes, nonce: int): block = Block() block._data.transactions.extend([qrl_pb2.Transaction()]) # FIXME: Empty for coinbase? # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee hashedtransactions.append(tx.txhash) block._data.transactions.extend([tx.pbdata]) # copy memory rather than sym link if not hashedtransactions: hashedtransactions = [sha256(b'')] txs_hash = merkle_tx_hash(hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create(blocknumber=block_number, mining_nonce=mining_nonce, PK=signing_xmss.pk(), prev_blockheaderhash=prevblock_headerhash, hashedtransactions=txs_hash, fee_reward=fee_reward) block._data.header.MergeFrom(tmp_blockheader.pbdata) # Prepare coinbase tx coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss, master_address) coinbase_tx.pbdata.nonce = nonce coinbase_tx.sign(signing_xmss) # Sign after nonce has been set # Replace first tx block._data.transactions[0].CopyFrom(coinbase_tx.pbdata) return block
def test_hash_nonce(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), sha256(b'txs'), 10) block_header.set_nonces(100, 0) header_hash = block_header.generate_headerhash() self.assertEquals( '28556460d0b3b4830ef3d74fab1cd52bca25ee00d1a6396a7f053d53549f73ba', bin2hstr(header_hash)) self.assertEquals(bin2hstr(header_hash), bin2hstr(block_header.headerhash)) self.assertEquals(32, len(block_header.headerhash))
def create(block_number: int, prevblock_headerhash: bytes, transactions: list, signing_xmss: XMSS, master_address: bytes, nonce: int): block = Block() block._data.transactions.extend([qrl_pb2.Transaction() ]) # FIXME: Empty for coinbase? # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee hashedtransactions.append(tx.txhash) block._data.transactions.extend( [tx.pbdata]) # copy memory rather than sym link if not hashedtransactions: hashedtransactions = [sha256(b'')] txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create( blocknumber=block_number, PK=signing_xmss.pk, prev_blockheaderhash=prevblock_headerhash, hashedtransactions=txs_hash, fee_reward=fee_reward) block._data.header.MergeFrom(tmp_blockheader.pbdata) # Prepare coinbase tx coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss, master_address) coinbase_tx.pbdata.nonce = nonce coinbase_tx.sign(signing_xmss) # Sign after nonce has been set # Replace first tx block._data.transactions[0].CopyFrom(coinbase_tx.pbdata) return block
def test_GetBlockMiningCompatible(self): block_header = BlockHeader.create(**self.block_header_params) self.qrlnode.get_blockheader_and_metadata = MagicMock( return_value=[block_header, BlockMetadata()]) req = qrlmining_pb2.GetBlockMiningCompatibleReq(height=10) answer = self.service.GetBlockMiningCompatible(request=req, context=None) self.assertEqual(10, answer.blockheader.block_number) self.assertEqual(1, answer.blockheader.reward_fee) # if QRLNode responds with None, None, the GRPC response should be blank too self.qrlnode.get_blockheader_and_metadata = MagicMock( return_value=[None, None]) answer = self.service.GetBlockMiningCompatible(request=req, context=None) self.assertEqual(0, answer.blockheader.block_number) self.assertEqual(0, answer.blockheader.reward_fee)
def test_hash_nonce(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) block_header.set_nonces(100, 0) header_hash = block_header.generate_headerhash() self.assertEquals( 'f48ef2a482b2b85b429979ea1d7014806754b3ff37705c4f61a54f17bca4ccc4', bin2hstr(header_hash)) self.assertEquals(bin2hstr(header_hash), bin2hstr(block_header.headerhash)) self.assertEquals(32, len(block_header.headerhash))
def test_hash_nonce(self): with mock.patch('qrl.core.misc.ntp.getTime') as time_mock: time_mock.return_value = 1615270948 block_header = BlockHeader.create(1, sha256(b'prev'), time_mock.return_value, sha256(b'txs'), 10) block_header.set_nonces(100, 0) header_hash = block_header.generate_headerhash() self.assertEquals( '8ab90d398ef7d219fb985a15814525b42f597a44478599a4a25b4b0a10697cf2', bin2hstr(header_hash)) self.assertEquals(bin2hstr(header_hash), bin2hstr(block_header.headerhash)) self.assertEquals(32, len(block_header.headerhash))
def validate_mining_nonce(self, state: State, blockheader: BlockHeader, enable_logging=False): parent_metadata = state.get_block_metadata( blockheader.prev_blockheaderhash) parent_block = state.get_block(blockheader.prev_blockheaderhash) measurement = state.get_measurement(blockheader.timestamp, blockheader.prev_blockheaderhash, parent_metadata) diff, target = DifficultyTracker.get( measurement=measurement, parent_difficulty=parent_metadata.block_difficulty) if enable_logging: logger.debug('-----------------START--------------------') logger.debug('Validate #%s', blockheader.block_number) logger.debug('block.timestamp %s', blockheader.timestamp) logger.debug('parent_block.timestamp %s', parent_block.timestamp) logger.debug('parent_block.difficulty %s', UInt256ToString(parent_metadata.block_difficulty)) logger.debug('diff : %s | target : %s', UInt256ToString(diff), target) logger.debug('-------------------END--------------------') if not self.verify_input_cached(blockheader.mining_blob, target): if enable_logging: logger.warning("PoW verification failed") qn = Qryptonight() tmp_hash = qn.hash(blockheader.mining_blob) logger.warning("{}".format(tmp_hash)) logger.debug('%s', blockheader.to_json()) return False return True
def test_init(self): block_header = BlockHeader() self.assertIsNotNone(block_header) # just to avoid warnings
def test_init(self): # TODO: Not much going on here.. block_header = BlockHeader() self.assertIsNotNone(block_header) # just to avoid warnings
class Block(object): def __init__(self, protobuf_block=None): self._data = protobuf_block if protobuf_block is None: self._data = qrl_pb2.Block() self.blockheader = BlockHeader(self._data.header) @property def size(self): return self._data.ByteSize() @property def pbdata(self): """ Returns a protobuf object that contains persistable data representing this object :return: A protobuf Block object :rtype: qrl_pb2.Block """ return self._data @property def block_number(self): return self.blockheader.block_number @property def epoch(self): return int(self.block_number // config.dev.blocks_per_epoch) @property def headerhash(self): return self.blockheader.headerhash @property def prev_headerhash(self): return self.blockheader.prev_blockheaderhash @property def transactions(self): return self._data.transactions @property def mining_nonce(self): return self.blockheader.mining_nonce @property def PK(self): return self.blockheader.PK @property def block_reward(self): return self.blockheader.block_reward @property def fee_reward(self): return self.blockheader.fee_reward @property def timestamp(self): return self.blockheader.timestamp @property def mining_blob(self) -> bytes: return self.blockheader.mining_blob @property def mining_nonce_offset(self) -> bytes: return self.blockheader.nonce_offset @staticmethod def from_json(json_data): pbdata = qrl_pb2.Block() Parse(json_data, pbdata) return Block(pbdata) def verify_blob(self, blob: bytes) -> bool: return self.blockheader.verify_blob(blob) def set_nonces(self, mining_nonce, extra_nonce=0): self.blockheader.set_nonces(mining_nonce, extra_nonce) def to_json(self) -> str: # FIXME: Remove once we move completely to protobuf return MessageToJson(self._data) @staticmethod def create(block_number: int, prevblock_headerhash: bytes, transactions: list, miner_address: bytes): block = Block() # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee # Prepare coinbase tx total_reward_amount = BlockHeader.block_reward_calc( block_number) + fee_reward coinbase_tx = CoinBase.create(total_reward_amount, miner_address, block_number) hashedtransactions.append(coinbase_tx.txhash) block._data.transactions.extend([coinbase_tx.pbdata ]) # copy memory rather than sym link for tx in transactions: hashedtransactions.append(tx.txhash) block._data.transactions.extend( [tx.pbdata]) # copy memory rather than sym link txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create( blocknumber=block_number, prev_blockheaderhash=prevblock_headerhash, hashedtransactions=txs_hash, fee_reward=fee_reward) block._data.header.MergeFrom(tmp_blockheader.pbdata) block.set_nonces(0, 0) return block def update_mining_address(self, mining_address: bytes): self.transactions[0].update_mining_address(mining_address) hashedtransactions = [] for tx in self.transactions: hashedtransactions.append(tx.transaction_hash) tmp_blockheader = BlockHeader.create( blocknumber=self.block_number, prev_blockheaderhash=self.prev_headerhash, hashedtransactions=merkle_tx_hash(hashedtransactions), fee_reward=self.fee_reward) self._data.header.MergeFrom(tmp_blockheader.pbdata) def validate(self) -> bool: fee_reward = 0 for index in range(1, len(self.transactions)): fee_reward += self.transactions[index].fee if len(self.transactions) == 0: return False try: coinbase_txn = Transaction.from_pbdata(self.transactions[0]) coinbase_amount = coinbase_txn.amount except Exception as e: logger.warning('Exception %s', e) return False return self.blockheader.validate(fee_reward, coinbase_amount) def validate_parent_child_relation(self, parent_block) -> bool: return self.blockheader.validate_parent_child_relation(parent_block)
class Block(object): def __init__(self, protobuf_block=None): self._data = protobuf_block if protobuf_block is None: self._data = qrl_pb2.Block() self.blockheader = BlockHeader(self._data.header) @property def size(self): return self._data.ByteSize() @property def pbdata(self): """ Returns a protobuf object that contains persistable data representing this object :return: A protobuf Block object :rtype: qrl_pb2.Block """ return self._data @property def block_number(self): return self.blockheader.block_number @property def epoch(self): return int(self.block_number // config.dev.blocks_per_epoch) @property def headerhash(self): return self.blockheader.headerhash @property def prev_headerhash(self): return self.blockheader.prev_blockheaderhash @property def transactions(self): return self._data.transactions @property def mining_nonce(self): return self.blockheader.mining_nonce @property def PK(self): return self.blockheader.PK @property def block_reward(self): return self.blockheader.block_reward @property def timestamp(self): return self.blockheader.timestamp @property def mining_hash(self): return self.blockheader.mining_hash @staticmethod def from_json(json_data): pbdata = qrl_pb2.Block() Parse(json_data, pbdata) return Block(pbdata) def set_mining_nonce(self, mining_nonce): self.blockheader.set_mining_nonce(mining_nonce) def to_json(self)->str: # FIXME: Remove once we move completely to protobuf return MessageToJson(self._data) @staticmethod def create(mining_nonce: int, block_number: int, prevblock_headerhash: bytes, transactions: list, signing_xmss: XMSS, master_address: bytes, nonce: int): block = Block() block._data.transactions.extend([qrl_pb2.Transaction()]) # FIXME: Empty for coinbase? # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee hashedtransactions.append(tx.txhash) block._data.transactions.extend([tx.pbdata]) # copy memory rather than sym link if not hashedtransactions: hashedtransactions = [sha256(b'')] txs_hash = merkle_tx_hash(hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create(blocknumber=block_number, mining_nonce=mining_nonce, PK=signing_xmss.pk(), prev_blockheaderhash=prevblock_headerhash, hashedtransactions=txs_hash, fee_reward=fee_reward) block._data.header.MergeFrom(tmp_blockheader.pbdata) # Prepare coinbase tx coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss, master_address) coinbase_tx.pbdata.nonce = nonce coinbase_tx.sign(signing_xmss) # Sign after nonce has been set # Replace first tx block._data.transactions[0].CopyFrom(coinbase_tx.pbdata) return block def validate(self) -> bool: fee_reward = 0 for index in range(1, len(self.transactions)): fee_reward += self.transactions[index].fee if len(self.transactions) == 0: return False try: coinbase_txn = Transaction.from_pbdata(self.transactions[0]) coinbase_amount = coinbase_txn.amount except Exception as e: logger.warning('Exception %s', e) return False return self.blockheader.validate(fee_reward, coinbase_amount) def validate_parent_child_relation(self, parent_block) -> bool: return self.blockheader.validate_parent_child_relation(parent_block) def add_transaction(self, tx: Transaction): # TODO: Verify something basic here? self._data.transactions.extend(tx.pbdata)
class Block(object): def __init__(self, protobuf_block=None): self._data = protobuf_block if protobuf_block is None: self._data = qrl_pb2.Block() self.blockheader = BlockHeader(self._data.header) @property def size(self): return self._data.ByteSize() @property def pbdata(self): """ Returns a protobuf object that contains persistable data representing this object :return: A protobuf Block object :rtype: qrl_pb2.Block """ return self._data @property def block_number(self): return self.blockheader.block_number @property def epoch(self): return int(self.block_number // config.dev.blocks_per_epoch) @property def headerhash(self): return self.blockheader.headerhash @property def prev_headerhash(self): return self.blockheader.prev_blockheaderhash @property def transactions(self): return self._data.transactions @property def mining_nonce(self): return self.blockheader.mining_nonce @property def PK(self): return self.blockheader.PK @property def block_reward(self): return self.blockheader.block_reward @property def fee_reward(self): return self.blockheader.fee_reward @property def timestamp(self): return self.blockheader.timestamp @property def mining_blob(self) -> bytes: return self.blockheader.mining_blob @property def mining_nonce_offset(self) -> bytes: return self.blockheader.nonce_offset @staticmethod def from_json(json_data): pbdata = qrl_pb2.Block() Parse(json_data, pbdata) return Block(pbdata) def verify_blob(self, blob: bytes) -> bool: return self.blockheader.verify_blob(blob) def set_mining_nonce(self, mining_nonce): self.blockheader.set_mining_nonce(mining_nonce) def to_json(self) -> str: # FIXME: Remove once we move completely to protobuf return MessageToJson(self._data) @staticmethod def create(block_number: int, prevblock_headerhash: bytes, transactions: list, signing_xmss: XMSS, master_address: bytes, nonce: int): block = Block() block._data.transactions.extend([qrl_pb2.Transaction() ]) # FIXME: Empty for coinbase? # Process transactions hashedtransactions = [] fee_reward = 0 for tx in transactions: fee_reward += tx.fee hashedtransactions.append(tx.txhash) block._data.transactions.extend( [tx.pbdata]) # copy memory rather than sym link if not hashedtransactions: hashedtransactions = [sha256(b'')] txs_hash = merkle_tx_hash( hashedtransactions) # FIXME: Find a better name, type changes tmp_blockheader = BlockHeader.create( blocknumber=block_number, PK=signing_xmss.pk, prev_blockheaderhash=prevblock_headerhash, hashedtransactions=txs_hash, fee_reward=fee_reward) block._data.header.MergeFrom(tmp_blockheader.pbdata) # Prepare coinbase tx coinbase_tx = CoinBase.create(tmp_blockheader, signing_xmss, master_address) coinbase_tx.pbdata.nonce = nonce coinbase_tx.sign(signing_xmss) # Sign after nonce has been set # Replace first tx block._data.transactions[0].CopyFrom(coinbase_tx.pbdata) return block def validate(self) -> bool: fee_reward = 0 for index in range(1, len(self.transactions)): fee_reward += self.transactions[index].fee if len(self.transactions) == 0: return False try: coinbase_txn = Transaction.from_pbdata(self.transactions[0]) coinbase_amount = coinbase_txn.amount except Exception as e: logger.warning('Exception %s', e) return False return self.blockheader.validate(fee_reward, coinbase_amount) def validate_parent_child_relation(self, parent_block) -> bool: return self.blockheader.validate_parent_child_relation(parent_block) def add_transaction(self, tx: Transaction): # TODO: Verify something basic here? self._data.transactions.extend(tx.pbdata)
def __init__(self, protobuf_block=None): self._data = protobuf_block if protobuf_block is None: self._data = qrl_pb2.Block() self.blockheader = BlockHeader(self._data.header)