|
53 | 53 | "softforks": { |
54 | 54 | (...) |
55 | 55 | "hard_diff_removal": { |
| 56 | + "type": "buried", |
| 57 | + "active": true, |
| 58 | + "height": 168672 |
| 59 | + }, |
| 60 | + "interim_daa": { |
56 | 61 | "type": "bip9", |
57 | 62 | "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 |
63 | 68 | }, |
64 | | - "height": 168672, |
65 | | - "active": true |
| 69 | + "active": false |
66 | 70 | } |
67 | 71 | }, |
68 | | - "warnings": "" |
| 72 | + (...) |
69 | 73 | } |
70 | 74 | """ |
71 | 75 | MAINNET_HARD_DIFF_REMOVAL_ACTIVATION_HEIGHT = 168672 |
72 | 76 |
|
| 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 | + |
73 | 109 | class MissingHeader(Exception): |
74 | 110 | pass |
75 | 111 |
|
@@ -630,16 +666,32 @@ def get_epoch_target(self, epoch_index: int) -> int: |
630 | 666 |
|
631 | 667 | return new_target |
632 | 668 |
|
| 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 | + |
633 | 684 | 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.""" |
636 | 686 | if constants.net.TESTNET: |
637 | 687 | return 0 |
638 | 688 | if chunk_index == -1: |
639 | 689 | return MIN_TARGET |
640 | | - # The target applies to chunk chunk_index+1. |
641 | | - # Determine which retarget epoch chunk_index+1 falls in. |
642 | 690 | 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 | + |
643 | 695 | epoch_index = next_chunk_start // constants.RETARGET_INTERVAL |
644 | 696 | if epoch_index == 0: |
645 | 697 | return MIN_TARGET |
|
0 commit comments