proposal.rs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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::async_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_n_epoch_start(1);
  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_n_epoch_start(1);
  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!("consensus: 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 modifies its participating slot to next.
  34. match state.write().await.set_participating() {
  35. Ok(()) => info!("consensus: Node will start participating in the next slot"),
  36. Err(e) => error!("consensus: Failed to set participation slot: {}", e),
  37. }
  38. loop {
  39. let seconds_next_slot = state.read().await.next_n_slot_start(1).as_secs();
  40. info!("consensus: Waiting for next slot ({} sec)", seconds_next_slot);
  41. sleep(seconds_next_slot).await;
  42. // Node checks if epoch has changed, to broadcast a new participation message
  43. match state.write().await.epoch_changed().await {
  44. Ok(changed) => {
  45. if changed {
  46. let lock = state.read().await;
  47. info!("consensus: New epoch started: {}", lock.current_epoch());
  48. let public = lock.public;
  49. let address = lock.address;
  50. let mut coins = vec![];
  51. for slot_coins in &lock.consensus.coins {
  52. let mut slot_coins_inputs = vec![];
  53. for slot_coin in slot_coins {
  54. slot_coins_inputs.push(slot_coin.public_inputs());
  55. }
  56. coins.push(slot_coins_inputs);
  57. }
  58. let participant = Participant::new(public, address, coins);
  59. state.write().await.append_participant(participant.clone());
  60. match consensus_p2p.broadcast(participant).await {
  61. Ok(()) => {
  62. info!("consensus: Participation message broadcasted successfully.")
  63. }
  64. Err(e) => {
  65. error!("consensus: Failed broadcasting consensus participation: {}", e)
  66. }
  67. }
  68. // Node sleeps 2 seconds so all nodes can have the new epoch participants
  69. //TODO: optimize this
  70. sleep(2).await;
  71. }
  72. }
  73. Err(e) => {
  74. error!("consensus: Epoch check failed: {}", e);
  75. continue
  76. }
  77. };
  78. // Node checks if it's the slot leader to generate a new proposal
  79. // for that slot.
  80. let lock = state.read().await;
  81. let (won, idx) = lock.is_slot_leader();
  82. let result = if won { lock.propose(idx) } else { Ok(None) };
  83. let proposal = match result {
  84. Ok(prop) => {
  85. if prop.is_none() {
  86. info!("consensus: Node is not the slot lead");
  87. continue
  88. }
  89. prop.unwrap()
  90. }
  91. Err(e) => {
  92. error!("consensus: Block proposal failed: {}", e);
  93. continue
  94. }
  95. };
  96. info!("consensus: Node is the slot leader: Proposed block: {}", proposal);
  97. debug!("consensus: Full proposal: {:?}", proposal);
  98. match state.write().await.receive_proposal(&proposal).await {
  99. Ok(to_broadcast) => {
  100. info!("consensus: Block proposal saved successfully");
  101. // Broadcast block to other consensus nodes
  102. match consensus_p2p.broadcast(proposal).await {
  103. Ok(()) => info!("consensus: Proposal broadcasted successfully"),
  104. Err(e) => error!("consensus: Failed broadcasting proposal: {}", e),
  105. }
  106. // Broadcast finalized blocks info, if any:
  107. if let Some(blocks) = to_broadcast {
  108. info!("consensus: Broadcasting finalized blocks");
  109. for info in blocks {
  110. match sync_p2p.broadcast(info).await {
  111. Ok(()) => info!("consensus: Broadcasted block"),
  112. Err(e) => error!("consensus: Failed broadcasting block: {}", e),
  113. }
  114. }
  115. } else {
  116. info!("consensus: No finalized blocks to broadcast");
  117. }
  118. }
  119. Err(e) => {
  120. error!("consensus: Block proposal save failed: {}", e);
  121. }
  122. }
  123. }
  124. }