proposal.rs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. use std::time::Duration;
  2. use log::{debug, error, info};
  3. use super::consensus_sync_task;
  4. use crate::{
  5. consensus::{Participant, ValidatorStatePtr},
  6. net::P2pPtr,
  7. util::sleep,
  8. };
  9. /// async task used for participating in the consensus protocol
  10. pub async fn proposal_task(consensus_p2p: P2pPtr, sync_p2p: P2pPtr, state: ValidatorStatePtr) {
  11. // Node waits just before the current or next epoch end, so it can
  12. // 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!("consensus: 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!("consensus: 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. if let Err(e) = consensus_sync_task(consensus_p2p.clone(), state.clone()).await {
  28. error!("Failed syncing consensus state: {}. Quitting consensus.", e);
  29. // TODO: Perhaps notify over a channel in order to
  30. // stop consensus p2p protocols.
  31. return
  32. };
  33. // Node signals the network that it will start participating
  34. let address = state.read().await.address;
  35. let cur_epoch = state.read().await.current_epoch();
  36. let participant = Participant::new(address, cur_epoch);
  37. state.write().await.append_participant(participant.clone());
  38. match consensus_p2p.broadcast(participant).await {
  39. Ok(()) => info!("consensus: Participation message broadcasted successfully."),
  40. Err(e) => error!("Failed broadcasting consensus participation: {}", e),
  41. }
  42. // Node modifies its participating epoch to next.
  43. match state.write().await.set_participating() {
  44. Ok(()) => info!("consensus: Node will start participating in the next epoch"),
  45. Err(e) => error!("Failed to set participation epoch: {}", e),
  46. }
  47. loop {
  48. let seconds_next_epoch = state.read().await.next_epoch_start().as_secs();
  49. info!("consensus: Waiting for next epoch ({} sec)", seconds_next_epoch);
  50. sleep(seconds_next_epoch).await;
  51. // Node refreshes participants records
  52. match state.write().await.refresh_participants() {
  53. Ok(()) => debug!("Participants refreshed successfully."),
  54. Err(e) => error!("Failed refreshing consensus participants: {}", e),
  55. }
  56. // Node checks if it's the epoch leader to generate a new proposal
  57. // for that epoch.
  58. let result = if state.write().await.is_epoch_leader() {
  59. state.read().await.propose()
  60. } else {
  61. Ok(None)
  62. };
  63. let proposal = match result {
  64. Ok(prop) => {
  65. if prop.is_none() {
  66. info!("consensus: Node is not the epoch lead");
  67. continue
  68. }
  69. prop.unwrap()
  70. }
  71. Err(e) => {
  72. error!("consensus: Block proposal failed: {}", e);
  73. continue
  74. }
  75. };
  76. info!("consensus: Node is the epoch leader: Proposed block: {:?}", proposal);
  77. let vote = state.write().await.receive_proposal(&proposal);
  78. let vote = match vote {
  79. Ok(v) => {
  80. if v.is_none() {
  81. debug!("proposal_task(): Node did not vote for the proposed block");
  82. continue
  83. }
  84. v.unwrap()
  85. }
  86. Err(e) => {
  87. error!("consensus: Failed processing proposal: {}", e);
  88. continue
  89. }
  90. };
  91. let result = state.write().await.receive_vote(&vote).await;
  92. match result {
  93. Ok((_, to_broadcast)) => {
  94. info!("consensus: Vote saved successfully");
  95. // Broadcast finalized blocks info, if any:
  96. if let Some(blocks) = to_broadcast {
  97. info!("consensus: Broadcasting finalized blocks");
  98. for info in blocks {
  99. match sync_p2p.broadcast(info).await {
  100. Ok(()) => info!("consensus: Broadcasted block"),
  101. Err(e) => error!("consensus: Failed broadcasting block: {}", e),
  102. }
  103. }
  104. } else {
  105. info!("consensus: No finalized blocks to broadcast");
  106. }
  107. }
  108. Err(e) => {
  109. error!("consensus: Vote save failed: {}", e);
  110. // TODO: Is this fallthrough ok?
  111. }
  112. }
  113. // Broadcast block to other consensus nodes
  114. match consensus_p2p.broadcast(proposal).await {
  115. Ok(()) => info!("consensus: Proposal broadcasted successfully"),
  116. Err(e) => error!("consensus: Failed broadcasting proposal: {}", e),
  117. }
  118. // Broadcast leader vote
  119. match consensus_p2p.broadcast(vote).await {
  120. Ok(()) => info!("consensus: Leader vote broadcasted successfully"),
  121. Err(e) => error!("consensus: Failed broadcasting leader vote: {}", e),
  122. }
  123. }
  124. }