Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: gather v0 block signatures from stackerdb #4807

Merged
merged 11 commits into from
May 31, 2024

Conversation

hstove
Copy link
Contributor

@hstove hstove commented May 21, 2024

This PR updates the miner's SignCoordinator to gather signer signatures using the new header format.

@hstove hstove requested review from kantai and jferrant May 21, 2024 00:02
@hstove
Copy link
Contributor Author

hstove commented May 21, 2024

Opening for draft reviews - there is one integration test implemented that demonstrates the full flow of proposing a Nakamoto block, gathering block responses from signers, and then broadcasting that block.

@jferrant
Copy link
Collaborator

jferrant commented May 23, 2024

We do have a ticket in place to port some existing signer tests over that might be relevant but in terms of testing the miner signature aggregation, this seems like a good test and I wouldn't block this PR based on these other tests.

I do think we should add some unit tests to the logic for accumulating signatures. It might be a bit difficult as you may need to forcibly write stackerdb events, but we should simulate bad signaurtes being written and check that threshold calculations are as expected. You could maybe even add it as an integration test if you see how I force a block proposal manually in my one v0 signer test. Instead of forcing a block proposal and having signers respond, do not spin up any signers (or shut them all down inside the test) and manually act as a signer, broadcasting bad signatures/not enough signatures, etc. to stackerdb.

@hstove
Copy link
Contributor Author

hstove commented May 23, 2024

@jferrant yeah good call, I'll add more logic and tests around verifying and gathering signatures

@hstove hstove marked this pull request as ready for review May 30, 2024 18:26
@hstove hstove requested review from a team as code owners May 30, 2024 18:26
@hstove hstove requested a review from jcnelson May 30, 2024 18:26
@hstove
Copy link
Contributor Author

hstove commented May 30, 2024

@jcnelson @kantai @jferrant I've opened this as "ready for review" after adding additional logic and checks for the data the miner gets from StackerDB. I've really struggled with integration testing for these scenarios. For example, when using SignerTest, when stopping a signer it stops the event observer, which hangs the whole process.

Comment on lines 258 to 265
reward_set_signers
.iter()
.cloned()
.map(|s| s.weight)
.fold(0, |w, acc| {
acc.checked_add(w)
.expect("FATAL: Total signer weight > u32::MAX")
});
Copy link
Member

@kantai kantai May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be nice to implement as an instance method in RewardSet, i.e.:

pub fn total_signing_weight(&self) -> Result<u32, ChainstateError> {
       let Some(ref reward_set_signers) = self.signers else {
            error!("Could not initialize WSTS coordinator for reward set without signer");
            return Err(ChainstateError::NoRegisteredSigners(0));
       };
       Ok(reward_set_signers
                .iter()
                .fold(0, |s, acc| {
                    acc.checked_add(s.weight)
                        .expect("FATAL: Total signer weight > u32::MAX")
                }))
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏼 , added and am now using it in SignCoordinator::new and verify_signer_signature

.checked_add(signer_entry.weight)
.expect("FATAL: total weight signed exceeds u32::MAX");
}
debug!("SignCoordinator: Total weight signed: {total_weight_signed}");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be helpful with a bit more info:

debug!("Added another signature to block";
             "block_signer_sighash" => %block_sighash,
             "signer_pubkey" => %signer_pubkey,
             "signer_slot_id" => slot_id,
             "signature" => %signature,
             "signer_weight" => signer_entry.weight 
             "total_weight_signed" => total_weight_signed,
             );

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call - I've added this, but I removed signer_weight as it otherwise goes over the "max recursion" limit.

Copy link
Member

@kantai kantai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM, just a few comments

@hstove hstove requested a review from kantai May 30, 2024 23:37
@kantai
Copy link
Member

kantai commented May 30, 2024 via email

@hstove
Copy link
Contributor Author

hstove commented May 30, 2024

Ah, yeah added 😀

Copy link
Member

@kantai kantai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

})
.collect::<Result<HashMap<_, _>, ChainstateError>>()?;

let coordinator: FireCoordinator<Aggregator> = FireCoordinator::new(coord_config);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be moved into the #[cfg(test)] block? Also, can the imports for wsts be moved there as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both the cfg(test) block and the "non test" block return a SignCoordinator, which has a coordinator field. So, we'd have to return some other type if we wanted to only include the wsts stuff in the cfg(test) block. Ultimately, this whole file relies on both the v0 and v1 stuff (ie begin_sign_v0 and begin_sign_v1) - there's no easy fix other than separate files / structs IMO

assert!(all_signed);

// Test prometheus metrics response
#[cfg(feature = "monitoring_prom")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It this getting tested in CI?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is running in the integration-tests workflow, and I believe those tests do include the monitoring_prom flag enabled.

Copy link
Member

@jcnelson jcnelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; just a couple of minor comments

@hstove
Copy link
Contributor Author

hstove commented May 31, 2024

I'm going to merge this - @jcnelson if you want us to address your comment regarding the cfg(test) section, feel free to bring it back up in #4781

@hstove hstove merged commit ba9df14 into feat/header-signer-signatures May 31, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants