41
41
from hathor .transaction .exceptions import TxValidationError
42
42
from hathor .transaction .storage import TransactionStorage
43
43
from hathor .transaction .storage .exceptions import TransactionDoesNotExist
44
- from hathor .util import LogDuration , random_choices
44
+ from hathor .util import LogDuration , not_none , random_choices
45
45
from hathor .wallet import BaseWallet
46
46
47
47
settings = HathorSettings ()
@@ -67,6 +67,7 @@ def __init__(self, reactor: IReactorCore, peer_id: Optional[PeerId] = None, netw
67
67
wallet : Optional [BaseWallet ] = None , tx_storage : Optional [TransactionStorage ] = None ,
68
68
peer_storage : Optional [Any ] = None , default_port : int = 40403 , wallet_index : bool = False ,
69
69
stratum_port : Optional [int ] = None , ssl : bool = True ,
70
+ enable_sync_v1 : bool = True , enable_sync_v2 : bool = False ,
70
71
capabilities : Optional [List [str ]] = None , checkpoints : Optional [List [Checkpoint ]] = None ,
71
72
rng : Optional [Rng ] = None ) -> None :
72
73
"""
@@ -81,7 +82,7 @@ def __init__(self, reactor: IReactorCore, peer_id: Optional[PeerId] = None, netw
81
82
:param pubsub: If not given, a new one is created.
82
83
:type pubsub: :py:class:`hathor.pubsub.PubSubManager`
83
84
84
- :param tx_storage: If not given, a :py:class:`TransactionMemoryStorage` one is created .
85
+ :param tx_storage: Required storage backend .
85
86
:type tx_storage: :py:class:`hathor.transaction.storage.transaction_storage.TransactionStorage`
86
87
87
88
:param peer_storage: If not given, a new one is created.
@@ -99,7 +100,12 @@ def __init__(self, reactor: IReactorCore, peer_id: Optional[PeerId] = None, netw
99
100
from hathor .metrics import Metrics
100
101
from hathor .p2p .factory import HathorClientFactory , HathorServerFactory
101
102
from hathor .p2p .manager import ConnectionsManager
102
- from hathor .transaction .storage .memory_storage import TransactionMemoryStorage
103
+
104
+ if not (enable_sync_v1 or enable_sync_v2 ):
105
+ raise TypeError (f'{ type (self ).__name__ } () at least one sync version is required' )
106
+
107
+ if tx_storage is None :
108
+ raise TypeError (f'{ type (self ).__name__ } () missing 1 required positional argument: \' tx_storage\' ' )
103
109
104
110
self .log = logger .new ()
105
111
@@ -138,7 +144,7 @@ def __init__(self, reactor: IReactorCore, peer_id: Optional[PeerId] = None, netw
138
144
139
145
# XXX Should we use a singleton or a new PeerStorage? [msbrogli 2018-08-29]
140
146
self .pubsub = pubsub or PubSubManager (self .reactor )
141
- self .tx_storage = tx_storage or TransactionMemoryStorage ()
147
+ self .tx_storage = tx_storage
142
148
self .tx_storage .pubsub = self .pubsub
143
149
if wallet_index and self .tx_storage .with_index :
144
150
self .tx_storage .wallet_index = WalletIndex (self .pubsub )
@@ -156,10 +162,12 @@ def __init__(self, reactor: IReactorCore, peer_id: Optional[PeerId] = None, netw
156
162
self .peer_discoveries : List [PeerDiscovery ] = []
157
163
158
164
self .ssl = ssl
159
- self .server_factory = HathorServerFactory (self .network , self .my_peer , node = self , use_ssl = ssl )
160
- self .client_factory = HathorClientFactory (self .network , self .my_peer , node = self , use_ssl = ssl )
165
+ self .server_factory = HathorServerFactory (self .network , self .my_peer , node = self , use_ssl = ssl ,
166
+ enable_sync_v1 = enable_sync_v1 , enable_sync_v2 = enable_sync_v2 )
167
+ self .client_factory = HathorClientFactory (self .network , self .my_peer , node = self , use_ssl = ssl ,
168
+ enable_sync_v1 = enable_sync_v1 , enable_sync_v2 = enable_sync_v2 )
161
169
self .connections = ConnectionsManager (self .reactor , self .my_peer , self .server_factory , self .client_factory ,
162
- self .pubsub , self , ssl , rng = self .rng )
170
+ self .pubsub , self , ssl , whitelist_only = False , rng = self .rng )
163
171
164
172
self .wallet = wallet
165
173
if self .wallet :
@@ -193,6 +201,8 @@ def __init__(self, reactor: IReactorCore, peer_id: Optional[PeerId] = None, netw
193
201
# List of capabilities of the peer
194
202
if capabilities is not None :
195
203
self .capabilities = capabilities
204
+ elif enable_sync_v2 :
205
+ self .capabilities = [settings .CAPABILITY_WHITELIST , settings .CAPABILITY_SYNC_V2 ]
196
206
else :
197
207
self .capabilities = [settings .CAPABILITY_WHITELIST ]
198
208
@@ -507,19 +517,33 @@ def generate_parent_txs(self, timestamp: Optional[float]) -> 'ParentTxs':
507
517
This method tries to return a stable result, such that for a given timestamp and storage state it will always
508
518
return the same.
509
519
"""
510
- if timestamp is None :
511
- timestamp = self .reactor .seconds ()
512
- can_include_intervals = sorted (self .tx_storage .get_tx_tips (timestamp - 1 ))
513
- assert can_include_intervals , 'tips cannot be empty'
514
- max_timestamp = max (int (i .begin ) for i in can_include_intervals )
515
- must_include : List [bytes ] = []
516
- assert len (can_include_intervals ) > 0 , f'invalid timestamp "{ timestamp } ", no tips found"'
517
- if len (can_include_intervals ) < 2 :
518
- # If there is only one tip, let's randomly choose one of its parents.
519
- must_include_interval = can_include_intervals [0 ]
520
- must_include = [must_include_interval .data ]
521
- can_include_intervals = sorted (self .tx_storage .get_tx_tips (must_include_interval .begin - 1 ))
522
- can_include = [i .data for i in can_include_intervals ]
520
+ # get all that are before "timestamp"
521
+ # XXX: maybe add some tolerance?
522
+ tx_tips = list (self .tx_storage .iter_tx_tips (timestamp ))
523
+ must_include : List [bytes ]
524
+ can_include : List [bytes ]
525
+ max_timestamp : int
526
+ if not tx_tips :
527
+ # there are no txs on mempool, repeat the same tx parents as the best block
528
+ must_include = []
529
+ # can_include = self.tx_storage.get_best_block().parents[1:]
530
+ best_block = self .tx_storage .get_best_block ()
531
+ if best_block .is_genesis :
532
+ can_include = [settings .GENESIS_TX1_HASH , settings .GENESIS_TX2_HASH ]
533
+ else :
534
+ can_include = self .tx_storage .get_best_block ().parents [1 :]
535
+ max_timestamp = max (tx .timestamp for tx in map (self .tx_storage .get_transaction , can_include ) if tx )
536
+ elif len (tx_tips ) < 2 :
537
+ # there is only one tx, it must be included, and either of its parents can be included
538
+ only_tx = tx_tips [0 ]
539
+ must_include = [not_none (tx .hash ) for tx in tx_tips ]
540
+ can_include = only_tx .parents [:]
541
+ max_timestamp = only_tx .timestamp
542
+ else :
543
+ # otherwise we can include any tx on the mempool
544
+ must_include = []
545
+ can_include = [not_none (tx .hash ) for tx in tx_tips ]
546
+ max_timestamp = max (tx .timestamp for tx in tx_tips )
523
547
return ParentTxs (max_timestamp , can_include , must_include )
524
548
525
549
def allow_mining_without_peers (self ) -> None :
@@ -646,6 +670,17 @@ def _make_block_template(self, parent_block: Block, parent_txs: 'ParentTxs', cur
646
670
score = sum_weights (parent_block_metadata .score , weight ),
647
671
)
648
672
673
+ def get_current_score (self , parent_block : Optional [Block ] = None , timestamp : Optional [int ] = None ) -> float :
674
+ if timestamp is None :
675
+ timestamp = int (max (self .tx_storage .latest_timestamp , self .reactor .seconds ()))
676
+ if parent_block is None :
677
+ block = self .tx_storage .get_transaction (next (iter (self .tx_storage .get_best_block_tips ())))
678
+ assert isinstance (block , Block )
679
+ parent_block = block
680
+ parent_block_metadata = parent_block .get_metadata ()
681
+ weight = daa .calculate_next_weight (parent_block , timestamp )
682
+ return sum_weights (parent_block_metadata .score , weight )
683
+
649
684
def generate_mining_block (self , timestamp : Optional [int ] = None ,
650
685
parent_block_hash : Optional [bytes ] = None ,
651
686
data : bytes = b'' , address : Optional [bytes ] = None ,
0 commit comments