config: distinguish knowing mempool is empty vs not having mempool_fees
config.mempool_fees is now [] if server claims mempool is ~empty, and None if no valid histogram has been received from server. (previously it used to be [] in both cases)
This commit is contained in:
@@ -156,7 +156,7 @@ class TxDialog(Factory.Popup):
|
|||||||
if tx_mined_status.timestamp:
|
if tx_mined_status.timestamp:
|
||||||
self.date_label = _('Date')
|
self.date_label = _('Date')
|
||||||
self.date_str = datetime.fromtimestamp(tx_mined_status.timestamp).isoformat(' ')[:-3]
|
self.date_str = datetime.fromtimestamp(tx_mined_status.timestamp).isoformat(' ')[:-3]
|
||||||
elif exp_n:
|
elif exp_n is not None:
|
||||||
self.date_label = _('Mempool depth')
|
self.date_label = _('Mempool depth')
|
||||||
self.date_str = _('{} from tip').format('%.2f MB'%(exp_n/1000000))
|
self.date_str = _('{} from tip').format('%.2f MB'%(exp_n/1000000))
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -430,7 +430,7 @@ class BaseTxDialog(QDialog, MessageBoxMixin):
|
|||||||
time_str = datetime.datetime.fromtimestamp(tx_mined_status.timestamp).isoformat(' ')[:-3]
|
time_str = datetime.datetime.fromtimestamp(tx_mined_status.timestamp).isoformat(' ')[:-3]
|
||||||
self.date_label.setText(_("Date: {}").format(time_str))
|
self.date_label.setText(_("Date: {}").format(time_str))
|
||||||
self.date_label.show()
|
self.date_label.show()
|
||||||
elif exp_n:
|
elif exp_n is not None:
|
||||||
text = '%.2f MB'%(exp_n/1000000)
|
text = '%.2f MB'%(exp_n/1000000)
|
||||||
self.date_label.setText(_('Position in mempool: {} from tip').format(text))
|
self.date_label.setText(_('Position in mempool: {} from tip').format(text))
|
||||||
self.date_label.show()
|
self.date_label.show()
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class SimpleConfig(Logger):
|
|||||||
# a thread-safe way.
|
# a thread-safe way.
|
||||||
self.lock = threading.RLock()
|
self.lock = threading.RLock()
|
||||||
|
|
||||||
self.mempool_fees = [] # type: Sequence[Tuple[Union[float, int], int]]
|
self.mempool_fees = None # type: Optional[Sequence[Tuple[Union[float, int], int]]]
|
||||||
self.fee_estimates = {}
|
self.fee_estimates = {}
|
||||||
self.fee_estimates_last_updated = {}
|
self.fee_estimates_last_updated = {}
|
||||||
self.last_time_fee_estimates_requested = 0 # zero ensures immediate fees
|
self.last_time_fee_estimates_requested = 0 # zero ensures immediate fees
|
||||||
@@ -345,11 +345,13 @@ class SimpleConfig(Logger):
|
|||||||
fee = int(fee)
|
fee = int(fee)
|
||||||
return fee
|
return fee
|
||||||
|
|
||||||
def fee_to_depth(self, target_fee: Real) -> int:
|
def fee_to_depth(self, target_fee: Real) -> Optional[int]:
|
||||||
"""For a given sat/vbyte fee, returns an estimate of how deep
|
"""For a given sat/vbyte fee, returns an estimate of how deep
|
||||||
it would be in the current mempool in vbytes.
|
it would be in the current mempool in vbytes.
|
||||||
Pessimistic == overestimates the depth.
|
Pessimistic == overestimates the depth.
|
||||||
"""
|
"""
|
||||||
|
if self.mempool_fees is None:
|
||||||
|
return None
|
||||||
depth = 0
|
depth = 0
|
||||||
for fee, s in self.mempool_fees:
|
for fee, s in self.mempool_fees:
|
||||||
depth += s
|
depth += s
|
||||||
@@ -357,16 +359,18 @@ class SimpleConfig(Logger):
|
|||||||
break
|
break
|
||||||
return depth
|
return depth
|
||||||
|
|
||||||
def depth_to_fee(self, slider_pos) -> int:
|
def depth_to_fee(self, slider_pos) -> Optional[int]:
|
||||||
"""Returns fee in sat/kbyte."""
|
"""Returns fee in sat/kbyte."""
|
||||||
target = self.depth_target(slider_pos)
|
target = self.depth_target(slider_pos)
|
||||||
return self.depth_target_to_fee(target)
|
return self.depth_target_to_fee(target)
|
||||||
|
|
||||||
@impose_hard_limits_on_fee
|
@impose_hard_limits_on_fee
|
||||||
def depth_target_to_fee(self, target: int) -> int:
|
def depth_target_to_fee(self, target: int) -> Optional[int]:
|
||||||
"""Returns fee in sat/kbyte.
|
"""Returns fee in sat/kbyte.
|
||||||
target: desired mempool depth in vbytes
|
target: desired mempool depth in vbytes
|
||||||
"""
|
"""
|
||||||
|
if self.mempool_fees is None:
|
||||||
|
return None
|
||||||
depth = 0
|
depth = 0
|
||||||
for fee, s in self.mempool_fees:
|
for fee, s in self.mempool_fees:
|
||||||
depth += s
|
depth += s
|
||||||
@@ -381,7 +385,7 @@ class SimpleConfig(Logger):
|
|||||||
# convert to sat/kbyte
|
# convert to sat/kbyte
|
||||||
return int(fee * 1000)
|
return int(fee * 1000)
|
||||||
|
|
||||||
def depth_target(self, slider_pos):
|
def depth_target(self, slider_pos) -> int:
|
||||||
slider_pos = max(slider_pos, 0)
|
slider_pos = max(slider_pos, 0)
|
||||||
slider_pos = min(slider_pos, len(FEE_DEPTH_TARGETS)-1)
|
slider_pos = min(slider_pos, len(FEE_DEPTH_TARGETS)-1)
|
||||||
return FEE_DEPTH_TARGETS[slider_pos]
|
return FEE_DEPTH_TARGETS[slider_pos]
|
||||||
@@ -400,8 +404,11 @@ class SimpleConfig(Logger):
|
|||||||
min_target = -1
|
min_target = -1
|
||||||
return min_target
|
return min_target
|
||||||
|
|
||||||
def depth_tooltip(self, depth):
|
def depth_tooltip(self, depth: Optional[int]) -> str:
|
||||||
return "%.1f MB from tip"%(depth/1000000)
|
"""Returns text tooltip for given mempool depth (in vbytes)."""
|
||||||
|
if depth is None:
|
||||||
|
return "unknown from tip"
|
||||||
|
return "%.1f MB from tip" % (depth/1_000_000)
|
||||||
|
|
||||||
def eta_tooltip(self, x):
|
def eta_tooltip(self, x):
|
||||||
if x < 0:
|
if x < 0:
|
||||||
@@ -460,7 +467,7 @@ class SimpleConfig(Logger):
|
|||||||
maxp = len(FEE_ETA_TARGETS) # not (-1) to have "next block"
|
maxp = len(FEE_ETA_TARGETS) # not (-1) to have "next block"
|
||||||
return min(maxp, self.get('fee_level', 2))
|
return min(maxp, self.get('fee_level', 2))
|
||||||
|
|
||||||
def get_fee_slider(self, dyn, mempool):
|
def get_fee_slider(self, dyn, mempool) -> Tuple[int, int, Optional[int]]:
|
||||||
if dyn:
|
if dyn:
|
||||||
if mempool:
|
if mempool:
|
||||||
pos = self.get_depth_level()
|
pos = self.get_depth_level()
|
||||||
@@ -479,7 +486,7 @@ class SimpleConfig(Logger):
|
|||||||
def static_fee(self, i):
|
def static_fee(self, i):
|
||||||
return FEERATE_STATIC_VALUES[i]
|
return FEERATE_STATIC_VALUES[i]
|
||||||
|
|
||||||
def static_fee_index(self, value):
|
def static_fee_index(self, value) -> int:
|
||||||
if value is None:
|
if value is None:
|
||||||
raise TypeError('static fee cannot be None')
|
raise TypeError('static fee cannot be None')
|
||||||
dist = list(map(lambda x: abs(x - value), FEERATE_STATIC_VALUES))
|
dist = list(map(lambda x: abs(x - value), FEERATE_STATIC_VALUES))
|
||||||
@@ -488,8 +495,8 @@ class SimpleConfig(Logger):
|
|||||||
def has_fee_etas(self):
|
def has_fee_etas(self):
|
||||||
return len(self.fee_estimates) == 4
|
return len(self.fee_estimates) == 4
|
||||||
|
|
||||||
def has_fee_mempool(self):
|
def has_fee_mempool(self) -> bool:
|
||||||
return bool(self.mempool_fees)
|
return self.mempool_fees is not None
|
||||||
|
|
||||||
def has_dynamic_fees_ready(self):
|
def has_dynamic_fees_ready(self):
|
||||||
if self.use_mempool_fees():
|
if self.use_mempool_fees():
|
||||||
|
|||||||
@@ -131,6 +131,10 @@ class Test_SimpleConfig(ElectrumTestCase):
|
|||||||
self.assertEqual( 2 * 1000, config.depth_target_to_fee(10 ** 6))
|
self.assertEqual( 2 * 1000, config.depth_target_to_fee(10 ** 6))
|
||||||
self.assertEqual( 2 * 1000, config.depth_target_to_fee(10 ** 7))
|
self.assertEqual( 2 * 1000, config.depth_target_to_fee(10 ** 7))
|
||||||
self.assertEqual( 1 * 1000, config.depth_target_to_fee(10 ** 8))
|
self.assertEqual( 1 * 1000, config.depth_target_to_fee(10 ** 8))
|
||||||
|
config.mempool_fees = []
|
||||||
|
self.assertEqual(1 * 1000, config.depth_target_to_fee(10 ** 5))
|
||||||
|
config.mempool_fees = None
|
||||||
|
self.assertEqual(None, config.depth_target_to_fee(10 ** 5))
|
||||||
|
|
||||||
def test_fee_to_depth(self):
|
def test_fee_to_depth(self):
|
||||||
config = SimpleConfig(self.options)
|
config = SimpleConfig(self.options)
|
||||||
|
|||||||
@@ -1050,7 +1050,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
|
|||||||
if fee is not None and height in (TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED) \
|
if fee is not None and height in (TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED) \
|
||||||
and self.config.has_fee_mempool():
|
and self.config.has_fee_mempool():
|
||||||
exp_n = self.config.fee_to_depth(fee_per_byte)
|
exp_n = self.config.fee_to_depth(fee_per_byte)
|
||||||
if exp_n:
|
if exp_n is not None:
|
||||||
extra.append('%.2f MB'%(exp_n/1000000))
|
extra.append('%.2f MB'%(exp_n/1000000))
|
||||||
if height == TX_HEIGHT_LOCAL:
|
if height == TX_HEIGHT_LOCAL:
|
||||||
status = 3
|
status = 3
|
||||||
|
|||||||
Reference in New Issue
Block a user