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

Allow producer to produce predefined blocks #2081

Merged
merged 27 commits into from
Aug 16, 2024

Conversation

MitchTurner
Copy link
Member

@MitchTurner MitchTurner commented Aug 14, 2024

Linked Issues/PRs

Part of #1902

Description

Provide mechanism for taking predefined blocks and including them in block production.

Does not provide the mechanism for introducing those predefined blocks into the running system, e.g. parsing from file or something. That will come after.

Checklist

  • Breaking changes are clearly marked as such in the PR description and changelog
  • New behavior is reflected in tests
  • The specification matches the implemented behavior (link update PR if changes are needed)

Before requesting review

  • I have reviewed the code myself
  • I have created follow-up issues caused by this PR and linked them here

After merging, notify other teams

[Add or remove entries as needed]

@MitchTurner MitchTurner marked this pull request as ready for review August 16, 2024 10:54
@MitchTurner MitchTurner requested a review from a team August 16, 2024 10:54
@MitchTurner MitchTurner self-assigned this Aug 16, 2024
@xgreenx xgreenx mentioned this pull request Aug 16, 2024
2 tasks
}
should_continue = true;
} else {
tracing::error!("The PoA task should be the holder of the `Sender`");
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand this message here. If I read this correctly, this branch is taken iff the PoA task drops the channel, which happens only if it panics. Maybe "The PoA task panicked!" or something like that would be appropriate? Maybe this function should panic as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

This comment was here before. I agree it's not clear.

@Dentosal
Copy link
Member

The whole mechanism should be documented somehow, somewhere. Probably in doc comments in some relevant trait or function.

@@ -28,10 +28,10 @@ async fn loads_snapshot() {
// setup config
let starting_state = StateConfig {
last_block: Some(LastBlockConfig {
block_height: (u32::MAX - 1).into(),
block_height: (u32::MAX - 2).into(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we need to change this file?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because the code internally calls next_block now. If it's u32::Max (as it becomes) then next_block will panic.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Then test shouldn't produce any blocks, maybe we need to disable block producer

Copy link
Member Author

Choose a reason for hiding this comment

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

Adding Trigger::Never doesn't seem to fix the issue; the producer is still being run.

// Update last block time
self.last_height = *sealed_block.entity.header().height();
self.last_timestamp = sealed_block.entity.header().time();
self.last_block_created = last_block_created;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Because you don't set the timer here, I think after applying predefined blocks the server will halt in the case of Interval trigger more

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe we could somehow reuse main part of the produce_block function

Copy link
Collaborator

Choose a reason for hiding this comment

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

It will be removed during #1917


for (tx_id, err) in skipped_transactions {
let maybe_tx = txs.iter().find(|tx| tx.id(chain_id) == tx_id);
if let Some(tx) = maybe_tx {
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should always be able to find the transaction. Maybe it is better to return an error

let txs = predefined_block.transactions();

for (tx_id, err) in skipped_transactions {
let maybe_tx = txs.iter().find(|tx| tx.id(chain_id) == tx_id);
Copy link
Collaborator

Choose a reason for hiding this comment

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

It is very performance-heavy. It is better to iterate over all transactions in the block and check that it is in the hash map of failed transactions.

let maybe_tx = txs.iter().find(|tx| tx.id(chain_id) == tx_id);
if let Some(tx) = maybe_tx {
tracing::error!(
"During block production got invalid transaction {:?} with error {:?}",
Copy link
Collaborator

Choose a reason for hiding this comment

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

We agreed that in the case of discarded predefined transactions we want to print them in JSON format with some BEGIN {JSON_TX} END marker.

let maybe_block = self.predefined_blocks.get_block(&next_height);
if let Some(block) = maybe_block {
self.produce_predefined_block(&block, &chain_id).await?;
should_continue = true;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we please make an early return here? To avoid shifting a big part of the code into the if statement?

We can move the code below into the else { in a separate PR

Comment on lines +500 to +502
(2u32.into(), block_for_height(2)),
(3u32.into(), block_for_height(3)),
(4u32.into(), block_for_height(4)),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we also test the case when we produce some blocks first form the interval, then we have predefined blocks, please?

let actual = block_receiver.recv().await.unwrap();
assert_eq!(expected, actual);
}
let maybe_produced_block = block_receiver.recv().await.unwrap();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could this test also verify the production of the block after pre-defined blocks, please? Like 3 predefined blocks, and 1-3 non predefined(from interval)

@MitchTurner MitchTurner enabled auto-merge (squash) August 16, 2024 16:38
@MitchTurner MitchTurner merged commit 9de2c08 into master Aug 16, 2024
27 of 28 checks passed
@MitchTurner MitchTurner deleted the feature/produce-predefined-blocks branch August 16, 2024 17:19
xgreenx added a commit that referenced this pull request Aug 18, 2024
Follow-up PR for #2081.

Closes #1902

Add a CLI argument to process predefined blocks.

## Checklist
- [x] New behavior is reflected in tests

### Before requesting review
- [x] I have reviewed the code myself

---------

Co-authored-by: Mitch Turner <james.mitchell.turner@gmail.com>
@xgreenx xgreenx mentioned this pull request Aug 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants