@@ -27,6 +27,8 @@ use blockstack_lib::util_lib::db::{
27
27
#[ cfg( any( test, feature = "testing" ) ) ]
28
28
use blockstack_lib:: util_lib:: db:: { FromColumn , FromRow } ;
29
29
use clarity:: types:: chainstate:: { BurnchainHeaderHash , StacksAddress } ;
30
+ use clarity:: types:: Address ;
31
+ use libsigner:: v0:: messages:: { RejectReason , RejectReasonPrefix } ;
30
32
use libsigner:: BlockProposal ;
31
33
use rusqlite:: functions:: FunctionFlags ;
32
34
use rusqlite:: {
@@ -500,6 +502,11 @@ CREATE TABLE IF NOT EXISTS tenure_activity (
500
502
last_activity_time INTEGER NOT NULL
501
503
) STRICT;"# ;
502
504
505
+ static ADD_REJECT_CODE : & str = r#"
506
+ ALTER TABLE block_rejection_signer_addrs
507
+ ADD COLUMN reject_code INTEGER;
508
+ "# ;
509
+
503
510
static SCHEMA_1 : & [ & str ] = & [
504
511
DROP_SCHEMA_0 ,
505
512
CREATE_DB_CONFIG ,
@@ -564,9 +571,14 @@ static SCHEMA_8: &[&str] = &[
564
571
"INSERT INTO db_config (version) VALUES (8);" ,
565
572
] ;
566
573
574
+ static SCHEMA_9 : & [ & str ] = & [
575
+ ADD_REJECT_CODE ,
576
+ "INSERT INTO db_config (version) VALUES (9);" ,
577
+ ] ;
578
+
567
579
impl SignerDb {
568
580
/// The current schema version used in this build of the signer binary.
569
- pub const SCHEMA_VERSION : u32 = 8 ;
581
+ pub const SCHEMA_VERSION : u32 = 9 ;
570
582
571
583
/// Create a new `SignerState` instance.
572
584
/// This will create a new SQLite database at the given path
@@ -708,6 +720,20 @@ impl SignerDb {
708
720
Ok ( ( ) )
709
721
}
710
722
723
+ /// Migrate from schema 9 to schema 9
724
+ fn schema_9_migration ( tx : & Transaction ) -> Result < ( ) , DBError > {
725
+ if Self :: get_schema_version ( tx) ? >= 9 {
726
+ // no migration necessary
727
+ return Ok ( ( ) ) ;
728
+ }
729
+
730
+ for statement in SCHEMA_9 . iter ( ) {
731
+ tx. execute_batch ( statement) ?;
732
+ }
733
+
734
+ Ok ( ( ) )
735
+ }
736
+
711
737
/// Register custom scalar functions used by the database
712
738
fn register_scalar_functions ( & self ) -> Result < ( ) , DBError > {
713
739
// Register helper function for determining if a block is a tenure change transaction
@@ -749,7 +775,8 @@ impl SignerDb {
749
775
5 => Self :: schema_6_migration ( & sql_tx) ?,
750
776
6 => Self :: schema_7_migration ( & sql_tx) ?,
751
777
7 => Self :: schema_8_migration ( & sql_tx) ?,
752
- 8 => break ,
778
+ 8 => Self :: schema_9_migration ( & sql_tx) ?,
779
+ 9 => break ,
753
780
x => return Err ( DBError :: Other ( format ! (
754
781
"Database schema is newer than supported by this binary. Expected version = {}, Database version = {x}" ,
755
782
Self :: SCHEMA_VERSION ,
@@ -998,27 +1025,58 @@ impl SignerDb {
998
1025
& self ,
999
1026
block_sighash : & Sha512Trunc256Sum ,
1000
1027
addr : & StacksAddress ,
1028
+ reject_reason : & RejectReason ,
1001
1029
) -> Result < ( ) , DBError > {
1002
- let qry = "INSERT OR REPLACE INTO block_rejection_signer_addrs (signer_signature_hash, signer_addr) VALUES (?1, ?2);" ;
1003
- let args = params ! [ block_sighash, addr. to_string( ) , ] ;
1030
+ let qry = "INSERT OR REPLACE INTO block_rejection_signer_addrs (signer_signature_hash, signer_addr, reject_code) VALUES (?1, ?2, ?3);" ;
1031
+ let args = params ! [
1032
+ block_sighash,
1033
+ addr. to_string( ) ,
1034
+ RejectReasonPrefix :: from( reject_reason) as i64
1035
+ ] ;
1004
1036
1005
1037
debug ! ( "Inserting block rejection." ;
1006
- "block_sighash" => %block_sighash,
1007
- "signer_address" => %addr) ;
1038
+ "block_sighash" => %block_sighash,
1039
+ "signer_address" => %addr,
1040
+ "reject_reason" => %reject_reason
1041
+ ) ;
1008
1042
1009
1043
self . db . execute ( qry, args) ?;
1010
1044
Ok ( ( ) )
1011
1045
}
1012
1046
1013
- /// Get all signer addresses that rejected the block
1047
+ /// Get all signer addresses that rejected the block (and their reject codes)
1014
1048
pub fn get_block_rejection_signer_addrs (
1015
1049
& self ,
1016
1050
block_sighash : & Sha512Trunc256Sum ,
1017
- ) -> Result < Vec < StacksAddress > , DBError > {
1051
+ ) -> Result < Vec < ( StacksAddress , RejectReasonPrefix ) > , DBError > {
1018
1052
let qry =
1019
- "SELECT signer_addr FROM block_rejection_signer_addrs WHERE signer_signature_hash = ?1" ;
1053
+ "SELECT signer_addr, reject_code FROM block_rejection_signer_addrs WHERE signer_signature_hash = ?1" ;
1020
1054
let args = params ! [ block_sighash] ;
1021
- query_rows ( & self . db , qry, args)
1055
+ let mut stmt = self . db . prepare ( qry) ?;
1056
+
1057
+ let rows = stmt. query_map ( args, |row| {
1058
+ let addr: String = row. get ( 0 ) ?;
1059
+ let addr = StacksAddress :: from_string ( & addr) . ok_or ( SqliteError :: InvalidColumnType (
1060
+ 0 ,
1061
+ "signer_addr" . into ( ) ,
1062
+ rusqlite:: types:: Type :: Text ,
1063
+ ) ) ?;
1064
+ let reject_code: i64 = row. get ( 1 ) ?;
1065
+
1066
+ let reject_code = u8:: try_from ( reject_code)
1067
+ . map_err ( |_| {
1068
+ SqliteError :: InvalidColumnType (
1069
+ 1 ,
1070
+ "reject_code" . into ( ) ,
1071
+ rusqlite:: types:: Type :: Integer ,
1072
+ )
1073
+ } )
1074
+ . map ( RejectReasonPrefix :: from) ?;
1075
+
1076
+ Ok ( ( addr, reject_code) )
1077
+ } ) ?;
1078
+
1079
+ rows. collect :: < Result < Vec < _ > , _ > > ( ) . map_err ( |e| e. into ( ) )
1022
1080
}
1023
1081
1024
1082
/// Mark a block as having been broadcasted and therefore GloballyAccepted
0 commit comments