13
13
// You should have received a copy of the GNU General Public License
14
14
// along with this program. If not, see <http://www.gnu.org/licenses/>.
15
15
use std:: collections:: HashMap ;
16
+ use std:: time:: SystemTime ;
16
17
17
18
use clarity:: types:: chainstate:: {
18
- ConsensusHash , StacksAddress , StacksBlockId , StacksPrivateKey , StacksPublicKey ,
19
+ BurnchainHeaderHash , ConsensusHash , StacksAddress , StacksBlockId , StacksPrivateKey ,
20
+ StacksPublicKey ,
19
21
} ;
20
22
use clarity:: util:: hash:: Hash160 ;
21
23
use clarity:: util:: secp256k1:: MessageSignature ;
@@ -32,7 +34,7 @@ use crate::v0::signer_state::LocalStateMachine;
32
34
#[ test]
33
35
fn check_capitulate_miner_view ( ) {
34
36
let mut address_weights = HashMap :: new ( ) ;
35
- for _ in 0 ..5 {
37
+ for _ in 0 ..10 {
36
38
let stacks_address = StacksAddress :: p2pkh (
37
39
false ,
38
40
& StacksPublicKey :: from_private ( & StacksPrivateKey :: random ( ) ) ,
@@ -43,17 +45,23 @@ fn check_capitulate_miner_view() {
43
45
let active_signer_protocol_version = 0 ;
44
46
let local_supported_signer_protocol_version = 0 ;
45
47
let burn_block = ConsensusHash ( [ 0x55 ; 20 ] ) ;
46
- let burn_block_height = 100 ;
47
48
let parent_tenure_id = ConsensusHash ( [ 0x22 ; 20 ] ) ;
48
49
let parent_tenure_last_block = StacksBlockId ( [ 0x33 ; 32 ] ) ;
49
50
let parent_tenure_last_block_height = 1 ;
51
+
52
+ let old_miner_tenure_id = ConsensusHash ( [ 0x01 ; 20 ] ) ;
53
+ let new_miner_tenure_id = ConsensusHash ( [ 0x00 ; 20 ] ) ;
54
+
55
+ let burn_block_height = 100 ;
56
+
50
57
let old_miner = StateMachineUpdateMinerState :: ActiveMiner {
51
58
current_miner_pkh : Hash160 ( [ 0xab ; 20 ] ) ,
52
- tenure_id : ConsensusHash ( [ 0x44 ; 20 ] ) ,
59
+ tenure_id : old_miner_tenure_id ,
53
60
parent_tenure_id,
54
61
parent_tenure_last_block,
55
62
parent_tenure_last_block_height,
56
63
} ;
64
+ // Make sure the old update still has the newer burn block height
57
65
let old_update = StateMachineUpdateMessage :: new (
58
66
active_signer_protocol_version,
59
67
local_supported_signer_protocol_version,
@@ -86,35 +94,21 @@ fn check_capitulate_miner_view() {
86
94
StateMachineUpdateContent :: V0 {
87
95
burn_block,
88
96
burn_block_height,
89
- current_miner ,
97
+ ..
90
98
} ,
91
99
..
92
100
} = local_update. clone ( )
93
101
else {
94
102
panic ! ( "Unexpected state machine update message version" ) ;
95
103
} ;
96
104
// Let's create a new miner view
97
- let new_tenure_id = ConsensusHash ( [ 0x00 ; 20 ] ) ;
98
-
99
- let db_path = tmp_db_path ( ) ;
100
- let mut db = SignerDb :: new ( db_path) . expect ( "Failed to create signer db" ) ;
101
- let ( mut block_info_1, _block_proposal) = create_block_override ( |b| {
102
- b. block . header . consensus_hash = new_tenure_id;
103
- b. block . header . miner_signature = MessageSignature ( [ 0x01 ; 65 ] ) ;
104
- b. block . header . chain_length = 1 ;
105
- b. burn_height = burn_block_height;
106
- } ) ;
107
-
108
- db. insert_block ( & block_info_1) . unwrap ( ) ;
109
105
let new_miner = StateMachineUpdateMinerState :: ActiveMiner {
110
106
current_miner_pkh : Hash160 ( [ 0x00 ; 20 ] ) ,
111
- tenure_id : new_tenure_id ,
107
+ tenure_id : new_miner_tenure_id ,
112
108
parent_tenure_id,
113
109
parent_tenure_last_block,
114
110
parent_tenure_last_block_height,
115
111
} ;
116
-
117
- // Let's update only our own view: the evaluator will tell me to revert my viewpoint to the old miner
118
112
let new_update = StateMachineUpdateMessage :: new (
119
113
active_signer_protocol_version,
120
114
local_supported_signer_protocol_version,
@@ -126,6 +120,43 @@ fn check_capitulate_miner_view() {
126
120
)
127
121
. unwrap ( ) ;
128
122
123
+ // Update the database to have both the burn blocks corresponding to the tenure ids
124
+ // and both tenures have a locally accepted block
125
+ let db_path = tmp_db_path ( ) ;
126
+ let mut db = SignerDb :: new ( db_path) . expect ( "Failed to create signer db" ) ;
127
+ // Make sure both burn block corresponding to the tenure id's exist in our DB.
128
+ db. insert_burn_block (
129
+ & BurnchainHeaderHash ( [ 0u8 ; 32 ] ) ,
130
+ & old_miner_tenure_id,
131
+ burn_block_height. saturating_sub ( 1 ) ,
132
+ & SystemTime :: now ( ) ,
133
+ & BurnchainHeaderHash ( [ 1u8 ; 32 ] ) ,
134
+ )
135
+ . unwrap ( ) ;
136
+ db. insert_burn_block (
137
+ & BurnchainHeaderHash ( [ 0u8 ; 32 ] ) ,
138
+ & new_miner_tenure_id,
139
+ burn_block_height,
140
+ & SystemTime :: now ( ) ,
141
+ & BurnchainHeaderHash ( [ 1u8 ; 32 ] ) ,
142
+ )
143
+ . unwrap ( ) ;
144
+ let ( mut block_info_1, _block_proposal) = create_block_override ( |b| {
145
+ b. block . header . consensus_hash = old_miner_tenure_id;
146
+ b. block . header . miner_signature = MessageSignature ( [ 0x02 ; 65 ] ) ;
147
+ b. block . header . chain_length = 1 ;
148
+ b. burn_height = burn_block_height. saturating_sub ( 1 ) ;
149
+ } ) ;
150
+ db. insert_block ( & block_info_1) . unwrap ( ) ;
151
+
152
+ let ( mut block_info_2, _block_proposal) = create_block_override ( |b| {
153
+ b. block . header . consensus_hash = new_miner_tenure_id;
154
+ b. block . header . miner_signature = MessageSignature ( [ 0x01 ; 65 ] ) ;
155
+ b. block . header . chain_length = 1 ;
156
+ b. burn_height = burn_block_height;
157
+ } ) ;
158
+ db. insert_block ( & block_info_2) . unwrap ( ) ;
159
+
129
160
let signer_state_machine = SignerStateMachine {
130
161
burn_block,
131
162
burn_block_height,
@@ -135,35 +166,43 @@ fn check_capitulate_miner_view() {
135
166
} ;
136
167
137
168
let mut local_state_machine = LocalStateMachine :: Initialized ( signer_state_machine. clone ( ) ) ;
138
- assert_eq ! (
139
- local_state_machine
140
- . capitulate_miner_view( & mut global_eval, & mut db, local_address, & new_update)
141
- . unwrap( ) ,
142
- current_miner
143
- ) ;
144
169
145
- // Let's set a blocking minority to this different view: evaluator should see no global blocks for the blocking majority and return none
146
- // I.e. only if the blocking minority is attempting to reject an reorg should it take priority over the rest.
147
- // Let's update 1 other signer to some new miner key (60 percent)
148
- for address in addresses. into_iter ( ) . skip ( 1 ) . take ( 1 ) {
170
+ // Let's update 40 percent of other signers to some new miner key
171
+ for address in addresses. into_iter ( ) . take ( 4 ) {
149
172
global_eval. insert_update ( address, new_update. clone ( ) ) ;
150
173
}
174
+ // Miner view should be None as we can't find consensus on a single miner
151
175
assert ! (
152
176
local_state_machine
153
177
. capitulate_miner_view( & mut global_eval, & mut db, local_address, & new_update)
154
178
. is_none( ) ,
155
- "Evaluator should have been unable to determine a majority view and return none "
179
+ "Evaluator should have told me to capitulate to the old miner "
156
180
) ;
157
181
182
+ // Mark the old miner's block as globally accepted
158
183
db. mark_block_globally_accepted ( & mut block_info_1) . unwrap ( ) ;
159
-
160
184
db. insert_block ( & block_info_1) . unwrap ( ) ;
161
185
162
- // Now that the blocking minority references a tenure which would actually get reorged, lets capitulate to their view
186
+ // Miner view should stay as the old miner as it has a globally accepted block and 60% consider it valid.
187
+ assert_eq ! (
188
+ local_state_machine
189
+ . capitulate_miner_view( & mut global_eval, & mut db, local_address, & new_update)
190
+ . unwrap( ) ,
191
+ old_miner,
192
+ "Evaluator should have told me to capitulate to the old miner"
193
+ ) ;
194
+
195
+ // Now that we have a globally approved block for the new miner
196
+ db. mark_block_globally_accepted ( & mut block_info_2) . unwrap ( ) ;
197
+ db. insert_block ( & block_info_2) . unwrap ( ) ;
198
+
199
+ // Now that the blocking minority references a tenure which would actually get reorged, lets capitulate to the NEW view
200
+ // even though both the old and new signer have > 30% approval (it has a higher burn block).
163
201
assert_eq ! (
164
202
local_state_machine
165
203
. capitulate_miner_view( & mut global_eval, & mut db, local_address, & new_update)
166
204
. unwrap( ) ,
167
- new_miner
205
+ new_miner,
206
+ "Evaluator should have told me to capitulate to the new miner"
168
207
) ;
169
208
}
0 commit comments