diff --git a/crates/contracts/hyllar/src/lib.rs b/crates/contracts/hyllar/src/lib.rs index b9b23a74e..6099e7d12 100644 --- a/crates/contracts/hyllar/src/lib.rs +++ b/crates/contracts/hyllar/src/lib.rs @@ -126,9 +126,10 @@ impl ERC20 for Hyllar { return Err("Insufficient balance".to_string()); } - *self.balances.entry(sender.to_string()).or_insert(0) -= amount; - *self.balances.entry(recipient.to_string()).or_insert(0) += amount; - + let sender_entry = self.balances.entry(sender.to_string()).or_insert(0); + *sender_entry = sender_entry.checked_sub(amount).ok_or("Insufficient balance")?; + let recipient_entry = self.balances.entry(recipient.to_string()).or_insert(0); + *recipient_entry = recipient_entry.checked_add(amount).ok_or("Balance overflow")?; Ok(()) } @@ -151,11 +152,12 @@ impl ERC20 for Hyllar { return Err("Insufficient balance".to_string()); } - *self.balances.entry(owner.to_string()).or_insert(0) -= amount; - *self.balances.entry(recipient.to_string()).or_insert(0) += amount; - + let owner_entry = self.balances.entry(owner.to_string()).or_insert(0); + *owner_entry = owner_entry.checked_sub(amount).ok_or("Insufficient balance")?; + let recipient_entry_tf = self.balances.entry(recipient.to_string()).or_insert(0); + *recipient_entry_tf = recipient_entry_tf.checked_add(amount).ok_or("Balance overflow")?; // Decrease the allowance - let new_allowance = allowance - amount; + let new_allowance = allowance.checked_sub(amount).ok_or("Allowance underflow")?; self.allowances .insert((owner.to_string(), spender.to_string()), new_allowance); diff --git a/src/consensus/role_follower.rs b/src/consensus/role_follower.rs index 4f0097998..85e9cbc63 100644 --- a/src/consensus/role_follower.rs +++ b/src/consensus/role_follower.rs @@ -209,25 +209,40 @@ impl Consensus { follower_state!(self).buffered_prepares.push(( sender.clone(), - consensus_proposal, - ticket, + consensus_proposal.clone(), + ticket.clone(), view, )); self.record_prepare_cache_sizes(); - // If we already have the next Prepare, fast-forward - if let Some(prepare) = follower_state!(self) - .buffered_prepares - .next_prepare(cp_hash.clone()) - { + // Fast-forward through chained prepares iteratively instead of recursively. + // The recursive approach could cause a stack overflow with many chained prepares. + let mut sender = sender; + let mut consensus_proposal = consensus_proposal; + let mut ticket = ticket; + let mut view = view; + loop { + let Some(prepare) = follower_state!(self) + .buffered_prepares + .next_prepare(cp_hash.clone()) + else { + break; + }; debug!( "🏎️ Fast forwarding to next Prepare with prepare {:?}", prepare ); - // FIXME? In theory, we could have a stackoverflow if we need to catchup a lot of prepares - // Note: If we want to vote on the passed proposal even if it's too late, - // we can just remove the "return" here and continue. - return self.on_prepare(prepare.0, prepare.1, prepare.2, prepare.3); + (sender, consensus_proposal, ticket, view) = prepare; + self.bft_round_state.current_proposal = Some(consensus_proposal.clone()); + cp_hash = consensus_proposal.hashed(); + follower_state!(self).buffered_prepares.push(( + sender.clone(), + consensus_proposal.clone(), + ticket.clone(), + view, + )); + self.record_prepare_cache_sizes(); + } } if self.is_in_timeout_phase() {