@@ -24,7 +24,6 @@ use blockstack_lib::util_lib::db::{
24
24
Error as DBError ,
25
25
} ;
26
26
use clarity:: types:: chainstate:: { BurnchainHeaderHash , StacksAddress } ;
27
- use clarity:: util:: secp256k1:: Secp256k1PublicKey ;
28
27
use libsigner:: BlockProposal ;
29
28
use rusqlite:: {
30
29
params, Connection , Error as SqliteError , OpenFlags , OptionalExtension , Transaction ,
@@ -158,31 +157,28 @@ pub struct BlockInfo {
158
157
pub signed_group : Option < u64 > ,
159
158
/// The block state relative to the signer's view of the stacks blockchain
160
159
pub state : BlockState ,
161
- /// The miner pubkey that proposed this block
162
- pub miner_pubkey : Secp256k1PublicKey ,
163
160
/// Extra data specific to v0, v1, etc.
164
161
pub ext : ExtraBlockInfo ,
165
162
}
166
163
167
- impl BlockInfo {
168
- /// Create a new block info from the provided proposal and corresponding miner pubkey
169
- pub fn new ( block_proposal : BlockProposal , miner_pubkey : Secp256k1PublicKey ) -> Self {
164
+ impl From < BlockProposal > for BlockInfo {
165
+ fn from ( value : BlockProposal ) -> Self {
170
166
Self {
171
- block : block_proposal . block ,
172
- burn_block_height : block_proposal . burn_height ,
173
- reward_cycle : block_proposal . reward_cycle ,
167
+ block : value . block ,
168
+ burn_block_height : value . burn_height ,
169
+ reward_cycle : value . reward_cycle ,
174
170
vote : None ,
175
171
valid : None ,
176
172
signed_over : false ,
177
173
proposed_time : get_epoch_time_secs ( ) ,
178
174
signed_self : None ,
179
175
signed_group : None ,
180
176
ext : ExtraBlockInfo :: default ( ) ,
181
- miner_pubkey,
182
177
state : BlockState :: Unprocessed ,
183
178
}
184
179
}
185
-
180
+ }
181
+ impl BlockInfo {
186
182
/// Mark this block as locally accepted, valid, signed over, and records either the self or group signed timestamp in the block info if it wasn't
187
183
/// already set.
188
184
pub fn mark_locally_accepted ( & mut self , group_signed : bool ) -> Result < ( ) , String > {
@@ -617,6 +613,18 @@ impl SignerDb {
617
613
try_deserialize ( result)
618
614
}
619
615
616
+ /// Return the last accepted block the signer (highest stacks height). It will tie break a match based on which was more recently signed.
617
+ pub fn get_signer_last_accepted_block ( & self ) -> Result < Option < BlockInfo > , DBError > {
618
+ let query = "SELECT block_info FROM blocks WHERE json_extract(block_info, '$.state') IN (?1, ?2) ORDER BY stacks_height DESC, json_extract(block_info, '$.signed_group') DESC, json_extract(block_info, '$.signed_self') DESC LIMIT 1" ;
619
+ let args = params ! [
620
+ & BlockState :: GloballyAccepted . to_string( ) ,
621
+ & BlockState :: LocallyAccepted . to_string( )
622
+ ] ;
623
+ let result: Option < String > = query_row ( & self . db , query, args) ?;
624
+
625
+ try_deserialize ( result)
626
+ }
627
+
620
628
/// Return the last accepted block in a tenure (identified by its consensus hash).
621
629
pub fn get_last_accepted_block (
622
630
& self ,
@@ -891,7 +899,7 @@ mod tests {
891
899
use std:: path:: PathBuf ;
892
900
893
901
use blockstack_lib:: chainstate:: nakamoto:: { NakamotoBlock , NakamotoBlockHeader } ;
894
- use clarity:: util:: secp256k1:: { MessageSignature , Secp256k1PrivateKey } ;
902
+ use clarity:: util:: secp256k1:: MessageSignature ;
895
903
use libsigner:: BlockProposal ;
896
904
897
905
use super :: * ;
@@ -917,13 +925,7 @@ mod tests {
917
925
reward_cycle : 42 ,
918
926
} ;
919
927
overrides ( & mut block_proposal) ;
920
- (
921
- BlockInfo :: new (
922
- block_proposal. clone ( ) ,
923
- Secp256k1PublicKey :: from_private ( & Secp256k1PrivateKey :: new ( ) ) ,
924
- ) ,
925
- block_proposal,
926
- )
928
+ ( BlockInfo :: from ( block_proposal. clone ( ) ) , block_proposal)
927
929
}
928
930
929
931
fn create_block ( ) -> ( BlockInfo , BlockProposal ) {
@@ -940,7 +942,6 @@ mod tests {
940
942
fn test_basic_signer_db_with_path ( db_path : impl AsRef < Path > ) {
941
943
let mut db = SignerDb :: new ( db_path) . expect ( "Failed to create signer db" ) ;
942
944
let ( block_info, block_proposal) = create_block ( ) ;
943
- let miner_pubkey = block_info. miner_pubkey ;
944
945
let reward_cycle = block_info. reward_cycle ;
945
946
db. insert_block ( & block_info)
946
947
. expect ( "Unable to insert block into db" ) ;
@@ -952,10 +953,7 @@ mod tests {
952
953
. unwrap ( )
953
954
. expect ( "Unable to get block from db" ) ;
954
955
955
- assert_eq ! (
956
- BlockInfo :: new( block_proposal. clone( ) , miner_pubkey) ,
957
- block_info
958
- ) ;
956
+ assert_eq ! ( BlockInfo :: from( block_proposal. clone( ) ) , block_info) ;
959
957
960
958
// Test looking up a block from a different reward cycle
961
959
let block_info = db
@@ -975,10 +973,7 @@ mod tests {
975
973
. unwrap ( )
976
974
. expect ( "Unable to get block state from db" ) ;
977
975
978
- assert_eq ! (
979
- block_state,
980
- BlockInfo :: new( block_proposal. clone( ) , miner_pubkey) . state
981
- ) ;
976
+ assert_eq ! ( block_state, BlockInfo :: from( block_proposal. clone( ) ) . state) ;
982
977
}
983
978
984
979
#[ test]
@@ -998,7 +993,6 @@ mod tests {
998
993
let db_path = tmp_db_path ( ) ;
999
994
let mut db = SignerDb :: new ( db_path) . expect ( "Failed to create signer db" ) ;
1000
995
let ( block_info, block_proposal) = create_block ( ) ;
1001
- let miner_pubkey = block_info. miner_pubkey ;
1002
996
let reward_cycle = block_info. reward_cycle ;
1003
997
db. insert_block ( & block_info)
1004
998
. expect ( "Unable to insert block into db" ) ;
@@ -1011,10 +1005,7 @@ mod tests {
1011
1005
. unwrap ( )
1012
1006
. expect ( "Unable to get block from db" ) ;
1013
1007
1014
- assert_eq ! (
1015
- BlockInfo :: new( block_proposal. clone( ) , miner_pubkey) ,
1016
- block_info
1017
- ) ;
1008
+ assert_eq ! ( BlockInfo :: from( block_proposal. clone( ) ) , block_info) ;
1018
1009
1019
1010
let old_block_info = block_info;
1020
1011
let old_block_proposal = block_proposal;
@@ -1338,4 +1329,69 @@ mod tests {
1338
1329
1339
1330
assert_eq ! ( db. get_canonical_tip( ) . unwrap( ) . unwrap( ) , block_info_2) ;
1340
1331
}
1332
+
1333
+ #[ test]
1334
+ fn signer_last_accepted_block ( ) {
1335
+ let db_path = tmp_db_path ( ) ;
1336
+ let mut db = SignerDb :: new ( db_path) . expect ( "Failed to create signer db" ) ;
1337
+
1338
+ let ( mut block_info_1, _block_proposal_1) = create_block_override ( |b| {
1339
+ b. block . header . miner_signature = MessageSignature ( [ 0x01 ; 65 ] ) ;
1340
+ b. block . header . chain_length = 1 ;
1341
+ b. burn_height = 1 ;
1342
+ } ) ;
1343
+
1344
+ let ( mut block_info_2, _block_proposal_2) = create_block_override ( |b| {
1345
+ b. block . header . miner_signature = MessageSignature ( [ 0x02 ; 65 ] ) ;
1346
+ b. block . header . chain_length = 2 ;
1347
+ b. burn_height = 1 ;
1348
+ } ) ;
1349
+
1350
+ let ( mut block_info_3, _block_proposal_3) = create_block_override ( |b| {
1351
+ b. block . header . miner_signature = MessageSignature ( [ 0x02 ; 65 ] ) ;
1352
+ b. block . header . chain_length = 2 ;
1353
+ b. burn_height = 4 ;
1354
+ } ) ;
1355
+ block_info_3
1356
+ . mark_locally_accepted ( false )
1357
+ . expect ( "Failed to mark block as locally accepted" ) ;
1358
+
1359
+ db. insert_block ( & block_info_1)
1360
+ . expect ( "Unable to insert block into db" ) ;
1361
+ db. insert_block ( & block_info_2)
1362
+ . expect ( "Unable to insert block into db" ) ;
1363
+
1364
+ assert ! ( db. get_signer_last_accepted_block( ) . unwrap( ) . is_none( ) ) ;
1365
+
1366
+ block_info_1
1367
+ . mark_globally_accepted ( )
1368
+ . expect ( "Failed to mark block as globally accepted" ) ;
1369
+ db. insert_block ( & block_info_1)
1370
+ . expect ( "Unable to insert block into db" ) ;
1371
+
1372
+ assert_eq ! (
1373
+ db. get_signer_last_accepted_block( ) . unwrap( ) . unwrap( ) ,
1374
+ block_info_1
1375
+ ) ;
1376
+
1377
+ block_info_2
1378
+ . mark_globally_accepted ( )
1379
+ . expect ( "Failed to mark block as globally accepted" ) ;
1380
+ block_info_2. signed_self = Some ( get_epoch_time_secs ( ) ) ;
1381
+ db. insert_block ( & block_info_2)
1382
+ . expect ( "Unable to insert block into db" ) ;
1383
+
1384
+ assert_eq ! (
1385
+ db. get_signer_last_accepted_block( ) . unwrap( ) . unwrap( ) ,
1386
+ block_info_2
1387
+ ) ;
1388
+
1389
+ db. insert_block ( & block_info_3)
1390
+ . expect ( "Unable to insert block into db" ) ;
1391
+
1392
+ assert_eq ! (
1393
+ db. get_signer_last_accepted_block( ) . unwrap( ) . unwrap( ) ,
1394
+ block_info_3
1395
+ ) ;
1396
+ }
1341
1397
}
0 commit comments