Skip to content

Commit 275efc8

Browse files
committed
Implement interim DAA
1 parent 274f63e commit 275efc8

1 file changed

Lines changed: 64 additions & 12 deletions

File tree

electrum/blockchain.py

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,59 @@
5353
"softforks": {
5454
(...)
5555
"hard_diff_removal": {
56+
"type": "buried",
57+
"active": true,
58+
"height": 168672
59+
},
60+
"interim_daa": {
5661
"type": "bip9",
5762
"bip9": {
58-
"status": "active",
59-
"start_time": 1743465600,
60-
"timeout": 1775001600,
61-
"since": 168672,
62-
"min_activation_height": 160000
63+
"status": "locked_in",
64+
"start_time": 1767225600,
65+
"timeout": 1784505600,
66+
"since": 172116,
67+
"min_activation_height": 0
6368
},
64-
"height": 168672,
65-
"active": true
69+
"active": false
6670
}
6771
},
68-
"warnings": ""
72+
(...)
6973
}
7074
"""
7175
MAINNET_HARD_DIFF_REMOVAL_ACTIVATION_HEIGHT = 168672
7276

77+
MAINNET_INTERIM_DAA_ACTIVATION_HEIGHT = 172116 + 42 # 172158
78+
MAINNET_INTERIM_DAA_END_HEIGHT = MAINNET_INTERIM_DAA_ACTIVATION_HEIGHT + 1344 # 173502
79+
INTERIM_DAA_PERIOD = 42
80+
INTERIM_DAA_TARGET_TIMESPAN = (INTERIM_DAA_PERIOD - 1) * 30 * 60 # 73800 seconds
81+
82+
83+
def is_interim_daa_active(height: int) -> bool:
84+
return MAINNET_INTERIM_DAA_ACTIVATION_HEIGHT <= height < MAINNET_INTERIM_DAA_END_HEIGHT
85+
86+
87+
def calculate_interim_daa_delta(nBits: int, proportion: float) -> int:
88+
# See CalculateInterimDifficultyDelta in src/pow.cpp
89+
delta = 0
90+
if nBits % 2 != 0:
91+
delta -= 1
92+
93+
if proportion < 0.5:
94+
delta += 6
95+
elif proportion < 0.6667:
96+
delta += 4
97+
elif proportion < 0.9:
98+
delta += 2
99+
elif proportion > 2.0:
100+
delta -= 6
101+
elif proportion > 1.5:
102+
delta -= 4
103+
elif proportion > 1.0333:
104+
delta -= 2
105+
106+
return delta
107+
108+
73109
class MissingHeader(Exception):
74110
pass
75111

@@ -630,16 +666,32 @@ def get_epoch_target(self, epoch_index: int) -> int:
630666

631667
return new_target
632668

669+
def get_interim_daa_target(self, chunk_index: int) -> int:
670+
"""Compute target for chunk chunk_index+1 using the 42-block interim DAA."""
671+
first_height = chunk_index * constants.CHUNK_SIZE
672+
last_height = first_height + constants.CHUNK_SIZE - 1
673+
first = self.read_header(first_height)
674+
last = self.read_header(last_height)
675+
if not first or not last:
676+
raise MissingHeader()
677+
678+
nActualTimespan = last.get('timestamp') - first.get('timestamp')
679+
proportion = nActualTimespan / INTERIM_DAA_TARGET_TIMESPAN
680+
nBits = int(last.get('bits'))
681+
delta = calculate_interim_daa_delta(nBits, proportion)
682+
return nBits + delta
683+
633684
def get_target(self, chunk_index: int) -> int:
634-
"""Returns the target applicable to chunk chunk_index+1,
635-
derived from the retarget epoch that contains it."""
685+
"""Returns the target applicable to chunk chunk_index+1."""
636686
if constants.net.TESTNET:
637687
return 0
638688
if chunk_index == -1:
639689
return MIN_TARGET
640-
# The target applies to chunk chunk_index+1.
641-
# Determine which retarget epoch chunk_index+1 falls in.
642690
next_chunk_start = (chunk_index + 1) * constants.CHUNK_SIZE
691+
692+
if is_interim_daa_active(next_chunk_start):
693+
return self.get_interim_daa_target(chunk_index)
694+
643695
epoch_index = next_chunk_start // constants.RETARGET_INTERVAL
644696
if epoch_index == 0:
645697
return MIN_TARGET

0 commit comments

Comments
 (0)