proposal.rs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. use std::time::Duration;
  2. use log::{debug, error, info};
  3. use super::consensus_sync_task;
  4. use crate::{
  5. consensus2::{state::ValidatorStatePtr, Participant},
  6. net,
  7. util::async_util::sleep,
  8. };
  9. /// async task used for participating in the consensus protocol
  10. pub async fn proposal_task(p2p: net::P2pPtr, state: ValidatorStatePtr) {
  11. // Node waits just before the current or next epoch end,
  12. // so it can start syncing latest state.
  13. let mut seconds_until_next_epoch = state.read().await.next_epoch_start();
  14. let one_sec = Duration::new(1, 0);
  15. loop {
  16. if seconds_until_next_epoch > one_sec {
  17. seconds_until_next_epoch -= one_sec;
  18. break
  19. }
  20. info!("Waiting for next epoch ({:?} sec)...", seconds_until_next_epoch);
  21. sleep(seconds_until_next_epoch.as_secs()).await;
  22. seconds_until_next_epoch = state.read().await.next_epoch_start();
  23. }
  24. info!("Waiting for next epoch ({:?} sec)...", seconds_until_next_epoch);
  25. sleep(seconds_until_next_epoch.as_secs()).await;
  26. // Node syncs its consensus state
  27. match consensus_sync_task(p2p.clone(), state.clone()).await {
  28. Ok(()) => {}
  29. Err(e) => {
  30. error!("Failed syncing consensus state: {}. Quitting consensus.", e);
  31. return
  32. }
  33. }
  34. // Node signals the network that it will start participating
  35. let participant = Participant::new(state.read().await.id, state.read().await.current_epoch());
  36. state.write().await.append_self_participant(participant.clone());
  37. match p2p.broadcast(participant).await {
  38. Ok(()) => info!("Consensus participation message broadcasted successfully."),
  39. Err(e) => error!("Failed broadcasting consensus participation: {}", e),
  40. }
  41. // After initialization node waits for next epoch to start participating
  42. let seconds_until_next_epoch = state.read().await.next_epoch_start().as_secs();
  43. info!(target: "consensus", "Waiting for next epoch ({:?} sec)...", seconds_until_next_epoch);
  44. sleep(seconds_until_next_epoch).await;
  45. // Note modifies its participating flag to true.
  46. state.write().await.participating = true;
  47. loop {
  48. // Node refreshes participants records
  49. match state.write().await.refresh_participants() {
  50. Ok(()) => debug!("Participants refreshed successfully."),
  51. Err(e) => error!("Failed refreshing participants: {}", e),
  52. }
  53. // Node checks if it's the epoch leader to generate a new proposal
  54. // for that epoch.
  55. let result = if state.write().await.is_epoch_leader() {
  56. state.read().await.propose()
  57. } else {
  58. Ok(None)
  59. };
  60. match result {
  61. Ok(proposal) => {
  62. if proposal.is_none() {
  63. info!(target: "consensus", "Node is not the epoch leader. Sleeping till next epoch...");
  64. } else {
  65. // Leader creates a vote for the proposal and broadcasts them both
  66. let proposal = proposal.unwrap();
  67. info!(target: "consensus", "Node is the epoch leader: Proposed block: {:?}", proposal);
  68. let vote = state.write().await.receive_proposal(&proposal);
  69. match vote {
  70. Ok(v) => {
  71. if v.is_none() {
  72. debug!("proposal_task(): Node did not vote for the proposed block");
  73. } else {
  74. let vote = v.unwrap();
  75. let result = state.write().await.receive_vote(&vote);
  76. match result {
  77. Ok(_) => info!(target: "consensus", "Vote saved successfully."),
  78. Err(e) => {
  79. error!(target: "consensus", "Vote save failed: {}", e)
  80. }
  81. }
  82. // Broadcast block
  83. let result = p2p.broadcast(proposal).await;
  84. match result {
  85. Ok(()) => {
  86. info!(target: "consensus", "Proposal broadcasted successfully.")
  87. }
  88. Err(e) => {
  89. error!(target: "consensus", "Failed broadcasting proposal: {}", e)
  90. }
  91. }
  92. // Broadcast leader vote
  93. let result = p2p.broadcast(vote).await;
  94. match result {
  95. Ok(()) => {
  96. info!(target: "consensus", "Leader vote broadcasted successfully.")
  97. }
  98. Err(e) => {
  99. error!(target: "consensus", "Failed broadcasting leader vote: {}", e)
  100. }
  101. }
  102. }
  103. }
  104. Err(e) => error!(target: "consensus", "Failed processing proposal: {}", e),
  105. }
  106. }
  107. }
  108. Err(e) => error!("Block proposal failed: {}", e),
  109. }
  110. let seconds_until_next_epoch = state.read().await.next_epoch_start().as_secs();
  111. info!(target: "consensus", "Waiting for next epoch ({:?} sec)...", seconds_until_next_epoch);
  112. sleep(seconds_until_next_epoch).await;
  113. }
  114. }