@@ -1227,26 +1227,6 @@ mod tests {
12271227 ) ;
12281228 }
12291229
1230- #[ tokio:: test]
1231- async fn mem_db_clashing_blocks ( ) {
1232- const SLOT : u64 = 123 ;
1233- let db = make_db ( ) ;
1234- let pubkey = random_core_pub_key ( ) ;
1235- let duty = Duty :: new ( SlotNumber :: new ( SLOT ) , DutyType :: Proposer ) ;
1236-
1237- let block1 = phase0_proposal ( SLOT , 1 ) ;
1238- let block2 = phase0_proposal ( SLOT , 2 ) ;
1239-
1240- let mut set1 = UnsignedDataSet :: new ( ) ;
1241- set1. insert ( pubkey, UnsignedDutyData :: Proposal ( Box :: new ( block1) ) ) ;
1242- db. store ( duty. clone ( ) , set1) . await . unwrap ( ) ;
1243-
1244- let mut set2 = UnsignedDataSet :: new ( ) ;
1245- set2. insert ( pubkey, UnsignedDutyData :: Proposal ( Box :: new ( block2) ) ) ;
1246- let err = db. store ( duty, set2) . await . unwrap_err ( ) ;
1247- assert ! ( err. to_string( ) . contains( "clashing blocks" ) , "got: {err}" ) ;
1248- }
1249-
12501230 #[ tokio:: test]
12511231 async fn mem_db_clash_proposer ( ) {
12521232 const SLOT : u64 = 123 ;
@@ -1311,4 +1291,183 @@ mod tests {
13111291 // Should no longer be findable.
13121292 assert ! ( db. pub_key_by_attestation( SLOT , 0 , 0 ) . await . is_err( ) ) ;
13131293 }
1294+
1295+ #[ tokio:: test]
1296+ async fn agg_attestation_two_roots_same_slot ( ) {
1297+ const SLOT : u64 = 300 ;
1298+ let db = make_db ( ) ;
1299+
1300+ // Two aggregations at the same slot but different committee indices
1301+ // produce different tree-hash roots and must coexist.
1302+ let agg_a = agg_attestation_fixture ( SLOT , 1 , 0 ) ;
1303+ let agg_b = agg_attestation_fixture ( SLOT , 2 , 0 ) ;
1304+ let root_a = agg_a. data ( ) . unwrap ( ) . tree_hash_root ( ) . 0 ;
1305+ let root_b = agg_b. data ( ) . unwrap ( ) . tree_hash_root ( ) . 0 ;
1306+ assert_ne ! ( root_a, root_b) ;
1307+
1308+ let duty = Duty :: new ( SlotNumber :: new ( SLOT ) , DutyType :: Aggregator ) ;
1309+ let mut set = UnsignedDataSet :: new ( ) ;
1310+ set. insert (
1311+ random_core_pub_key ( ) ,
1312+ UnsignedDutyData :: AggAttestation ( agg_a) ,
1313+ ) ;
1314+ set. insert (
1315+ random_core_pub_key ( ) ,
1316+ UnsignedDutyData :: AggAttestation ( agg_b) ,
1317+ ) ;
1318+ db. store ( duty, set) . await . unwrap ( ) ;
1319+
1320+ let att_a = db. await_agg_attestation ( root_a) . await . unwrap ( ) ;
1321+ assert_eq ! ( att_a. attestation. unwrap( ) . data( ) . slot, SLOT ) ;
1322+
1323+ let att_b = db. await_agg_attestation ( root_b) . await . unwrap ( ) ;
1324+ assert_eq ! ( att_b. attestation. unwrap( ) . data( ) . slot, SLOT ) ;
1325+ }
1326+
1327+ #[ tokio:: test]
1328+ async fn concurrent_attestation_waiters ( ) {
1329+ const SLOT : u64 = 400 ;
1330+ const COMM_IDX : u64 = 5 ;
1331+ const N : usize = 100 ;
1332+
1333+ let db = Arc :: new ( make_db ( ) ) ;
1334+ let handles: Vec < _ > = ( 0 ..N )
1335+ . map ( |_| {
1336+ let db = Arc :: clone ( & db) ;
1337+ tokio:: spawn ( async move { db. await_attestation ( SLOT , COMM_IDX ) . await } )
1338+ } )
1339+ . collect ( ) ;
1340+
1341+ tokio:: task:: yield_now ( ) . await ;
1342+
1343+ let att = att_data ( SLOT , COMM_IDX , 0 ) ;
1344+ let mut set = UnsignedDataSet :: new ( ) ;
1345+ set. insert ( random_core_pub_key ( ) , UnsignedDutyData :: Attestation ( att) ) ;
1346+ db. store ( Duty :: new ( SlotNumber :: new ( SLOT ) , DutyType :: Attester ) , set)
1347+ . await
1348+ . unwrap ( ) ;
1349+
1350+ for handle in handles {
1351+ let data = handle. await . unwrap ( ) . unwrap ( ) ;
1352+ assert_eq ! ( data. slot, SLOT ) ;
1353+ assert_eq ! ( data. index, COMM_IDX ) ;
1354+ }
1355+ }
1356+
1357+ #[ tokio:: test]
1358+ async fn await_attestation_before_store ( ) {
1359+ const SLOT : u64 = 500 ;
1360+ const COMM_IDX : u64 = 2 ;
1361+
1362+ let db = Arc :: new ( make_db ( ) ) ;
1363+ let handles: Vec < _ > = ( 0 ..3 )
1364+ . map ( |_| {
1365+ let db = Arc :: clone ( & db) ;
1366+ tokio:: spawn ( async move { db. await_attestation ( SLOT , COMM_IDX ) . await } )
1367+ } )
1368+ . collect ( ) ;
1369+
1370+ tokio:: task:: yield_now ( ) . await ;
1371+
1372+ let att = att_data ( SLOT , COMM_IDX , 0 ) ;
1373+ let mut set = UnsignedDataSet :: new ( ) ;
1374+ set. insert ( random_core_pub_key ( ) , UnsignedDutyData :: Attestation ( att) ) ;
1375+ db. store ( Duty :: new ( SlotNumber :: new ( SLOT ) , DutyType :: Attester ) , set)
1376+ . await
1377+ . unwrap ( ) ;
1378+
1379+ for handle in handles {
1380+ handle. await . unwrap ( ) . unwrap ( ) ;
1381+ }
1382+ }
1383+
1384+ #[ tokio:: test]
1385+ async fn await_before_shutdown ( ) {
1386+ let db = Arc :: new ( make_db ( ) ) ;
1387+
1388+ let db_clone = Arc :: clone ( & db) ;
1389+ let waiter = tokio:: spawn ( async move { db_clone. await_attestation ( 9999 , 0 ) . await } ) ;
1390+
1391+ tokio:: task:: yield_now ( ) . await ;
1392+ db. shutdown ( ) ;
1393+
1394+ let err = waiter. await . unwrap ( ) . unwrap_err ( ) ;
1395+ assert ! (
1396+ err. to_string( ) . contains( "shutdown" ) ,
1397+ "expected shutdown error, got: {err}"
1398+ ) ;
1399+ }
1400+
1401+ #[ tokio:: test]
1402+ async fn shutdown_wakes_await_attestation ( ) {
1403+ let db = make_db ( ) ;
1404+ db. shutdown ( ) ;
1405+
1406+ let err = db. await_attestation ( 0 , 0 ) . await . unwrap_err ( ) ;
1407+ assert ! ( err. to_string( ) . contains( "shutdown" ) , "got: {err}" ) ;
1408+ }
1409+
1410+ #[ tokio:: test]
1411+ async fn shutdown_wakes_await_agg_attestation ( ) {
1412+ let db = make_db ( ) ;
1413+ db. shutdown ( ) ;
1414+
1415+ let err = db. await_agg_attestation ( [ 0u8 ; 32 ] ) . await . unwrap_err ( ) ;
1416+ assert ! ( err. to_string( ) . contains( "shutdown" ) , "got: {err}" ) ;
1417+ }
1418+
1419+ #[ tokio:: test]
1420+ async fn invalid_unsigned_type_proposer ( ) {
1421+ let db = make_db ( ) ;
1422+ let duty = Duty :: new ( SlotNumber :: new ( 1 ) , DutyType :: Proposer ) ;
1423+ let mut set = UnsignedDataSet :: new ( ) ;
1424+ set. insert (
1425+ random_core_pub_key ( ) ,
1426+ UnsignedDutyData :: Attestation ( att_data ( 1 , 0 , 0 ) ) ,
1427+ ) ;
1428+ let err = db. store ( duty, set) . await . unwrap_err ( ) ;
1429+ assert ! ( matches!( err, Error :: InvalidVersionedProposal ) , "got: {err}" ) ;
1430+ }
1431+
1432+ #[ tokio:: test]
1433+ async fn invalid_unsigned_type_attester ( ) {
1434+ let db = make_db ( ) ;
1435+ let duty = Duty :: new ( SlotNumber :: new ( 1 ) , DutyType :: Attester ) ;
1436+ let mut set = UnsignedDataSet :: new ( ) ;
1437+ set. insert (
1438+ random_core_pub_key ( ) ,
1439+ UnsignedDutyData :: Proposal ( Box :: new ( phase0_proposal ( 1 , 0 ) ) ) ,
1440+ ) ;
1441+ let err = db. store ( duty, set) . await . unwrap_err ( ) ;
1442+ assert ! ( matches!( err, Error :: InvalidAttestationData ) , "got: {err}" ) ;
1443+ }
1444+
1445+ #[ tokio:: test]
1446+ async fn invalid_unsigned_type_aggregator ( ) {
1447+ let db = make_db ( ) ;
1448+ let duty = Duty :: new ( SlotNumber :: new ( 1 ) , DutyType :: Aggregator ) ;
1449+ let mut set = UnsignedDataSet :: new ( ) ;
1450+ set. insert (
1451+ random_core_pub_key ( ) ,
1452+ UnsignedDutyData :: Attestation ( att_data ( 1 , 0 , 0 ) ) ,
1453+ ) ;
1454+ let err = db. store ( duty, set) . await . unwrap_err ( ) ;
1455+ assert ! (
1456+ matches!( err, Error :: InvalidAggregatedAttestation ) ,
1457+ "got: {err}"
1458+ ) ;
1459+ }
1460+
1461+ #[ tokio:: test]
1462+ async fn invalid_unsigned_type_sync_contribution ( ) {
1463+ let db = make_db ( ) ;
1464+ let duty = Duty :: new ( SlotNumber :: new ( 1 ) , DutyType :: SyncContribution ) ;
1465+ let mut set = UnsignedDataSet :: new ( ) ;
1466+ set. insert (
1467+ random_core_pub_key ( ) ,
1468+ UnsignedDutyData :: Attestation ( att_data ( 1 , 0 , 0 ) ) ,
1469+ ) ;
1470+ let err = db. store ( duty, set) . await . unwrap_err ( ) ;
1471+ assert ! ( matches!( err, Error :: InvalidSyncContribution ) , "got: {err}" ) ;
1472+ }
13141473}
0 commit comments