bft.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the deltavm library. 3 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at: 7 8 // http://www.apache.org/licenses/LICENSE-2.0 9 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 #![allow(clippy::type_complexity)] 17 18 use deltavm_ledger_block::{Ratify, Transaction}; 19 use deltavm_ledger_narwhal::{Transmission, TransmissionID}; 20 use deltavm_ledger_puzzle::Solution; 21 use console::network::Network; 22 23 use anyhow::{Result, bail, ensure}; 24 use std::collections::HashSet; 25 26 /// Takes in an iterator of transmissions and returns a tuple of ratifications, solutions, and transactions. 27 /// 28 /// This method ensures each transmission ID corresponds to its given transmission. 29 /// This method guarantees that the output is 1) order-preserving, and 2) unique. 30 pub fn decouple_transmissions<N: Network>( 31 transmissions: impl Iterator<Item = (TransmissionID<N>, Transmission<N>)>, 32 ) -> Result<(Vec<Ratify<N>>, Vec<Solution<N>>, Vec<Transaction<N>>)> { 33 // Initialize a list for the ratifications. 34 let ratifications = Vec::new(); 35 // Initialize a list for the solutions. 36 let mut solutions = Vec::new(); 37 // Initialize a list for the transactions. 38 let mut transactions = Vec::new(); 39 40 // Initialize a set to ensure the transmissions are unique. 41 let mut unique = HashSet::new(); 42 43 // Iterate over the transmissions. 44 for (transmission_id, transmission) in transmissions { 45 // Ensure the transmission ID is unique. 46 ensure!(unique.insert(transmission_id), "Found a duplicate transmission ID - {transmission_id}"); 47 // Deserialize and store the transmission. 48 match (transmission_id, transmission) { 49 (TransmissionID::Ratification, Transmission::Ratification) => (), 50 (TransmissionID::Solution(commitment, checksum), Transmission::Solution(solution)) => { 51 // Ensure the transmission checksum corresponds to the solution. 52 ensure!(checksum == solution.to_checksum::<N>()?, "Mismatching transmission checksum (solution)"); 53 // Deserialize the solution. 54 let solution = solution.deserialize_blocking()?; 55 // Ensure the transmission ID corresponds to the solution. 56 ensure!(commitment == solution.id(), "Mismatching transmission ID (solution)"); 57 // Insert the solution into the list. 58 solutions.push(solution); 59 } 60 (TransmissionID::Transaction(transaction_id, checksum), Transmission::Transaction(transaction)) => { 61 // Ensure the transmission checksum corresponds to the transaction. 62 ensure!(checksum == transaction.to_checksum::<N>()?, "Mismatching transmission checksum (transaction)"); 63 // Deserialize the transaction. 64 let transaction = transaction.deserialize_blocking()?; 65 // Ensure the transmission ID corresponds to the transaction. 66 ensure!(transaction_id == transaction.id(), "Mismatching transmission ID (transaction)"); 67 // Insert the transaction into the list. 68 transactions.push(transaction); 69 } 70 _ => bail!("Mismatching (transmission ID, transmission) entry"), 71 } 72 } 73 // Return the ratifications, solutions, and transactions. 74 Ok((ratifications, solutions, transactions)) 75 }