Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 64 additions & 14 deletions hathor/builder/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
from hathor.event import EventManager
from hathor.event.storage import EventMemoryStorage, EventRocksDBStorage, EventStorage
from hathor.event.websocket import EventWebsocketFactory
from hathor.feature_activation.bit_signaling_service import BitSignalingService
from hathor.feature_activation.feature import Feature
from hathor.feature_activation.feature_service import FeatureService
from hathor.indexes import IndexesManager, MemoryIndexesManager, RocksDBIndexesManager
from hathor.manager import HathorManager
Expand Down Expand Up @@ -64,7 +66,6 @@ class BuildArtifacts(NamedTuple):
wallet: Optional[BaseWallet]
rocksdb_storage: Optional[RocksDBStorage]
stratum_factory: Optional[StratumFactory]
feature_service: FeatureService


class Builder:
Expand All @@ -80,7 +81,7 @@ def __init__(self) -> None:
self.log = logger.new()
self.artifacts: Optional[BuildArtifacts] = None

self._settings: HathorSettingsType = HathorSettings()
self._settings: Optional[HathorSettingsType] = None
self._rng: Random = Random()
self._checkpoints: Optional[list[Checkpoint]] = None
self._capabilities: Optional[list[str]] = None
Expand All @@ -95,6 +96,11 @@ def __init__(self) -> None:
self._event_manager: Optional[EventManager] = None
self._enable_event_queue: Optional[bool] = None

self._support_features: set[Feature] = set()
self._not_support_features: set[Feature] = set()
self._feature_service: Optional[FeatureService] = None
self._bit_signaling_service: Optional[BitSignalingService] = None

self._rocksdb_path: Optional[str] = None
self._rocksdb_storage: Optional[RocksDBStorage] = None
self._rocksdb_cache_capacity: Optional[int] = None
Expand Down Expand Up @@ -134,7 +140,7 @@ def build(self) -> BuildArtifacts:
if self._network is None:
raise TypeError('you must set a network')

settings = self._get_settings()
settings = self._get_or_create_settings()
reactor = self._get_reactor()
pubsub = self._get_or_create_pubsub()

Expand All @@ -149,6 +155,7 @@ def build(self) -> BuildArtifacts:
event_manager = self._get_or_create_event_manager()
indexes = self._get_or_create_indexes_manager()
tx_storage = self._get_or_create_tx_storage(indexes)
bit_signaling_service = self._get_or_create_bit_signaling_service(tx_storage)

if self._enable_address_index:
indexes.enable_address_index(pubsub)
Expand Down Expand Up @@ -181,6 +188,7 @@ def build(self) -> BuildArtifacts:
checkpoints=self._checkpoints,
capabilities=self._capabilities,
environment_info=get_environment_info(self._cmdline, peer_id.id),
bit_signaling_service=bit_signaling_service,
**kwargs
)

Expand All @@ -190,8 +198,6 @@ def build(self) -> BuildArtifacts:
if self._enable_stratum_server:
stratum_factory = self._create_stratum_server(manager)

feature_service = self._create_feature_service(tx_storage)

self.artifacts = BuildArtifacts(
peer_id=peer_id,
settings=settings,
Expand All @@ -206,7 +212,6 @@ def build(self) -> BuildArtifacts:
wallet=wallet,
rocksdb_storage=self._rocksdb_storage,
stratum_factory=stratum_factory,
feature_service=feature_service
)

return self.artifacts
Expand All @@ -220,6 +225,16 @@ def set_event_manager(self, event_manager: EventManager) -> 'Builder':
self._event_manager = event_manager
return self

def set_feature_service(self, feature_service: FeatureService) -> 'Builder':
self.check_if_can_modify()
self._feature_service = feature_service
return self

def set_bit_signaling_service(self, bit_signaling_service: BitSignalingService) -> 'Builder':
self.check_if_can_modify()
self._bit_signaling_service = bit_signaling_service
return self

def set_rng(self, rng: Random) -> 'Builder':
self.check_if_can_modify()
self._rng = rng
Expand All @@ -240,7 +255,9 @@ def set_peer_id(self, peer_id: PeerId) -> 'Builder':
self._peer_id = peer_id
return self

def _get_settings(self) -> HathorSettingsType:
def _get_or_create_settings(self) -> HathorSettingsType:
if self._settings is None:
self._settings = HathorSettings()
return self._settings

def _get_reactor(self) -> Reactor:
Expand All @@ -252,7 +269,7 @@ def _get_soft_voided_tx_ids(self) -> set[bytes]:
if self._soft_voided_tx_ids is not None:
return self._soft_voided_tx_ids

settings = self._get_settings()
settings = self._get_or_create_settings()

return set(settings.SOFT_VOIDED_TX_IDS)

Expand All @@ -272,12 +289,6 @@ def _create_stratum_server(self, manager: HathorManager) -> StratumFactory:
manager.metrics.stratum_factory = stratum_factory
return stratum_factory

def _create_feature_service(self, tx_storage: TransactionStorage) -> FeatureService:
return FeatureService(
feature_settings=self._settings.FEATURE_ACTIVATION,
tx_storage=tx_storage
)

def _get_or_create_rocksdb_storage(self) -> RocksDBStorage:
assert self._rocksdb_path is not None

Expand Down Expand Up @@ -388,6 +399,29 @@ def _get_or_create_event_manager(self) -> EventManager:

return self._event_manager

def _get_or_create_feature_service(self, tx_storage: TransactionStorage) -> FeatureService:
if self._feature_service is None:
settings = self._get_or_create_settings()
self._feature_service = FeatureService(
feature_settings=settings.FEATURE_ACTIVATION,
tx_storage=tx_storage
)

return self._feature_service

def _get_or_create_bit_signaling_service(self, tx_storage: TransactionStorage) -> BitSignalingService:
if self._bit_signaling_service is None:
settings = self._get_or_create_settings()
self._bit_signaling_service = BitSignalingService(
feature_settings=settings.FEATURE_ACTIVATION,
feature_service=self._get_or_create_feature_service(tx_storage),
tx_storage=tx_storage,
support_features=self._support_features,
not_support_features=self._not_support_features,
)

return self._bit_signaling_service

def use_memory(self) -> 'Builder':
self.check_if_can_modify()
self._storage_type = StorageType.MEMORY
Expand Down Expand Up @@ -559,3 +593,19 @@ def set_soft_voided_tx_ids(self, soft_voided_tx_ids: set[bytes]) -> 'Builder':
self.check_if_can_modify()
self._soft_voided_tx_ids = soft_voided_tx_ids
return self

def set_features(
self,
*,
support_features: Optional[set[Feature]],
not_support_features: Optional[set[Feature]]
) -> 'Builder':
self.check_if_can_modify()
self._support_features = support_features or set()
self._not_support_features = not_support_features or set()
return self

def set_settings(self, settings: HathorSettingsType) -> 'Builder':
self.check_if_can_modify()
self._settings = settings
return self
18 changes: 17 additions & 1 deletion hathor/builder/cli_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
from hathor.consensus import ConsensusAlgorithm
from hathor.event import EventManager
from hathor.exception import BuilderError
from hathor.feature_activation.bit_signaling_service import BitSignalingService
from hathor.feature_activation.feature_service import FeatureService
from hathor.indexes import IndexesManager, MemoryIndexesManager, RocksDBIndexesManager
from hathor.manager import HathorManager
from hathor.p2p.manager import ConnectionsManager
Expand Down Expand Up @@ -189,6 +191,19 @@ def create_manager(self, reactor: PosixReactorBase) -> HathorManager:
self.log.info('--x-enable-event-queue flag provided. '
'The events detected by the full node will be stored and can be retrieved by clients')

self.feature_service = FeatureService(
feature_settings=settings.FEATURE_ACTIVATION,
tx_storage=tx_storage
)

bit_signaling_service = BitSignalingService(
feature_settings=settings.FEATURE_ACTIVATION,
feature_service=self.feature_service,
tx_storage=tx_storage,
support_features=self._args.signal_support,
not_support_features=self._args.signal_not_support
)

p2p_manager = ConnectionsManager(
reactor,
network=network,
Expand Down Expand Up @@ -216,7 +231,8 @@ def create_manager(self, reactor: PosixReactorBase) -> HathorManager:
checkpoints=settings.CHECKPOINTS,
environment_info=get_environment_info(args=str(self._args), peer_id=peer_id.id),
full_verification=full_verification,
enable_event_queue=self._args.x_enable_event_queue
enable_event_queue=self._args.x_enable_event_queue,
bit_signaling_service=bit_signaling_service
)

p2p_manager.set_manager(self.manager)
Expand Down
14 changes: 6 additions & 8 deletions hathor/cli/run_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,15 @@ def prepare(self, *, register_resources: bool = True) -> None:
self.reactor.listenTCP(self._args.stratum, self.manager.stratum_factory)

from hathor.conf import HathorSettings
from hathor.feature_activation.feature_service import FeatureService
settings = HathorSettings()

feature_service = FeatureService(
feature_settings=settings.FEATURE_ACTIVATION,
tx_storage=self.manager.tx_storage
)

if register_resources:
resources_builder = ResourcesBuilder(self.manager, self._args, builder.event_ws_factory, feature_service)
resources_builder = ResourcesBuilder(
self.manager,
self._args,
builder.event_ws_factory,
builder.feature_service
)
status_server = resources_builder.build()
if self._args.status:
self.reactor.listenTCP(self._args.status, status_server)
Expand All @@ -188,7 +187,6 @@ def prepare(self, *, register_resources: bool = True) -> None:
wallet=self.manager.wallet,
rocksdb_storage=getattr(builder, 'rocksdb_storage', None),
stratum_factory=self.manager.stratum_factory,
feature_service=feature_service
)

def start_sentry_if_possible(self) -> None:
Expand Down
10 changes: 8 additions & 2 deletions hathor/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
RewardLockedError,
SpendingVoidedError,
)
from hathor.feature_activation.bit_signaling_service import BitSignalingService
from hathor.mining import BlockTemplate, BlockTemplates
from hathor.p2p.manager import ConnectionsManager
from hathor.p2p.peer_discovery import PeerDiscovery
Expand Down Expand Up @@ -97,6 +98,7 @@ def __init__(self,
tx_storage: TransactionStorage,
p2p_manager: ConnectionsManager,
event_manager: EventManager,
bit_signaling_service: BitSignalingService,
network: str,
hostname: Optional[str] = None,
wallet: Optional[BaseWallet] = None,
Expand Down Expand Up @@ -170,6 +172,8 @@ def __init__(self,
self._event_manager.save_event_queue_state(enable_event_queue)
self._enable_event_queue = enable_event_queue

self._bit_signaling_service = bit_signaling_service

self.consensus_algorithm = consensus_algorithm

self.peer_discoveries: list[PeerDiscovery] = []
Expand Down Expand Up @@ -261,6 +265,8 @@ def start(self) -> None:
if self._enable_event_queue:
self._event_manager.start(not_none(self.my_peer.id))

self._bit_signaling_service.start()

self.state = self.NodeState.INITIALIZING
self.pubsub.publish(HathorEvents.MANAGER_ON_START)
self._event_manager.load_started()
Expand Down Expand Up @@ -838,12 +844,13 @@ def _make_block_template(self, parent_block: Block, parent_txs: 'ParentTxs', cur
parents_any=parents_any,
height=height,
score=sum_weights(parent_block_metadata.score, weight),
signal_bits=self._bit_signaling_service.generate_signal_bits(block=parent_block)
)

def generate_mining_block(self, timestamp: Optional[int] = None,
parent_block_hash: Optional[VertexId] = None,
data: bytes = b'', address: Optional[Address] = None,
merge_mined: bool = False, signal_bits: int = 0) -> Union[Block, MergeMinedBlock]:
merge_mined: bool = False) -> Union[Block, MergeMinedBlock]:
""" Generates a block ready to be mined. The block includes new issued tokens,
parents, and the weight.

Expand All @@ -860,7 +867,6 @@ def generate_mining_block(self, timestamp: Optional[int] = None,
merge_mined=merge_mined,
address=address or None, # XXX: because we allow b'' for explicit empty output script
data=data,
signal_bits=signal_bits
)
return block

Expand Down
12 changes: 7 additions & 5 deletions hathor/mining/block_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class BlockTemplate(NamedTuple):
parents_any: list[bytes] # list of extra parents to choose from when there are more options
height: int # metadata
score: float # metadata
signal_bits: int # signal bits for blocks generated from this template

def generate_minimaly_valid_block(self) -> BaseTransaction:
""" Generates a block, without any extra information that is valid for this template. No random choices."""
Expand All @@ -47,8 +48,8 @@ def generate_minimaly_valid_block(self) -> BaseTransaction:

def generate_mining_block(self, rng: Random, merge_mined: bool = False, address: Optional[bytes] = None,
timestamp: Optional[int] = None, data: Optional[bytes] = None,
storage: Optional[TransactionStorage] = None, include_metadata: bool = False,
signal_bits: int = 0) -> Union[Block, MergeMinedBlock]:
storage: Optional[TransactionStorage] = None, include_metadata: bool = False
) -> Union[Block, MergeMinedBlock]:
""" Generates a block by filling the template with the given options and random parents (if multiple choices).

Note that if a timestamp is given it will be coerced into the [timestamp_min, timestamp_max] range.
Expand All @@ -64,7 +65,7 @@ def generate_mining_block(self, rng: Random, merge_mined: bool = False, address:
tx_outputs = [TxOutput(self.reward, output_script)]
cls: Union[type['Block'], type['MergeMinedBlock']] = MergeMinedBlock if merge_mined else Block
block = cls(outputs=tx_outputs, parents=parents, timestamp=block_timestamp,
data=data or b'', storage=storage, weight=self.weight, signal_bits=signal_bits)
data=data or b'', storage=storage, weight=self.weight, signal_bits=self.signal_bits)
if include_metadata:
block._metadata = TransactionMetadata(height=self.height, score=self.score)
block.get_metadata(use_storage=False)
Expand Down Expand Up @@ -93,6 +94,7 @@ def to_dict(self) -> dict:
'parents_any': [p.hex() for p in self.parents_any],
'height': self.height,
'score': self.score,
'signal_bits': self.signal_bits,
}

@classmethod
Expand All @@ -108,6 +110,7 @@ def from_dict(cls, data: dict) -> 'BlockTemplate':
parents_any=[bytes.fromhex(p) for p in data['parents_any']],
height=int(data['height']),
score=int(data['score']),
signal_bits=int(data.get('signal_bits', 0)),
)


Expand All @@ -129,5 +132,4 @@ def generate_mining_block(self, rng: Random, merge_mined: bool = False, address:
return self.choose_random_template(rng).generate_mining_block(rng, merge_mined=merge_mined, address=address,
timestamp=timestamp, data=data,
storage=storage or self.storage,
include_metadata=include_metadata,
signal_bits=signal_bits)
include_metadata=include_metadata)
5 changes: 4 additions & 1 deletion hathor/simulator/miner/geometric_miner.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ def _generate_mining_block(self) -> 'Block':
except IndexError:
signal_bits = 0

return self._manager.generate_mining_block(signal_bits=signal_bits)
block = self._manager.generate_mining_block()
block.signal_bits = signal_bits

return block

def _schedule_next_block(self):
if self._block:
Expand Down
1 change: 1 addition & 0 deletions hathor/transaction/base_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,7 @@ def to_json(self, decode_script: bool = False, include_metadata: bool = False) -
data['timestamp'] = self.timestamp
data['version'] = int(self.version)
data['weight'] = self.weight
data['signal_bits'] = self.signal_bits

data['parents'] = []
for parent in self.parents:
Expand Down
Loading