Skip to content

Latest commit

 

History

History
94 lines (73 loc) · 3.41 KB

File metadata and controls

94 lines (73 loc) · 3.41 KB

Engineering conventions

Conventions

When writing code, follow these conventions

  • Do NOT add comments explaining what is each line/expression doing.
  • Try to keep the code uniform, and follow the style of the existing code.
  • Always use standalone Rust modules, avoid inline mods
  • Don't change anything without a good reason.
  • Always prefer "lower than" or "lower than or equal" operators over "greater than" and "greater than or equal" ones.

Module Development

Self-Version Table Requirement

Every BFTE module MUST implement a self_version table for database versioning and migration support:

  1. Create a tables.rs file with a self_version table definition:

    use bfte_consensus_core::ver::ConsensusVersion;
    use bfte_util_db::def_table;
    
    def_table! {
        /// Own current consensus version
        ///
        /// This is used to detect version change, for the purpose
        /// of database migration.
        self_version: () => ConsensusVersion
    }
  2. Implement init_db_tx method in your module struct:

    impl YourModule {
        pub(crate) fn init_db_tx(
            dbtx: &ModuleWriteTransactionCtx,
            new_version: ConsensusVersion,
        ) -> DbResult<()> {
            {
                let mut tbl = dbtx.open_table(&tables::self_version::TABLE)?;
                
                if let Some(prev_version) = tbl.get(&())?.map(|v| v.value()) {
                    if prev_version != new_version {
                        info!(target: LOG_TARGET, %prev_version, %new_version, "Version upgrade");
                        // Database migrations go here
                    }
                }
                tbl.insert(&(), &new_version)?;
            }
            Ok(())
        }
    }
  3. Call init_db_tx in your IModuleInit::init implementation:

    async fn init(&self, args: ModuleInitArgs) -> ModuleInitResult<Arc<dyn IModule + Send + Sync + 'static>> {
        // Version validation...
        
        args.db
            .write_with_expect(|dbtx| YourModule::init_db_tx(dbtx, args.module_consensus_version))
            .await;
            
        // Module creation...
    }

This pattern ensures consistent version tracking and provides a framework for future database migrations when module versions change.

Documentation

  • Every Rust crate must have a README.md file at its root directory containing:
    • A summary of what the crate does
    • High-level explanation of how it works
    • Key concepts and architecture
  • Include README.md as Rust documentation by adding #![doc = include_str!("../README.md")] at the top of lib.rs
  • Update README.md when making significant changes to maintain accuracy
  • Keep documentation concise but informative for both users and developers
  • Every type should have at least a short explanation of its purpose.

Project structure

Most notable directories:

  • crates/ - all the project Rust modules (crates)
    • crates/consensus - Simplex algorithm implementation, deterministic and side-effect-free
    • crates/node - implementation of BFTE node, driving communication with other peers and consensus changes
    • crates/node-ui-axum - web UI for the node administrator
    • crates/util-* - small utility crates with functionality described in the name
    • crates/db - wrapper around redb-bincode/redb database
    • crates/derive-secret - deterministic, hierarchical secret derivation