def load(self, genesis_block): height = self.state.get_mainchain_height() if height == -1: self.state.put_block(genesis_block, None) block_number_mapping = qrl_pb2.BlockNumberMapping(headerhash=genesis_block.headerhash, prev_headerhash=genesis_block.prev_headerhash) self.state.put_block_number_mapping(genesis_block.block_number, block_number_mapping, None) parent_difficulty = StringToUInt256(str(config.dev.genesis_difficulty)) self.current_difficulty, _ = self._difficulty_tracker.get( measurement=config.dev.mining_setpoint_blocktime, parent_difficulty=parent_difficulty) block_metadata = BlockMetadata.create() block_metadata.set_orphan(False) block_metadata.set_block_difficulty(self.current_difficulty) block_metadata.set_cumulative_difficulty(self.current_difficulty) self.state.put_block_metadata(genesis_block.headerhash, block_metadata, None) addresses_state = dict() for genesis_balance in GenesisBlock().genesis_balance: bytes_addr = genesis_balance.address.encode() addresses_state[bytes_addr] = AddressState.get_default(bytes_addr) addresses_state[bytes_addr]._data.balance = genesis_balance.balance self.state.state_objects.update_current_state(addresses_state) self.state.state_objects.push(genesis_block.headerhash) else: self.last_block = self.get_block_by_number(height) self.current_difficulty = self.state.get_block_metadata(self.last_block.headerhash).block_difficulty
def _add_block_metadata(self, headerhash, block_timestamp, parent_headerhash, batch): block_metadata = self._state.get_block_metadata(headerhash) if not block_metadata: block_metadata = BlockMetadata.create() parent_metadata = self._state.get_block_metadata(parent_headerhash) parent_block_difficulty = parent_metadata.block_difficulty parent_cumulative_difficulty = parent_metadata.cumulative_difficulty block_metadata.update_last_headerhashes( parent_metadata.last_N_headerhashes, parent_headerhash) measurement = self._state.get_measurement(block_timestamp, parent_headerhash, parent_metadata) block_difficulty, _ = DifficultyTracker.get( measurement=measurement, parent_difficulty=parent_block_difficulty) block_cumulative_difficulty = StringToUInt256( str( int(UInt256ToString(block_difficulty)) + int(UInt256ToString(parent_cumulative_difficulty)))) block_metadata.set_block_difficulty(block_difficulty) block_metadata.set_cumulative_difficulty(block_cumulative_difficulty) parent_metadata.add_child_headerhash(headerhash) self._state.put_block_metadata(parent_headerhash, parent_metadata, batch) self._state.put_block_metadata(headerhash, block_metadata, batch) return block_metadata
def load(self, genesis_block): height = self.state.get_mainchain_height() if height == -1: self.state.put_block(genesis_block, None) block_number_mapping = qrl_pb2.BlockNumberMapping(headerhash=genesis_block.headerhash, prev_headerhash=genesis_block.prev_headerhash) self.state.put_block_number_mapping(genesis_block.block_number, block_number_mapping, None) parent_difficulty = StringToUInt256(str(config.dev.genesis_difficulty)) self.current_difficulty, _ = DifficultyTracker.get( measurement=config.dev.mining_setpoint_blocktime, parent_difficulty=parent_difficulty) block_metadata = BlockMetadata.create() block_metadata.set_orphan(False) block_metadata.set_block_difficulty(self.current_difficulty) block_metadata.set_cumulative_difficulty(self.current_difficulty) self.state.put_block_metadata(genesis_block.headerhash, block_metadata, None) addresses_state = dict() for genesis_balance in GenesisBlock().genesis_balance: bytes_addr = genesis_balance.address addresses_state[bytes_addr] = AddressState.get_default(bytes_addr) addresses_state[bytes_addr]._data.balance = genesis_balance.balance self.state.state_objects.update_current_state(addresses_state) self.state.state_objects.push(genesis_block.headerhash) else: self.last_block = self.get_block_by_number(height) self.current_difficulty = self.state.get_block_metadata(self.last_block.headerhash).block_difficulty
def test_put_block_metadata(self): with set_qrl_dir('no_data'): with State() as state: block_metadata = BlockMetadata.create() block_metadata.update_last_headerhashes([b'test1', b'test2'], b'test3') state.put_block_metadata(b'block_headerhash', block_metadata, None) state.put_block_metadata(b'block_headerhash2', BlockMetadata.create(), None) self.assertEqual(state.get_block_metadata(b'block_headerhash').to_json(), block_metadata.to_json()) expected_json = b'{\n "blockDifficulty": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",\n ' \ b'"cumulativeDifficulty": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="\n}' self.assertEqual(state.get_block_metadata(b'block_headerhash2').to_json(), expected_json)
def add_block_metadata(self, headerhash, block_timestamp, parent_headerhash, batch): block_metadata = self.state.get_block_metadata(headerhash) if not block_metadata: block_metadata = BlockMetadata.create() parent_metadata = self.state.get_block_metadata(parent_headerhash) block_difficulty = (0, ) * 32 # 32 bytes to represent 256 bit of 0 block_cumulative_difficulty = ( 0, ) * 32 # 32 bytes to represent 256 bit of 0 if not parent_metadata: parent_metadata = BlockMetadata.create() else: parent_block = self.state.get_block(parent_headerhash) if parent_block: parent_block_difficulty = parent_metadata.block_difficulty parent_cumulative_difficulty = parent_metadata.cumulative_difficulty if not parent_metadata.is_orphan: block_metadata.update_last_headerhashes( parent_metadata.last_N_headerhashes, parent_headerhash) measurement = self.state.get_measurement( block_timestamp, parent_headerhash, parent_metadata) block_difficulty, _ = DifficultyTracker.get( measurement=measurement, parent_difficulty=parent_block_difficulty) block_cumulative_difficulty = StringToUInt256( str( int(UInt256ToString(block_difficulty)) + int(UInt256ToString(parent_cumulative_difficulty))) ) block_metadata.set_orphan(parent_metadata.is_orphan) block_metadata.set_block_difficulty(block_difficulty) block_metadata.set_cumulative_difficulty(block_cumulative_difficulty) parent_metadata.add_child_headerhash(headerhash) self.state.put_block_metadata(parent_headerhash, parent_metadata, batch) self.state.put_block_metadata(headerhash, block_metadata, batch) # Call once to populate the cache self.state.get_block_datapoint(headerhash)
def test_get_measurement(self): def block(headerhash): nth_block = Block() if headerhash == b'test_block_1': nth_block.blockheader._data.timestamp_seconds = 50000 elif headerhash == b'test_block_2': nth_block.blockheader._data.timestamp_seconds = 80000 elif headerhash == b'test_block_3': nth_block.blockheader._data.timestamp_seconds = 90000 return nth_block with set_qrl_dir('no_data'): with State() as state: parent_metadata = BlockMetadata.create(block_difficulty=b'\x00' * 32, cumulative_difficulty=b'\x00' * 32, child_headerhashes=[]) measurement = state.get_measurement(block_timestamp=100000, parent_headerhash=b'', parent_metadata=parent_metadata) # Test Case, when count_headerhashes equals 0 self.assertEqual(measurement, config.dev.mining_setpoint_blocktime) state.get_block = MagicMock(side_effect=block) parent_metadata.update_last_headerhashes([], b'test_block_1') measurement = state.get_measurement(block_timestamp=100000, parent_headerhash=b'test_block_1', parent_metadata=parent_metadata) # Test Case, when count_headerhashes equals 1 self.assertEqual(measurement, (100000 - 50000 + config.dev.mining_setpoint_blocktime) // 2) parent_metadata.update_last_headerhashes([b'test_block_1'], b'test_block_2') measurement = state.get_measurement(block_timestamp=100000, parent_headerhash=b'test_block_2', parent_metadata=parent_metadata) # Test Case, when count_headerhashes is greater than 1 # but less than config.dev.N_measurement self.assertEqual(measurement, (100000 - 80000 + config.dev.mining_setpoint_blocktime) // 2) parent_metadata.update_last_headerhashes([b'test_block_3'] * config.dev.N_measurement, b'test_block_2') measurement = state.get_measurement(block_timestamp=100000, parent_headerhash=b'test_block_2', parent_metadata=parent_metadata) # Test Case, when count_headerhashes is greater than config.dev.N_measurement self.assertEqual(measurement, (100000 - 90000) // config.dev.N_measurement)
def load(self, genesis_block): height = self.state.get_mainchain_height() if height == -1: self.state.put_block(genesis_block, None) block_number_mapping = qrl_pb2.BlockNumberMapping(headerhash=genesis_block.headerhash, prev_headerhash=genesis_block.prev_headerhash) self.state.put_block_number_mapping(genesis_block.block_number, block_number_mapping, None) parent_difficulty = StringToUInt256(str(config.dev.genesis_difficulty)) self.current_difficulty, _ = DifficultyTracker.get( measurement=config.dev.mining_setpoint_blocktime, parent_difficulty=parent_difficulty) block_metadata = BlockMetadata.create() block_metadata.set_orphan(False) block_metadata.set_block_difficulty(self.current_difficulty) block_metadata.set_cumulative_difficulty(self.current_difficulty) self.state.put_block_metadata(genesis_block.headerhash, block_metadata, None) addresses_state = dict() for genesis_balance in GenesisBlock().genesis_balance: bytes_addr = genesis_balance.address addresses_state[bytes_addr] = AddressState.get_default(bytes_addr) addresses_state[bytes_addr]._data.balance = genesis_balance.balance for tx_idx in range(1, len(genesis_block.transactions)): tx = Transaction.from_pbdata(genesis_block.transactions[tx_idx]) for addr in tx.addrs_to: addresses_state[addr] = AddressState.get_default(addr) coinbase_tx = Transaction.from_pbdata(genesis_block.transactions[0]) if not isinstance(coinbase_tx, CoinBase): return False addresses_state[coinbase_tx.addr_to] = AddressState.get_default(coinbase_tx.addr_to) if not coinbase_tx.validate_extended(): return False coinbase_tx.apply_on_state(addresses_state) for tx_idx in range(1, len(genesis_block.transactions)): tx = Transaction.from_pbdata(genesis_block.transactions[tx_idx]) tx.apply_on_state(addresses_state) self.state.state_objects.update_current_state(addresses_state) self.state.state_objects.update_tx_metadata(genesis_block, None) self.state.state_objects.push(genesis_block.headerhash) else: self.last_block = self.get_block_by_number(height) self.current_difficulty = self.state.get_block_metadata(self.last_block.headerhash).block_difficulty
def test_get_block_metadata(self): with set_qrl_dir('no_data'): with State() as state: self.assertIsNone(state.get_block_metadata(b'test1')) state.put_block_metadata(b'block_headerhash2', BlockMetadata.create(), None) tmp_json = state.get_block_metadata(b'block_headerhash2').to_json() expected_json = b'{\n "blockDifficulty": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",\n ' \ b'"cumulativeDifficulty": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="\n}' self.assertEqual(tmp_json, expected_json)
def add_block_metadata(self, headerhash, block_timestamp, parent_headerhash, batch): parent_metadata = self.state.get_block_metadata(parent_headerhash) block_difficulty = (0,) * 32 # 32 bytes to represent 256 bit of 0 block_cumulative_difficulty = (0,) * 32 # 32 bytes to represent 256 bit of 0 if not parent_metadata: parent_metadata = BlockMetadata.create() else: parent_block = self.state.get_block(parent_headerhash) if parent_block: parent_block_difficulty = parent_metadata.block_difficulty parent_cumulative_difficulty = parent_metadata.cumulative_difficulty if not parent_metadata.is_orphan: measurement = self.state.get_measurement(block_timestamp, parent_headerhash) block_difficulty, _ = self._difficulty_tracker.get( measurement=measurement, parent_difficulty=parent_block_difficulty) block_cumulative_difficulty = StringToUInt256(str( int(UInt256ToString(block_difficulty)) + int(UInt256ToString(parent_cumulative_difficulty)))) block_metadata = self.state.get_block_metadata(headerhash) if not block_metadata: block_metadata = BlockMetadata.create() block_metadata.set_orphan(parent_metadata.is_orphan) block_metadata.set_block_difficulty(block_difficulty) block_metadata.set_cumulative_difficulty(block_cumulative_difficulty) parent_metadata.add_child_headerhash(headerhash) self.state.put_block_metadata(parent_headerhash, parent_metadata, batch) self.state.put_block_metadata(headerhash, block_metadata, batch)
def test_put_block_metadata(self): with set_qrl_dir('no_data'): with State() as state: block_metadata = BlockMetadata.create(False) block_metadata.update_last_headerhashes([b'test1', b'test2'], b'test3') state.put_block_metadata(b'block_headerhash', block_metadata, None) state.put_block_metadata(b'block_headerhash2', BlockMetadata(), None) self.assertEqual( state.get_block_metadata(b'block_headerhash').to_json(), block_metadata.to_json()) self.assertEqual( state.get_block_metadata(b'block_headerhash2').to_json(), b'{}')
def load(self, genesis_block): # load() has the following tasks: # Write Genesis Block into State immediately # Register block_number <-> blockhash mapping # Calculate difficulty Metadata for Genesis Block # Generate AddressStates from Genesis Block balances # Apply Genesis Block's transactions to the state # Detect if we are forked from genesis block and if so initiate recovery. height = self._state.get_mainchain_height() if height == -1: self._state.put_block(genesis_block, None) block_number_mapping = qrl_pb2.BlockNumberMapping( headerhash=genesis_block.headerhash, prev_headerhash=genesis_block.prev_headerhash) self._state.put_block_number_mapping(genesis_block.block_number, block_number_mapping, None) parent_difficulty = StringToUInt256( str(config.user.genesis_difficulty)) self.current_difficulty, _ = DifficultyTracker.get( measurement=config.dev.mining_setpoint_blocktime, parent_difficulty=parent_difficulty) block_metadata = BlockMetadata.create() block_metadata.set_block_difficulty(self.current_difficulty) block_metadata.set_cumulative_difficulty(self.current_difficulty) self._state.put_block_metadata(genesis_block.headerhash, block_metadata, None) addresses_state = dict() for genesis_balance in GenesisBlock().genesis_balance: bytes_addr = genesis_balance.address addresses_state[bytes_addr] = AddressState.get_default( bytes_addr) addresses_state[ bytes_addr]._data.balance = genesis_balance.balance for tx_idx in range(1, len(genesis_block.transactions)): tx = Transaction.from_pbdata( genesis_block.transactions[tx_idx]) for addr in tx.addrs_to: addresses_state[addr] = AddressState.get_default(addr) coinbase_tx = Transaction.from_pbdata( genesis_block.transactions[0]) if not isinstance(coinbase_tx, CoinBase): return False addresses_state[coinbase_tx.addr_to] = AddressState.get_default( coinbase_tx.addr_to) if not coinbase_tx.validate_extended(genesis_block.block_number): return False coinbase_tx.apply_state_changes(addresses_state) for tx_idx in range(1, len(genesis_block.transactions)): tx = Transaction.from_pbdata( genesis_block.transactions[tx_idx]) tx.apply_state_changes(addresses_state) self._state.put_addresses_state(addresses_state) self._state.update_tx_metadata(genesis_block, None) self._state.update_mainchain_height(0, None) else: self._last_block = self.get_block_by_number(height) self.current_difficulty = self._state.get_block_metadata( self._last_block.headerhash).block_difficulty fork_state = self._state.get_fork_state() if fork_state: block = self._state.get_block(fork_state.initiator_headerhash) self._fork_recovery(block, fork_state)