@@ -673,6 +673,18 @@ CREATE TABLE IF NOT EXISTS block_rejection_signer_addrs (
673
673
PRIMARY KEY (signer_signature_hash, signer_addr)
674
674
) STRICT;"# ;
675
675
676
+ static CREATE_BLOCK_PRE_COMMITS_TABLE : & str = r#"
677
+ CREATE TABLE IF NOT EXISTS block_pre_commits (
678
+ -- The block sighash commits to all of the stacks and burnchain state as of its parent,
679
+ -- as well as the tenure itself so there's no need to include the reward cycle. Just
680
+ -- the sighash is sufficient to uniquely identify the block across all burnchain, PoX,
681
+ -- and stacks forks.
682
+ signer_signature_hash TEXT NOT NULL,
683
+ -- signer address committing to sign the block
684
+ signer_addr TEXT NOT NULL,
685
+ PRIMARY KEY (signer_signature_hash, signer_addr)
686
+ ) STRICT;"# ;
687
+
676
688
static SCHEMA_1 : & [ & str ] = & [
677
689
DROP_SCHEMA_0 ,
678
690
CREATE_DB_CONFIG ,
@@ -786,6 +798,11 @@ static SCHEMA_16: &[&str] = &[
786
798
"INSERT INTO db_config (version) VALUES (16);" ,
787
799
] ;
788
800
801
+ static SCHEMA_17 : & [ & str ] = & [
802
+ CREATE_BLOCK_PRE_COMMITS_TABLE ,
803
+ "INSERT INTO db_config (version) VALUES (17);" ,
804
+ ] ;
805
+
789
806
struct Migration {
790
807
version : u32 ,
791
808
statements : & ' static [ & ' static str ] ,
@@ -856,11 +873,15 @@ static MIGRATIONS: &[Migration] = &[
856
873
version : 16 ,
857
874
statements : SCHEMA_16 ,
858
875
} ,
876
+ Migration {
877
+ version : 17 ,
878
+ statements : SCHEMA_17 ,
879
+ } ,
859
880
] ;
860
881
861
882
impl SignerDb {
862
883
/// The current schema version used in this build of the signer binary.
863
- pub const SCHEMA_VERSION : u32 = 16 ;
884
+ pub const SCHEMA_VERSION : u32 = 17 ;
864
885
865
886
/// Create a new `SignerState` instance.
866
887
/// This will create a new SQLite database at the given path
@@ -1821,6 +1842,62 @@ impl SignerDb {
1821
1842
1822
1843
Ok ( None )
1823
1844
}
1845
+
1846
+ /// Record an observed block pre commit
1847
+ pub fn add_block_pre_commit (
1848
+ & self ,
1849
+ block_sighash : & Sha512Trunc256Sum ,
1850
+ address : & StacksAddress ,
1851
+ ) -> Result < ( ) , DBError > {
1852
+ let qry = "INSERT OR REPLACE INTO block_pre_commits (signer_signature_hash, signer_addr) VALUES (?1, ?2);" ;
1853
+ let args = params ! [ block_sighash, address. to_string( ) ] ;
1854
+
1855
+ debug ! ( "Inserting block pre commit." ;
1856
+ "signer_signature_hash" => %block_sighash,
1857
+ "signer_addr" => %address) ;
1858
+
1859
+ self . db . execute ( qry, args) ?;
1860
+ Ok ( ( ) )
1861
+ }
1862
+
1863
+ /// Check if the given address has already committed to sign the block identified by block_sighash
1864
+ pub fn has_committed (
1865
+ & self ,
1866
+ block_sighash : & Sha512Trunc256Sum ,
1867
+ address : & StacksAddress ,
1868
+ ) -> Result < bool , DBError > {
1869
+ let qry_check = "
1870
+ SELECT 1 FROM block_pre_commits
1871
+ WHERE signer_signature_hash = ?1 AND signer_addr = ?2
1872
+ LIMIT 1;" ;
1873
+
1874
+ let exists: Option < u8 > = self
1875
+ . db
1876
+ . query_row (
1877
+ qry_check,
1878
+ params ! [ block_sighash, address. to_string( ) ] ,
1879
+ |row| row. get ( 0 ) ,
1880
+ )
1881
+ . optional ( ) ?;
1882
+
1883
+ Ok ( exists. is_some ( ) )
1884
+ }
1885
+
1886
+ /// Get all pre committers for a block
1887
+ pub fn get_block_pre_committers (
1888
+ & self ,
1889
+ block_sighash : & Sha512Trunc256Sum ,
1890
+ ) -> Result < Vec < StacksAddress > , DBError > {
1891
+ let qry = "SELECT signer_addr FROM block_pre_commits WHERE signer_signature_hash = ?1" ;
1892
+ let args = params ! [ block_sighash] ;
1893
+ let addrs_txt: Vec < String > = query_rows ( & self . db , qry, args) ?;
1894
+
1895
+ let res: Result < Vec < _ > , _ > = addrs_txt
1896
+ . into_iter ( )
1897
+ . map ( |addr| StacksAddress :: from_string ( & addr) . ok_or ( DBError :: Corruption ) )
1898
+ . collect ( ) ;
1899
+ res
1900
+ }
1824
1901
}
1825
1902
1826
1903
fn try_deserialize < T > ( s : Option < String > ) -> Result < Option < T > , DBError >
@@ -3381,4 +3458,56 @@ pub mod tests {
3381
3458
3382
3459
assert ! ( result_3. is_none( ) ) ;
3383
3460
}
3461
+
3462
+ #[ test]
3463
+ fn insert_and_get_state_block_pre_commits ( ) {
3464
+ let db_path = tmp_db_path ( ) ;
3465
+ let db = SignerDb :: new ( db_path) . expect ( "Failed to create signer db" ) ;
3466
+ let block_sighash1 = Sha512Trunc256Sum ( [ 1u8 ; 32 ] ) ;
3467
+ let address1 = StacksAddress :: p2pkh (
3468
+ false ,
3469
+ & StacksPublicKey :: from_private ( & StacksPrivateKey :: random ( ) ) ,
3470
+ ) ;
3471
+ let block_sighash2 = Sha512Trunc256Sum ( [ 2u8 ; 32 ] ) ;
3472
+ let address2 = StacksAddress :: p2pkh (
3473
+ false ,
3474
+ & StacksPublicKey :: from_private ( & StacksPrivateKey :: random ( ) ) ,
3475
+ ) ;
3476
+ let address3 = StacksAddress :: p2pkh (
3477
+ false ,
3478
+ & StacksPublicKey :: from_private ( & StacksPrivateKey :: random ( ) ) ,
3479
+ ) ;
3480
+ assert ! ( db
3481
+ . get_block_pre_committers( & block_sighash1)
3482
+ . unwrap( )
3483
+ . is_empty( ) ) ;
3484
+
3485
+ db. add_block_pre_commit ( & block_sighash1, & address1) . unwrap ( ) ;
3486
+ assert_eq ! (
3487
+ db. get_block_pre_committers( & block_sighash1) . unwrap( ) ,
3488
+ vec![ address1]
3489
+ ) ;
3490
+
3491
+ db. add_block_pre_commit ( & block_sighash1, & address2) . unwrap ( ) ;
3492
+ let commits = db. get_block_pre_committers ( & block_sighash1) . unwrap ( ) ;
3493
+ assert_eq ! ( commits. len( ) , 2 ) ;
3494
+ assert ! ( commits. contains( & address2) ) ;
3495
+ assert ! ( commits. contains( & address1) ) ;
3496
+
3497
+ db. add_block_pre_commit ( & block_sighash2, & address3) . unwrap ( ) ;
3498
+ let commits = db. get_block_pre_committers ( & block_sighash1) . unwrap ( ) ;
3499
+ assert_eq ! ( commits. len( ) , 2 ) ;
3500
+ assert ! ( commits. contains( & address2) ) ;
3501
+ assert ! ( commits. contains( & address1) ) ;
3502
+ let commits = db. get_block_pre_committers ( & block_sighash2) . unwrap ( ) ;
3503
+ assert_eq ! ( commits. len( ) , 1 ) ;
3504
+ assert ! ( commits. contains( & address3) ) ;
3505
+
3506
+ assert ! ( db. has_committed( & block_sighash1, & address1) . unwrap( ) ) ;
3507
+ assert ! ( db. has_committed( & block_sighash1, & address2) . unwrap( ) ) ;
3508
+ assert ! ( !db. has_committed( & block_sighash1, & address3) . unwrap( ) ) ;
3509
+ assert ! ( !db. has_committed( & block_sighash2, & address1) . unwrap( ) ) ;
3510
+ assert ! ( !db. has_committed( & block_sighash2, & address2) . unwrap( ) ) ;
3511
+ assert ! ( db. has_committed( & block_sighash2, & address3) . unwrap( ) ) ;
3512
+ }
3384
3513
}
0 commit comments