EIP-3076 tests - complete database (#4958)

* EIP-3076 interchange tests: Add `should_succeed_complete` boolean.

This new added `should_succeed_complete` boolean means the test should succeed using
complete anti-slashing DB, while the untouched `should_succeed` boolean is
still implicitely reserved for minimal anti-slashing DB.

Note:
This commit only adds the new `should_succeed_complete` boolean, and copy the value from
`should_succeed` without any meaning regarding the value this boolean should
take.

* `TestEIP3076SpecTests`: Modify two tests

Those two tests are modified in a way they both comply with minimal AND
complete anti-slashing DB.

* Disallow false positives and differentiate more minimal vs complete cases

* Fix my own typos

* Update to v5.3.0 tag

---------

Co-authored-by: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
Manu NALEPA 2023-12-05 00:49:50 +01:00 committed by GitHub
parent 4250385ae1
commit ec8edfb89a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 183 additions and 165 deletions

View File

@ -1,4 +1,4 @@
TESTS_TAG := v5.2.1 TESTS_TAG := v5.3.0
GENERATE_DIR := generated-tests GENERATE_DIR := generated-tests
OUTPUT_DIR := interchange-tests OUTPUT_DIR := interchange-tests
TARBALL := $(OUTPUT_DIR)-$(TESTS_TAG).tar.gz TARBALL := $(OUTPUT_DIR)-$(TESTS_TAG).tar.gz

View File

@ -70,14 +70,18 @@ fn interchange_with_signing_roots(
} }
fn main() { fn main() {
let single_validator_blocks = let single_validator_blocks = vec![
vec![(0, 32, false), (0, 33, true), (0, 31, false), (0, 1, false)]; (0, 32, false, false),
(0, 33, true, true),
(0, 31, false, false),
(0, 1, false, false),
];
let single_validator_attestations = vec![ let single_validator_attestations = vec![
(0, 3, 4, false), (0, 3, 4, false, false),
(0, 14, 19, false), (0, 14, 19, false, false),
(0, 15, 20, false), (0, 15, 20, false, false),
(0, 16, 20, false), (0, 16, 20, false, false),
(0, 15, 21, true), (0, 15, 21, true, true),
]; ];
let tests = vec![ let tests = vec![
@ -104,7 +108,7 @@ fn main() {
MultiTestCase::single( MultiTestCase::single(
"single_validator_genesis_attestation", "single_validator_genesis_attestation",
TestCase::new(interchange(vec![(0, vec![], vec![(0, 0)])])) TestCase::new(interchange(vec![(0, vec![], vec![(0, 0)])]))
.with_attestations(vec![(0, 0, 0, false)]), .with_attestations(vec![(0, 0, 0, false, false)]),
), ),
MultiTestCase::single( MultiTestCase::single(
"single_validator_multiple_blocks_and_attestations", "single_validator_multiple_blocks_and_attestations",
@ -114,23 +118,23 @@ fn main() {
vec![(10, 11), (12, 13), (20, 24)], vec![(10, 11), (12, 13), (20, 24)],
)])) )]))
.with_blocks(vec![ .with_blocks(vec![
(0, 1, false), (0, 1, false, false),
(0, 2, false), (0, 2, false, false),
(0, 3, false), (0, 3, false, false),
(0, 10, false), (0, 10, false, false),
(0, 1200, false), (0, 1200, false, false),
(0, 4, true), (0, 4, false, true),
(0, 256, true), (0, 256, false, true),
(0, 1201, true), (0, 1201, true, true),
]) ])
.with_attestations(vec![ .with_attestations(vec![
(0, 9, 10, false), (0, 9, 10, false, false),
(0, 12, 13, false), (0, 12, 13, false, false),
(0, 11, 14, false), (0, 11, 14, false, false),
(0, 21, 22, false), (0, 21, 22, false, false),
(0, 10, 24, false), (0, 10, 24, false, false),
(0, 11, 12, true), (0, 11, 12, false, true),
(0, 20, 25, true), (0, 20, 25, true, true),
]), ]),
), ),
MultiTestCase::single( MultiTestCase::single(
@ -157,30 +161,30 @@ fn main() {
(2, vec![10, 15, 20], vec![(1, 2), (1, 3), (2, 4)]), (2, vec![10, 15, 20], vec![(1, 2), (1, 3), (2, 4)]),
])) ]))
.with_blocks(vec![ .with_blocks(vec![
(0, 9, false), (0, 9, false, false),
(0, 10, false), (0, 10, false, false),
(0, 21, true), (0, 21, true, true),
(0, 11, true), (0, 11, false, true),
(1, 2, false), (1, 2, false, false),
(1, 3, false), (1, 3, false, false),
(1, 0, false), (1, 0, false, false),
(1, 101, true), (1, 101, true, true),
(2, 9, false), (2, 9, false, false),
(2, 10, false), (2, 10, false, false),
(2, 22, true), (2, 22, true, true),
]) ])
.with_attestations(vec![ .with_attestations(vec![
(0, 0, 5, false), (0, 0, 5, false, false),
(0, 3, 6, false), (0, 3, 6, false, false),
(0, 4, 6, true), (0, 4, 6, true, true),
(0, 5, 7, true), (0, 5, 7, true, true),
(0, 6, 8, true), (0, 6, 8, true, true),
(1, 1, 7, false), (1, 1, 7, false, false),
(1, 1, 4, true), (1, 1, 4, false, true),
(1, 5, 7, true), (1, 5, 7, true, true),
(2, 0, 0, false), (2, 0, 0, false, false),
(2, 0, 1, false), (2, 0, 1, false, false),
(2, 2, 5, true), (2, 2, 5, true, true),
]), ]),
), ),
MultiTestCase::single( MultiTestCase::single(
@ -202,16 +206,16 @@ fn main() {
TestCase::new(interchange(vec![(0, vec![40], vec![(2, 30)])])), TestCase::new(interchange(vec![(0, vec![40], vec![(2, 30)])])),
TestCase::new(interchange(vec![(0, vec![50], vec![(10, 50)])])) TestCase::new(interchange(vec![(0, vec![50], vec![(10, 50)])]))
.with_blocks(vec![ .with_blocks(vec![
(0, 41, false), (0, 41, false, true),
(0, 45, false), (0, 45, false, true),
(0, 49, false), (0, 49, false, true),
(0, 50, false), (0, 50, false, false),
(0, 51, true), (0, 51, true, true),
]) ])
.with_attestations(vec![ .with_attestations(vec![
(0, 3, 31, false), (0, 3, 31, false, true),
(0, 9, 49, false), (0, 9, 49, false, true),
(0, 10, 51, true), (0, 10, 51, true, true),
]), ]),
], ],
), ),
@ -221,20 +225,20 @@ fn main() {
TestCase::new(interchange(vec![(0, vec![40], vec![])])), TestCase::new(interchange(vec![(0, vec![40], vec![])])),
TestCase::new(interchange(vec![(0, vec![20], vec![])])) TestCase::new(interchange(vec![(0, vec![20], vec![])]))
.contains_slashable_data() .contains_slashable_data()
.with_blocks(vec![(0, 20, false)]), .with_blocks(vec![(0, 20, false, false)]),
], ],
), ),
MultiTestCase::new( MultiTestCase::new(
"multiple_interchanges_single_validator_multiple_blocks_out_of_order", "multiple_interchanges_single_validator_multiple_blocks_out_of_order",
vec![ vec![
TestCase::new(interchange(vec![(0, vec![0], vec![])])).with_blocks(vec![ TestCase::new(interchange(vec![(0, vec![0], vec![])])).with_blocks(vec![
(0, 10, true), (0, 10, true, true),
(0, 20, true), (0, 20, true, true),
(0, 30, true), (0, 30, true, true),
]), ]),
TestCase::new(interchange(vec![(0, vec![20], vec![])])) TestCase::new(interchange(vec![(0, vec![20], vec![])]))
.contains_slashable_data() .contains_slashable_data()
.with_blocks(vec![(0, 29, false)]), .with_blocks(vec![(0, 29, false, true)]),
], ],
), ),
MultiTestCase::new( MultiTestCase::new(
@ -243,7 +247,7 @@ fn main() {
TestCase::new(interchange(vec![(0, vec![40], vec![])])), TestCase::new(interchange(vec![(0, vec![40], vec![])])),
TestCase::new(interchange(vec![(0, vec![20, 50], vec![])])) TestCase::new(interchange(vec![(0, vec![20, 50], vec![])]))
.contains_slashable_data() .contains_slashable_data()
.with_blocks(vec![(0, 20, false), (0, 50, false)]), .with_blocks(vec![(0, 20, false, false), (0, 50, false, false)]),
], ],
), ),
MultiTestCase::new( MultiTestCase::new(
@ -253,10 +257,10 @@ fn main() {
TestCase::new(interchange(vec![(0, vec![], vec![(10, 11)])])) TestCase::new(interchange(vec![(0, vec![], vec![(10, 11)])]))
.contains_slashable_data() .contains_slashable_data()
.with_attestations(vec![ .with_attestations(vec![
(0, 10, 14, false), (0, 10, 14, false, false),
(0, 12, 13, false), (0, 12, 13, false, false),
(0, 12, 14, true), (0, 12, 14, true, true),
(0, 13, 15, true), (0, 13, 15, true, true),
]), ]),
], ],
), ),
@ -267,11 +271,11 @@ fn main() {
TestCase::new(interchange(vec![(0, vec![], vec![(9, 21)])])) TestCase::new(interchange(vec![(0, vec![], vec![(9, 21)])]))
.contains_slashable_data() .contains_slashable_data()
.with_attestations(vec![ .with_attestations(vec![
(0, 10, 20, false), (0, 10, 20, false, false),
(0, 10, 21, false), (0, 10, 21, false, false),
(0, 9, 21, false), (0, 9, 21, false, false),
(0, 9, 22, false), (0, 9, 22, false, false),
(0, 10, 22, true), (0, 10, 22, true, true),
]), ]),
], ],
), ),
@ -282,11 +286,11 @@ fn main() {
TestCase::new(interchange(vec![(0, vec![], vec![(10, 20)])])) TestCase::new(interchange(vec![(0, vec![], vec![(10, 20)])]))
.contains_slashable_data() .contains_slashable_data()
.with_attestations(vec![ .with_attestations(vec![
(0, 10, 20, false), (0, 10, 20, false, false),
(0, 10, 21, false), (0, 10, 21, false, false),
(0, 9, 21, false), (0, 9, 21, false, false),
(0, 9, 22, false), (0, 9, 22, false, false),
(0, 10, 22, true), (0, 10, 22, true, true),
]), ]),
], ],
), ),
@ -303,13 +307,13 @@ fn main() {
])) ]))
.contains_slashable_data() .contains_slashable_data()
.with_blocks(vec![ .with_blocks(vec![
(0, 0, false), (0, 0, false, false),
(0, 3, true), (0, 3, false, true),
(0, 7, true), (0, 7, true, true),
(0, 3, true), (0, 3, false, true),
(1, 0, false), (1, 0, false, false),
]) ])
.with_attestations(vec![(0, 0, 4, false), (1, 0, 4, true)]), .with_attestations(vec![(0, 0, 4, false, false), (1, 0, 4, true, true)]),
], ],
), ),
MultiTestCase::new( MultiTestCase::new(
@ -330,9 +334,9 @@ fn main() {
])) ]))
.contains_slashable_data() .contains_slashable_data()
.with_attestations(vec![ .with_attestations(vec![
(0, 0, 4, false), (0, 0, 4, false, false),
(1, 1, 2, false), (1, 1, 2, false, false),
(2, 1, 2, false), (2, 1, 2, false, false),
]), ]),
], ],
), ),
@ -351,23 +355,23 @@ fn main() {
])) ]))
.contains_slashable_data() .contains_slashable_data()
.with_blocks(vec![ .with_blocks(vec![
(0, 100, false), (0, 100, false, false),
(1, 101, false), (1, 101, false, false),
(2, 102, false), (2, 102, false, false),
(0, 103, true), (0, 103, true, true),
(1, 104, true), (1, 104, true, true),
(2, 105, true), (2, 105, true, true),
]) ])
.with_attestations(vec![ .with_attestations(vec![
(0, 12, 13, false), (0, 12, 13, false, false),
(0, 11, 14, false), (0, 11, 14, false, false),
(1, 12, 13, false), (1, 12, 13, false, false),
(1, 11, 14, false), (1, 11, 14, false, false),
(2, 12, 13, false), (2, 12, 13, false, false),
(2, 11, 14, false), (2, 11, 14, false, false),
(0, 12, 14, true), (0, 12, 14, true, true),
(1, 13, 14, true), (1, 13, 14, true, true),
(2, 13, 14, true), (2, 13, 14, true, true),
]), ]),
], ],
), ),
@ -379,36 +383,36 @@ fn main() {
"single_validator_source_greater_than_target_surrounding", "single_validator_source_greater_than_target_surrounding",
TestCase::new(interchange(vec![(0, vec![], vec![(5, 2)])])) TestCase::new(interchange(vec![(0, vec![], vec![(5, 2)])]))
.contains_slashable_data() .contains_slashable_data()
.with_attestations(vec![(0, 3, 4, false)]), .with_attestations(vec![(0, 3, 4, false, false)]),
), ),
MultiTestCase::single( MultiTestCase::single(
"single_validator_source_greater_than_target_surrounded", "single_validator_source_greater_than_target_surrounded",
TestCase::new(interchange(vec![(0, vec![], vec![(5, 2)])])) TestCase::new(interchange(vec![(0, vec![], vec![(5, 2)])]))
.contains_slashable_data() .contains_slashable_data()
.with_attestations(vec![(0, 6, 1, false)]), .with_attestations(vec![(0, 6, 1, false, false)]),
), ),
MultiTestCase::single( MultiTestCase::single(
"single_validator_source_greater_than_target_sensible_iff_minified", "single_validator_source_greater_than_target_sensible_iff_minified",
TestCase::new(interchange(vec![(0, vec![], vec![(5, 2), (6, 7)])])) TestCase::new(interchange(vec![(0, vec![], vec![(5, 2), (6, 7)])]))
.contains_slashable_data() .contains_slashable_data()
.with_attestations(vec![(0, 5, 8, false), (0, 6, 8, true)]), .with_attestations(vec![(0, 5, 8, false, false), (0, 6, 8, true, true)]),
), ),
MultiTestCase::single( MultiTestCase::single(
"single_validator_out_of_order_blocks", "single_validator_out_of_order_blocks",
TestCase::new(interchange(vec![(0, vec![6, 5], vec![])])).with_blocks(vec![ TestCase::new(interchange(vec![(0, vec![6, 5], vec![])])).with_blocks(vec![
(0, 5, false), (0, 5, false, false),
(0, 6, false), (0, 6, false, false),
(0, 7, true), (0, 7, true, true),
]), ]),
), ),
MultiTestCase::single( MultiTestCase::single(
"single_validator_out_of_order_attestations", "single_validator_out_of_order_attestations",
TestCase::new(interchange(vec![(0, vec![], vec![(4, 5), (3, 4)])])).with_attestations( TestCase::new(interchange(vec![(0, vec![], vec![(4, 5), (3, 4)])])).with_attestations(
vec![ vec![
(0, 3, 4, false), (0, 3, 4, false, false),
(0, 4, 5, false), (0, 4, 5, false, false),
(0, 1, 10, false), (0, 1, 10, false, false),
(0, 3, 3, false), (0, 3, 3, false, false),
], ],
), ),
), ),
@ -417,15 +421,15 @@ fn main() {
MultiTestCase::single( MultiTestCase::single(
"single_validator_two_blocks_no_signing_root", "single_validator_two_blocks_no_signing_root",
TestCase::new(interchange(vec![(0, vec![10, 20], vec![])])) TestCase::new(interchange(vec![(0, vec![10, 20], vec![])]))
.with_blocks(vec![(0, 20, false)]), .with_blocks(vec![(0, 20, false, false)]),
), ),
MultiTestCase::single( MultiTestCase::single(
"single_validator_multiple_block_attempts", "single_validator_multiple_block_attempts",
TestCase::new(interchange(vec![(0, vec![15, 16, 17], vec![])])) TestCase::new(interchange(vec![(0, vec![15, 16, 17], vec![])]))
.with_signing_root_blocks(vec![ .with_signing_root_blocks(vec![
(0, 16, 0, false), (0, 16, 0, false, false),
(0, 16, 1, false), (0, 16, 1, false, false),
(0, 16, u64::MAX, false), (0, 16, u64::MAX, false, false),
]), ]),
), ),
MultiTestCase::single( MultiTestCase::single(
@ -436,15 +440,15 @@ fn main() {
vec![], vec![],
)])) )]))
.with_signing_root_blocks(vec![ .with_signing_root_blocks(vec![
(0, 15, 151, true), (0, 15, 151, false, true),
(0, 16, 161, true), (0, 16, 161, false, true),
(0, 17, 171, true), (0, 17, 171, false, true),
(0, 15, 152, false), (0, 15, 152, false, false),
(0, 15, 0, false), (0, 15, 0, false, false),
(0, 16, 151, false), (0, 16, 151, false, false),
(0, 17, 151, false), (0, 17, 151, false, false),
(0, 18, 151, true), (0, 18, 151, true, true),
(0, 14, 171, false), (0, 14, 171, false, false),
]), ]),
), ),
MultiTestCase::single( MultiTestCase::single(
@ -455,11 +459,11 @@ fn main() {
vec![(5, 15, Some(515))], vec![(5, 15, Some(515))],
)])) )]))
.with_signing_root_attestations(vec![ .with_signing_root_attestations(vec![
(0, 5, 15, 0, false), (0, 5, 15, 0, false, false),
(0, 5, 15, 1, false), (0, 5, 15, 1, false, false),
(0, 5, 15, 515, true), (0, 5, 15, 515, false, true),
(0, 6, 15, 615, false), (0, 6, 15, 615, false, false),
(0, 5, 14, 515, false), (0, 5, 14, 515, false, false),
]), ]),
), ),
MultiTestCase::single( MultiTestCase::single(
@ -500,8 +504,12 @@ fn main() {
(0, vec![10, 11], vec![(0, 2)]), (0, vec![10, 11], vec![(0, 2)]),
(0, vec![12, 13], vec![(1, 3)]), (0, vec![12, 13], vec![(1, 3)]),
])) ]))
.with_blocks(vec![(0, 10, false), (0, 13, false), (0, 14, true)]) .with_blocks(vec![
.with_attestations(vec![(0, 0, 2, false), (0, 1, 3, false)]), (0, 10, false, false),
(0, 13, false, false),
(0, 14, true, true),
])
.with_attestations(vec![(0, 0, 2, false, false), (0, 1, 3, false, false)]),
), ),
MultiTestCase::single( MultiTestCase::single(
"duplicate_pubkey_slashable_block", "duplicate_pubkey_slashable_block",
@ -510,7 +518,7 @@ fn main() {
(0, vec![10], vec![(1, 3)]), (0, vec![10], vec![(1, 3)]),
])) ]))
.contains_slashable_data() .contains_slashable_data()
.with_blocks(vec![(0, 10, false), (0, 11, true)]), .with_blocks(vec![(0, 10, false, false), (0, 11, true, true)]),
), ),
MultiTestCase::single( MultiTestCase::single(
"duplicate_pubkey_slashable_attestation", "duplicate_pubkey_slashable_attestation",
@ -520,10 +528,10 @@ fn main() {
])) ]))
.contains_slashable_data() .contains_slashable_data()
.with_attestations(vec![ .with_attestations(vec![
(0, 0, 1, false), (0, 0, 1, false, false),
(0, 0, 2, false), (0, 0, 2, false, false),
(0, 0, 4, false), (0, 0, 4, false, false),
(0, 1, 4, true), (0, 1, 4, true, true),
]), ]),
), ),
]; ];

View File

@ -33,6 +33,7 @@ pub struct TestBlock {
pub slot: Slot, pub slot: Slot,
pub signing_root: Hash256, pub signing_root: Hash256,
pub should_succeed: bool, pub should_succeed: bool,
pub should_succeed_complete: bool,
} }
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
@ -43,6 +44,7 @@ pub struct TestAttestation {
pub target_epoch: Epoch, pub target_epoch: Epoch,
pub signing_root: Hash256, pub signing_root: Hash256,
pub should_succeed: bool, pub should_succeed: bool,
pub should_succeed_complete: bool,
} }
impl MultiTestCase { impl MultiTestCase {
@ -68,10 +70,6 @@ impl MultiTestCase {
let slashing_db_file = dir.path().join("slashing_protection.sqlite"); let slashing_db_file = dir.path().join("slashing_protection.sqlite");
let slashing_db = SlashingDatabase::create(&slashing_db_file).unwrap(); let slashing_db = SlashingDatabase::create(&slashing_db_file).unwrap();
// Now that we are using implicit minification on import, we must always allow
// false positives.
let allow_false_positives = true;
for test_case in &self.steps { for test_case in &self.steps {
// If the test case is marked as containing slashable data, then the spec allows us to // If the test case is marked as containing slashable data, then the spec allows us to
// fail to import the file. However, we minify on import and ignore slashable data, so // fail to import the file. However, we minify on import and ignore slashable data, so
@ -124,7 +122,7 @@ impl MultiTestCase {
i, self.name, safe i, self.name, safe
); );
} }
Err(e) if block.should_succeed && !allow_false_positives => { Err(e) if block.should_succeed => {
panic!( panic!(
"block {} from `{}` failed when it should have succeeded: {:?}", "block {} from `{}` failed when it should have succeeded: {:?}",
i, self.name, e i, self.name, e
@ -147,7 +145,7 @@ impl MultiTestCase {
i, self.name, safe i, self.name, safe
); );
} }
Err(e) if att.should_succeed && !allow_false_positives => { Err(e) if att.should_succeed => {
panic!( panic!(
"attestation {} from `{}` failed when it should have succeeded: {:?}", "attestation {} from `{}` failed when it should have succeeded: {:?}",
i, self.name, e i, self.name, e
@ -181,53 +179,65 @@ impl TestCase {
self self
} }
pub fn with_blocks(self, blocks: impl IntoIterator<Item = (usize, u64, bool)>) -> Self { pub fn with_blocks(self, blocks: impl IntoIterator<Item = (usize, u64, bool, bool)>) -> Self {
self.with_signing_root_blocks( self.with_signing_root_blocks(blocks.into_iter().map(
blocks |(index, slot, should_succeed, should_succeed_complete)| {
.into_iter() (index, slot, 0, should_succeed, should_succeed_complete)
.map(|(index, slot, should_succeed)| (index, slot, 0, should_succeed)), },
) ))
} }
pub fn with_signing_root_blocks( pub fn with_signing_root_blocks(
mut self, mut self,
blocks: impl IntoIterator<Item = (usize, u64, u64, bool)>, blocks: impl IntoIterator<Item = (usize, u64, u64, bool, bool)>,
) -> Self { ) -> Self {
self.blocks.extend( self.blocks.extend(blocks.into_iter().map(
blocks |(pk, slot, signing_root, should_succeed, should_succeed_complete)| {
.into_iter() assert!(
.map(|(pk, slot, signing_root, should_succeed)| TestBlock { !should_succeed || should_succeed_complete,
"if should_succeed is true then should_succeed_complete must also be true"
);
TestBlock {
pubkey: pubkey(pk), pubkey: pubkey(pk),
slot: Slot::new(slot), slot: Slot::new(slot),
signing_root: Hash256::from_low_u64_be(signing_root), signing_root: Hash256::from_low_u64_be(signing_root),
should_succeed, should_succeed,
}), should_succeed_complete,
); }
},
));
self self
} }
pub fn with_attestations( pub fn with_attestations(
self, self,
attestations: impl IntoIterator<Item = (usize, u64, u64, bool)>, attestations: impl IntoIterator<Item = (usize, u64, u64, bool, bool)>,
) -> Self { ) -> Self {
self.with_signing_root_attestations( self.with_signing_root_attestations(attestations.into_iter().map(
attestations |(id, source, target, succeed, succeed_complete)| {
.into_iter() (id, source, target, 0, succeed, succeed_complete)
.map(|(id, source, target, succeed)| (id, source, target, 0, succeed)), },
) ))
} }
pub fn with_signing_root_attestations( pub fn with_signing_root_attestations(
mut self, mut self,
attestations: impl IntoIterator<Item = (usize, u64, u64, u64, bool)>, attestations: impl IntoIterator<Item = (usize, u64, u64, u64, bool, bool)>,
) -> Self { ) -> Self {
self.attestations.extend(attestations.into_iter().map( self.attestations.extend(attestations.into_iter().map(
|(pk, source, target, signing_root, should_succeed)| TestAttestation { |(pk, source, target, signing_root, should_succeed, should_succeed_complete)| {
pubkey: pubkey(pk), assert!(
source_epoch: Epoch::new(source), !should_succeed || should_succeed_complete,
target_epoch: Epoch::new(target), "if should_succeed is true then should_succeed_complete must also be true"
signing_root: Hash256::from_low_u64_be(signing_root), );
should_succeed, TestAttestation {
pubkey: pubkey(pk),
source_epoch: Epoch::new(source),
target_epoch: Epoch::new(target),
signing_root: Hash256::from_low_u64_be(signing_root),
should_succeed,
should_succeed_complete,
}
}, },
)); ));
self self