From 4127f54032264c9e2acbf8f0ad75ad29651f2589 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Wed, 24 Jan 2024 18:57:16 -0500 Subject: [PATCH 01/47] add some specs to event processing --- src/builder_state.rs | 66 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 77aa25be..4d29d22a 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -1,6 +1,7 @@ #![allow(unused_imports)] use std::collections::{BTreeMap, HashMap, HashSet}; use std::hash::BuildHasher; +use std::marker::PhantomData; use std::sync::{Arc, Mutex}; use bincode::de; use futures::stream::select_all; @@ -9,9 +10,11 @@ use async_std::task::{self, Builder}; use async_trait::async_trait; //use async_compatibility_layer::channel::{unbounded, UnboundedSender, UnboundedStream, UnboundedReceiver}; use async_lock::RwLock; - +use hotshot_types::traits::block_contents::vid_commitment; +use sha2::{Digest, Sha256}; use hotshot::rand::seq::index; +use hotshot_testing::block_types::TestBlockPayload; //use hotshot_task::event_stream::{ChannelStream, EventStream, StreamId}; use tokio_stream::StreamExt; @@ -122,6 +125,12 @@ pub struct BuilderState { /// block hash to the full block pub block_hash_to_block: HashMap, + /// da_proposal_payload_commit to da_proposal + pub da_proposal_payload_commit_to_da_proposal: HashMap>, + + /// qc_payload_commit to qc + pub qc_payload_commit_to_qc: HashMap>, + /// processed views pub processed_views: HashMap>, @@ -211,14 +220,65 @@ impl BuilderProgress for BuilderState{ //println!("Processing DA proposal"); //todo!("process_da_proposal"); + let da_proposal_data = da_msg.proposal.data.clone(); + let sender = da_msg.sender; + + // get the view number and encoded txns from the da_proposal_data + let view_number = da_proposal_data.view_number; + let encoded_txns = da_proposal_data.encoded_transactions; + + let metadata: <::BlockPayload as BlockPayload>::Metadata = da_proposal_data.metadata; + + // get the block payload from the encoded_txns + let block_payload_txns = TestBlockPayload::from_bytes(encoded_txns.clone().into_iter(), &()).transactions; + + let encoded_txns_hash = Sha256::digest(&encoded_txns); + + // generate the vid commitment + // TODO: Currently we are hardcoding the number of storage nodes to 2, but later we need to change it + // let payload_vid_commitment = vid_commitment(&encoded_txns, 8); + + // // Verify the signature of the DA proposal + // // insert into the da_proposal_payload_commit_to_da_proposal hashmap if not exists already + // // sender.validate(&da_msg.proposal.signature, &encoded_txns) && + // if !self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment) { + // let da_proposal = DAProposal { + // encoded_transactions: encoded_txns.clone(), + // metadata: metadata.clone(), + // view_number: view_number, + // }; + + // self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal); + + // } + + return; + //self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data.clone()); + } /// processing the quorum proposal async fn process_quorum_proposal(&mut self, qc_msg: QCMessage) { //println!("Processing quorum proposal"); + let qc_proposal_data = qc_msg.proposal.data; + let sender = qc_msg.sender; - //todo!("process_quorum_proposal"); + let payload_vid_commitment = qc_proposal_data.block_header.payload_commitment(); + + // can use this commitment to match the da proposal or vice-versa + + // Verify the signature of the QC proposal + // insert into the qc_payload_commit_to_qc hashmap if not exists already + // if sender.validate(&qc_msg.proposal.signature, &payload_vid_commitment) && !self.qc_payload_commit_to_qc.contains_key(&payload_vid_commitment) { + // let qc_proposal = QCMessage { + // proposal: qc_proposal_data.clone(), + // sender: sender, + // }; + + // self.qc_payload_commit_to_qc.insert(payload_vid_commitment, qc_proposal); + + // } } /// processing the decide event @@ -252,6 +312,8 @@ impl BuilderState{ decide_receiver: decide_receiver, da_proposal_receiver: da_proposal_receiver, qc_receiver: qc_receiver, + da_proposal_payload_commit_to_da_proposal: HashMap::new(), + qc_payload_commit_to_qc: HashMap::new(), } } From 895e21fd7c3a3b2d068e9f8d07bb4dfaed6d970e Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Thu, 25 Jan 2024 14:14:38 -0500 Subject: [PATCH 02/47] add map specific operations --- src/builder_state.rs | 59 ++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 4d29d22a..809f0387 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -1,4 +1,5 @@ #![allow(unused_imports)] +#![allow(unused_variables)] use std::collections::{BTreeMap, HashMap, HashSet}; use std::hash::BuildHasher; use std::marker::PhantomData; @@ -41,6 +42,7 @@ use hotshot_types::{ use commit::{Commitment, Committable}; pub type TxTimeStamp = u128; +const NODES_IN_VID_COMPUTATION: usize = 8; #[derive(Clone, Debug, PartialEq)] pub enum TransactionType { @@ -129,7 +131,7 @@ pub struct BuilderState { pub da_proposal_payload_commit_to_da_proposal: HashMap>, /// qc_payload_commit to qc - pub qc_payload_commit_to_qc: HashMap>, + pub qc_payload_commit_to_qc: HashMap>, /// processed views pub processed_views: HashMap>, @@ -235,26 +237,20 @@ impl BuilderProgress for BuilderState{ let encoded_txns_hash = Sha256::digest(&encoded_txns); // generate the vid commitment - // TODO: Currently we are hardcoding the number of storage nodes to 2, but later we need to change it - // let payload_vid_commitment = vid_commitment(&encoded_txns, 8); - - // // Verify the signature of the DA proposal - // // insert into the da_proposal_payload_commit_to_da_proposal hashmap if not exists already - // // sender.validate(&da_msg.proposal.signature, &encoded_txns) && - // if !self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment) { - // let da_proposal = DAProposal { - // encoded_transactions: encoded_txns.clone(), - // metadata: metadata.clone(), - // view_number: view_number, - // }; - - // self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal); - - // } - - return; - //self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data.clone()); - + // TODO: Currently we are hardcoding the number of storage nodes to 8, but later we need to change it + let payload_vid_commitment = vid_commitment(&encoded_txns, NODES_IN_VID_COMPUTATION); + if !self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment) { + // add the original da proposal to the hashmap + // verify the signature and if valid then insert into the map + if sender.validate(&da_msg.proposal.signature, &encoded_txns_hash) { + let da_proposal = DAProposal { + encoded_transactions: encoded_txns.clone(), + metadata: metadata.clone(), + view_number: view_number, + }; + self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal); + } + } } /// processing the quorum proposal @@ -268,17 +264,15 @@ impl BuilderProgress for BuilderState{ // can use this commitment to match the da proposal or vice-versa - // Verify the signature of the QC proposal - // insert into the qc_payload_commit_to_qc hashmap if not exists already - // if sender.validate(&qc_msg.proposal.signature, &payload_vid_commitment) && !self.qc_payload_commit_to_qc.contains_key(&payload_vid_commitment) { - // let qc_proposal = QCMessage { - // proposal: qc_proposal_data.clone(), - // sender: sender, - // }; - - // self.qc_payload_commit_to_qc.insert(payload_vid_commitment, qc_proposal); - - // } + // first check whether vid_commitment exists in the qc_payload_commit_to_qc hashmap, if yer, ignore it, otherwise validate it and later insert in + if !self.qc_payload_commit_to_qc.contains_key(&payload_vid_commitment){ + // Verify the signature of the QC proposal + // insert into the qc_payload_commit_to_qc hashmap if not exists already + if sender.validate(&qc_msg.proposal.signature, payload_vid_commitment.as_ref()) { + self.qc_payload_commit_to_qc.insert(payload_vid_commitment, qc_proposal_data.clone()); + + } + } } /// processing the decide event @@ -286,6 +280,7 @@ impl BuilderProgress for BuilderState{ { //println!("Processing decide event"); //todo!("process_decide_event"); + } } From 043b8bf19de0076c6d953a1a2f336136139e2694 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Thu, 25 Jan 2024 14:19:13 -0500 Subject: [PATCH 03/47] add comments --- src/builder_state.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 809f0387..a5595399 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -178,17 +178,17 @@ impl BuilderProgress for BuilderState{ { // PRIVATE MEMPOOL TRANSACTION PROCESSING println!("Processing external transaction"); - // check if the transaction already exists in the hashmap + // check if the transaction already exists in either the included set or the local tx pool // if it exits, then we can ignore it and return - // else we can insert it into the both the maps - // get tx_hash_now + // else we can insert it into local tx pool + // get tx_hash as keu let tx_hash = tx.commit(); // If it already exists, then discard it. Decide the existence based on the tx_hash_tx and check in both the local pool and already included txns - if self.tx_hash_to_tx.contains_key(&tx_hash) && self.included_txns.contains(&tx_hash) { + if self.tx_hash_to_tx.contains_key(&tx_hash) || self.included_txns.contains(&tx_hash) { println!("Transaction already exists in the builderinfo.txid_to_tx hashmap, So we can ignore it"); } else { - // get the current timestamp in nanoseconds + // get the current timestamp in nanoseconds; it used for ordering the transactions let tx_timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); // insert into both timestamp_tx and tx_hash_tx maps @@ -239,16 +239,17 @@ impl BuilderProgress for BuilderState{ // generate the vid commitment // TODO: Currently we are hardcoding the number of storage nodes to 8, but later we need to change it let payload_vid_commitment = vid_commitment(&encoded_txns, NODES_IN_VID_COMPUTATION); + if !self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment) { // add the original da proposal to the hashmap // verify the signature and if valid then insert into the map if sender.validate(&da_msg.proposal.signature, &encoded_txns_hash) { - let da_proposal = DAProposal { + let da_proposal_data = DAProposal { encoded_transactions: encoded_txns.clone(), metadata: metadata.clone(), view_number: view_number, }; - self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal); + self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data); } } } @@ -280,7 +281,7 @@ impl BuilderProgress for BuilderState{ { //println!("Processing decide event"); //todo!("process_decide_event"); - + } } From 1e78333a9d52232338c761a6df12981beb8dd2cf Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 26 Jan 2024 10:38:59 -0500 Subject: [PATCH 04/47] add copyright notice and cli files --- .github/dependabot.yml | 12 +++++ .github/workflows/build.yml | 81 +++++++++++++++++++++++++++++ .github/workflows/build_nix.yml | 47 +++++++++++++++++ .github/workflows/build_windows.yml | 57 ++++++++++++++++++++ .github/workflows/combine-prs.yml | 24 +++++++++ .github/workflows/coverage.yml | 58 +++++++++++++++++++++ .github/workflows/debug_build.yml | 45 ++++++++++++++++ .github/workflows/lint.yml | 59 +++++++++++++++++++++ .github/workflows/update_nix.yml | 26 +++++++++ src/api.rs | 4 ++ src/builder_state.rs | 4 ++ src/data_source.rs | 4 ++ src/lib.rs | 4 ++ src/service.rs | 4 ++ src/testing.rs | 4 ++ src/testing/basic_test.rs | 4 ++ 16 files changed, 437 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/build_nix.yml create mode 100644 .github/workflows/build_windows.yml create mode 100644 .github/workflows/combine-prs.yml create mode 100644 .github/workflows/coverage.yml create mode 100644 .github/workflows/debug_build.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/update_nix.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..233172d0 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "daily" + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..9d042f79 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,81 @@ +name: Build + +on: + push: + branches: + - main + - release-* + pull_request: + branches: + - main + - release-* + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + env: + RUSTFLAGS: "--cfg async_executor_impl=\"async-std\" --cfg async_channel_impl=\"async-std\"" + RUST_LOG: info + steps: + - uses: styfle/cancel-workflow-action@0.12.0 + name: Cancel Outdated Builds + with: + all_but_latest: true + access_token: ${{ github.token }} + + - uses: actions/checkout@v4 + name: Checkout Repository + + - name: Install Protoc + uses: arduino/setup-protoc@v2 + + - uses: dtolnay/rust-toolchain@stable + + - name: Configure Git + run: | + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com".insteadOf git://github.com + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com".insteadOf ssh://git@github.com + + - uses: Swatinem/rust-cache@v2 + name: Enable Rust Caching + + - name: Format Check + run: cargo fmt -- --check + + # Run Clippy on all targets. The lint workflow doesn't run Clippy on tests, because the tests + # don't compile with all combinations of features. + - uses: actions-rs/clippy-check@v1 + name: Clippy + with: + token: ${{ github.token }} + args: --workspace --all-features --all-targets -- -D warnings + + - name: Audit + run: cargo audit --ignore RUSTSEC-2023-0018 --ignore RUSTSEC-2023-0052 --ignore RUSTSEC-2023-0065 + + - name: Build + # Build in release without `testing` feature, this should work without `hotshot_example` config. + run: | + cargo build --workspace --release + + - name: Test + # Build test binary with `testing` feature, which requires `hotshot_example` config + run: | + export RUSTFLAGS="$RUSTFLAGS --cfg hotshot_example" + cargo test --workspace --release --all-features --no-run + cargo test --workspace --release --all-features --verbose -- --test-threads 2 + timeout-minutes: 60 + + - name: Generate Documentation + run: | + cargo doc --no-deps --lib --release + echo '' > target/doc/index.html + + - name: Deploy Documentation + uses: peaceiris/actions-gh-pages@v3 + if: ${{ github.ref == 'refs/heads/main' }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./target/doc + cname: tide-disco.docs.espressosys.com diff --git a/.github/workflows/build_nix.yml b/.github/workflows/build_nix.yml new file mode 100644 index 00000000..8dcab5ad --- /dev/null +++ b/.github/workflows/build_nix.yml @@ -0,0 +1,47 @@ +name: Nix + +on: + push: + branches: + - main + - release-* + schedule: + - cron: '0 0 * * 1' + workflow_dispatch: + +jobs: + nix: + runs-on: ubuntu-latest + timeout-minutes: 90 + steps: + - name: Configure Git + run: | + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com/".insteadOf git://github.com/ + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com/".insteadOf ssh://git@github.com/ + + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Install Nix + uses: cachix/install-nix-action@v24 + + # - uses: cachix/cachix-action@v12 + # with: + # name: espresso-systems-private + # authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + + - name: Cache cargo + uses: actions/cache@v3.3.2 + with: + path: | + ~/.cargo-nix/registry/index + ~/.cargo-nix/registry/cache + ~/.cargo-nix/git + target + key: espresso-nix-v2-${{ hashFiles('Cargo.lock') }} + + - name: "Sanity Check: nix environment loads" + run: nix-shell --run "echo Success" + + - name: "Sanity Check: nix environment builds all targets" + run: nix-shell --run "cargo build --all-targets --all-features --release --workspace" diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml new file mode 100644 index 00000000..acd52bc3 --- /dev/null +++ b/.github/workflows/build_windows.yml @@ -0,0 +1,57 @@ +# Copyright (c) 2022 Espresso Systems (espressosys.com) +# This file is part of the Tide Disco library. +# +# This program is free software: you can redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# You should have received a copy of the GNU General Public License along with this program. If not, +# see . + +name: Windows build + +on: + push: + branches: + - main + - release-* + pull_request: + branches: + - main + - release-* + workflow_dispatch: + +jobs: + windows: + runs-on: windows-latest + env: + RUSTFLAGS: "--cfg async_executor_impl=\"async-std\" --cfg async_channel_impl=\"async-std\" --cfg hotshot_example" + RUST_LOG: info + steps: + - name: Configure Git + run: | + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com/".insteadOf git://github.com/ + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com/".insteadOf ssh://git@github.com/ + + - uses: dtolnay/rust-toolchain@stable + + - name: Install Protoc + uses: arduino/setup-protoc@v2 + + - name: Checkout Repository + uses: actions/checkout@v4 + + - uses: Swatinem/rust-cache@v2 + name: Enable Rust Caching + + - name: Build + run: | + cargo build --workspace --release + + - name: Test + run: | + cargo test --workspace --release --all-features --no-run + cargo test --workspace --release --all-features --verbose -- --test-threads 2 + timeout-minutes: 60 diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml new file mode 100644 index 00000000..6693abea --- /dev/null +++ b/.github/workflows/combine-prs.yml @@ -0,0 +1,24 @@ +name: Combine PRs + +on: + schedule: + - cron: "0 1 * * MON" + workflow_dispatch: # allows to manually trigger the workflow + +# The minimum permissions required to run this Action +permissions: + contents: write + pull-requests: write + checks: read + +jobs: + combine-prs: + runs-on: ubuntu-latest + + steps: + - name: combine-prs + id: combine-prs + uses: github/combine-prs@v5.0.0 + with: + github_token: ${{ secrets.ORG_GITHUB_PAT }} + labels: "dependabot,combined-pr" diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 00000000..770257da --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,58 @@ +name: Code Coverage Workflow + +on: + push: + branches: + - main + - release-* + schedule: + - cron: "0 1 * * 1" + workflow_dispatch: + +jobs: + code-coverage: + runs-on: ubuntu-latest + timeout-minutes: 120 + steps: + - name: Configure Git + run: | + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com/".insteadOf git://github.com/ + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com/".insteadOf ssh://git@github.com/ + + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Install Nix + uses: cachix/install-nix-action@v24 + + - name: Enable Cachix + uses: cachix/cachix-action@v13 + # If PR is from a non-collaborator (e.g. dependabot) the secrets are missing and the login to cachix fails. + continue-on-error: true + with: + name: espresso-systems-private + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + extraPullNames: nix-community + skipPush: ${{ github.actor == 'dependabot[bot]' }} + + - name: Cache cargo + uses: actions/cache@v3.3.2 + with: + path: | + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git + target + key: hotshot-query-service-codecov-v1-${{ hashFiles('Cargo.lock') }} + + - name: Generate coverage reports + run: | + git config --global --add safe.directory "$PWD" + nix run "github:NixOS/nix?ref=1849e6a1f64734c488c2b1469249d65ce08cef93" -- develop .#perfShell -c cargo llvm-cov --profile=release --all-features --all-targets --lcov --output-path lcov.info -- --test-threads 1 + + - name: Coveralls upload + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: lcov.info + fail_ci_if_error: true diff --git a/.github/workflows/debug_build.yml b/.github/workflows/debug_build.yml new file mode 100644 index 00000000..2e27082c --- /dev/null +++ b/.github/workflows/debug_build.yml @@ -0,0 +1,45 @@ +name: Debug Build + +on: + schedule: + - cron: "0 0 * * *" + +jobs: + build: + runs-on: ubuntu-latest + env: + RUSTFLAGS: "--cfg async_executor_impl=\"async-std\" --cfg async_channel_impl=\"async-std\"" + RUST_LOG: info + RUST_MIN_STACK: '3145728' + steps: + - name: Install Protoc + uses: arduino/setup-protoc@v2 + + - uses: dtolnay/rust-toolchain@stable + + - uses: styfle/cancel-workflow-action@0.12.0 + name: Cancel Outdated Builds + with: + all_but_latest: true + access_token: ${{ github.token }} + + - uses: actions/checkout@v4 + name: Checkout Repository + + - name: Configure Git + run: | + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com".insteadOf git://github.com + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com".insteadOf ssh://git@github.com + + - uses: Swatinem/rust-cache@v2 + name: Enable Rust Caching + + - name: Build + run: | + cargo build --workspace --all-features + + - name: Test + run: | + cargo test --workspace --all-features --no-run + cargo test --workspace --all-features --verbose -- --test-threads 2 + timeout-minutes: 60 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..27858f78 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,59 @@ +name: Lint + +on: + push: + branches: + - main + - release-* + pull_request: + branches: + - main + - release-* + workflow_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + strategy: + matrix: + # Lint with many combinations of feature flags + features: + # No optional features + - '' + # Each optional feature on its own + - sql-data-source + - file-system-data-source + - metrics-data-source + # All optional features together + - sql-data-source,file-system-data-source,metrics-data-source + env: + RUSTFLAGS: "--cfg async_executor_impl=\"async-std\" --cfg async_channel_impl=\"async-std\"" + RUST_LOG: info + steps: + - uses: styfle/cancel-workflow-action@0.12.0 + name: Cancel Outdated Builds + with: + all_but_latest: true + access_token: ${{ github.token }} + + - uses: actions/checkout@v4 + name: Checkout Repository + + - name: Install Protoc + uses: arduino/setup-protoc@v2 + + - uses: dtolnay/rust-toolchain@stable + + - name: Configure Git + run: | + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com".insteadOf git://github.com + git config --global url."https://ancient123:${{ secrets.ORG_GITHUB_PAT }}@github.com".insteadOf ssh://git@github.com + + - uses: Swatinem/rust-cache@v2 + name: Enable Rust Caching + + - uses: actions-rs/clippy-check@v1 + name: Clippy + with: + token: ${{ github.token }} + args: --workspace --no-default-features --features "${{ matrix.features }}" -- -D warnings diff --git a/.github/workflows/update_nix.yml b/.github/workflows/update_nix.yml new file mode 100644 index 00000000..8affd87b --- /dev/null +++ b/.github/workflows/update_nix.yml @@ -0,0 +1,26 @@ +name: update-flake-lock + +on: + workflow_dispatch: # allows manual triggering + schedule: + - cron: '0 0 * * 0' # runs weekly on Sunday at 00:00 + +jobs: + lockfile: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Nix + uses: cachix/install-nix-action@v24 + + - uses: cachix/cachix-action@v13 + with: + name: espresso-systems-private + authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + + - name: Update flake.lock + uses: DeterminateSystems/update-flake-lock@v20 + with: + pr-title: "Weekly PR to bump flake.nix" # Title of PR to be created diff --git a/src/api.rs b/src/api.rs index aa5ef0f3..fd3181ab 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,3 +1,7 @@ +// Copyright (c) 2024 Espresso Systems (espressosys.com) +// This file is part of the HotShot Builder Protocol. +// + //! Builder Phase 1 //! It mainly provides two API services to external users: //! 1. Serves a proposer(leader)'s request to provide blocks information diff --git a/src/builder_state.rs b/src/builder_state.rs index a5595399..1e000316 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -1,3 +1,7 @@ +// Copyright (c) 2024 Espresso Systems (espressosys.com) +// This file is part of the HotShot Builder Protocol. +// + #![allow(unused_imports)] #![allow(unused_variables)] use std::collections::{BTreeMap, HashMap, HashSet}; diff --git a/src/data_source.rs b/src/data_source.rs index f8a1c222..932721e6 100644 --- a/src/data_source.rs +++ b/src/data_source.rs @@ -1,3 +1,7 @@ +// Copyright (c) 2024 Espresso Systems (espressosys.com) +// This file is part of the HotShot Builder Protocol. +// + //! Builder Phase 1 //! It mainly provides two API services to external users: //! 1. Serves a proposer(leader)'s request to provide blocks information diff --git a/src/lib.rs b/src/lib.rs index 8e8d2114..6c1fa618 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,7 @@ +// Copyright (c) 2024 Espresso Systems (espressosys.com) +// This file is part of the HotShot Builder Protocol. +// + //! Builder Phase 1 //! It mainly provides two API services to external users: //! 1. Serves a proposer(leader)'s request to provide blocks information diff --git a/src/service.rs b/src/service.rs index fcc4a1d7..bd4a2798 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,3 +1,7 @@ +// Copyright (c) 2024 Espresso Systems (espressosys.com) +// This file is part of the HotShot Builder Protocol. +// + //! Builder Phase 1 //! It mainly provides two API services to external users: //! 1. Serves a proposer(leader)'s request to provide blocks information diff --git a/src/testing.rs b/src/testing.rs index 1a08eb65..ae1f9392 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -1,3 +1,7 @@ +// Copyright (c) 2024 Espresso Systems (espressosys.com) +// This file is part of the HotShot Builder Protocol. +// + //! Builder Phase 1 Testing //! //! diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 2a88a427..e9f6f961 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -1,3 +1,7 @@ +// Copyright (c) 2024 Espresso Systems (espressosys.com) +// This file is part of the HotShot Builder Protocol. +// + //! Builder Phase 1 Testing //! From be10e46f6f679e7775dfad6caf3fa13b4c1e3f28 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 26 Jan 2024 15:11:15 -0500 Subject: [PATCH 05/47] try add decide event action --- src/builder_state.rs | 60 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 1e000316..740947d8 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -15,11 +15,12 @@ use async_std::task::{self, Builder}; use async_trait::async_trait; //use async_compatibility_layer::channel::{unbounded, UnboundedSender, UnboundedStream, UnboundedReceiver}; use async_lock::RwLock; +use hotshot_task_impls::transactions; use hotshot_types::traits::block_contents::vid_commitment; use sha2::{Digest, Sha256}; use hotshot::rand::seq::index; -use hotshot_testing::block_types::TestBlockPayload; +use hotshot_testing::block_types::{TestBlockHeader, TestBlockPayload, TestTransaction}; //use hotshot_task::event_stream::{ChannelStream, EventStream, StreamId}; use tokio_stream::StreamExt; @@ -241,7 +242,7 @@ impl BuilderProgress for BuilderState{ let encoded_txns_hash = Sha256::digest(&encoded_txns); // generate the vid commitment - // TODO: Currently we are hardcoding the number of storage nodes to 8, but later we need to change it + // TODO: Currently we are hardcoding the number of storage nodes to 8, but later read it either form sequencer/hotshot repo let payload_vid_commitment = vid_commitment(&encoded_txns, NODES_IN_VID_COMPUTATION); if !self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment) { @@ -255,7 +256,8 @@ impl BuilderProgress for BuilderState{ }; self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data); } - } + } + } /// processing the quorum proposal @@ -283,9 +285,55 @@ impl BuilderProgress for BuilderState{ /// processing the decide event async fn process_decide_event(&mut self, decide_msg: DecideMessage) { - //println!("Processing decide event"); - //todo!("process_decide_event"); - + + let leaf_chain = decide_msg.leaf_chain; + let qc = decide_msg.qc; + let block_size = decide_msg.block_size; + + // get the most recent decide parent commitment as the first entry in the leaf_chain(sorted by descreasing view number) + let decide_parent_commitment = leaf_chain[0].parent_commitment; + // now we use this decide_parent_commitment to build blocks off + + + // do local pruning based on decide event data + // iterate over all the decide leaves and extract out the transactions contained inside it + // for each transaction, check if it exists in the included_txns set, if yes, then ignore it, otherwise add it to the included_txns set + for leaf in leaf_chain.iter() { + // get the block payload + // constrain its type to be of type TestBlockPayload + let block_payload = leaf.get_block_payload(); + match block_payload{ + Some(block_payload) => { + println!("Block payload in decide event {:?}", block_payload); + let transactions = block_payload.transactions; + // iterate over the transactions and remove them from tx_hash_to_tx and timestamp_to_tx, and included tx map + //let transactions:Vec = vec![]; + + for transaction in transactions.iter() { + // get the transaction hash + let tx_hash = transaction.commit(); + // check if the transaction already exists in the included_txns set, if yes, then ignore it, otherwise add it to the included_txns set + if self.included_txns.contains(&tx_hash) { + self.included_txns.remove(&tx_hash); + } + // remove the transaction from the timestamp_to_tx map + if let Some((timestamp, _, _)) = self.tx_hash_to_tx.get(&tx_hash) { + if self.timestamp_to_tx.contains_key(timestamp) { + self.timestamp_to_tx.remove(timestamp); + } + } + // remove the transaction from the tx_hash_to_tx map also + if self.tx_hash_to_tx.contains_key(&tx_hash) { + self.tx_hash_to_tx.remove(&tx_hash); + } + + } + }, + None => { + println!("Block payload is none"); + } + } + } } } From e1f3f2c275a4a58deea56958f9cd912995fe4738 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 26 Jan 2024 15:34:27 -0500 Subject: [PATCH 06/47] issue in metadata --- src/builder_state.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 740947d8..9bc6f8f4 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -305,13 +305,14 @@ impl BuilderProgress for BuilderState{ match block_payload{ Some(block_payload) => { println!("Block payload in decide event {:?}", block_payload); - let transactions = block_payload.transactions; + let metadata: BlockPayload::Metadata = (); + + let transactions_commitments = block_payload.transaction_commitments(&metadata); // iterate over the transactions and remove them from tx_hash_to_tx and timestamp_to_tx, and included tx map //let transactions:Vec = vec![]; - - for transaction in transactions.iter() { + for tx_hash in transactions_commitments.iter() { // get the transaction hash - let tx_hash = transaction.commit(); + //let tx_hash = transaction.commit(); // check if the transaction already exists in the included_txns set, if yes, then ignore it, otherwise add it to the included_txns set if self.included_txns.contains(&tx_hash) { self.included_txns.remove(&tx_hash); From 288ddd856de21e2adfcd681df0f7b76cccfe2043 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 26 Jan 2024 16:04:49 -0500 Subject: [PATCH 07/47] fix metadata error --- src/builder_state.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 9bc6f8f4..c283dfbc 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -291,7 +291,7 @@ impl BuilderProgress for BuilderState{ let block_size = decide_msg.block_size; // get the most recent decide parent commitment as the first entry in the leaf_chain(sorted by descreasing view number) - let decide_parent_commitment = leaf_chain[0].parent_commitment; + let latest_decide_parent_commitment = leaf_chain[0].parent_commitment; // now we use this decide_parent_commitment to build blocks off @@ -305,8 +305,7 @@ impl BuilderProgress for BuilderState{ match block_payload{ Some(block_payload) => { println!("Block payload in decide event {:?}", block_payload); - let metadata: BlockPayload::Metadata = (); - + let metadata = leaf.get_block_header().metadata(); let transactions_commitments = block_payload.transaction_commitments(&metadata); // iterate over the transactions and remove them from tx_hash_to_tx and timestamp_to_tx, and included tx map //let transactions:Vec = vec![]; @@ -335,6 +334,8 @@ impl BuilderProgress for BuilderState{ } } } + + // TODO: Think how to make use of the latest_decide_parent_commitment to build blocks off } } From 1f92621abbe891b8aa9f774d838ef830c1f294b4 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 26 Jan 2024 16:32:16 -0500 Subject: [PATCH 08/47] added event specific actions --- src/builder_state.rs | 62 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index c283dfbc..16d70b8c 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -257,6 +257,30 @@ impl BuilderProgress for BuilderState{ self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data); } } + let mut block_txns:Vec = vec![]; + + // if we have a matching qc for the current da proposal, then we can build a block off it + if self.qc_payload_commit_to_qc.contains_key(&payload_vid_commitment){ + // can spawn or call a function to build a block off it + // get the current system time + let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); + // start making off a block using the txns from the local pool + // iterate over the timestamp_to_tx map and get the txns with lowest timestamp first + for (_, tx_hash) in self.timestamp_to_tx.iter() { + // get the transaction from the tx_hash_to_tx map + if let Some((_, tx, _)) = self.tx_hash_to_tx.get(tx_hash){ + // add the transaction to the block_txns if it not already included + if !self.included_txns.contains(tx_hash) { + // include into the current building block + block_txns.push(tx.clone()); + // include in the included tx set + self.included_txns.insert(tx_hash.clone()); + + } + } + } + + } } @@ -280,6 +304,32 @@ impl BuilderProgress for BuilderState{ } } + + //TODO: see how to build multiplie blocks using this same VID commitment + let mut block_txns:Vec = vec![]; + + // if we have a matching da for the current da proposal, then we can build a block off it + if self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment){ + // can spawn or call a function to build a block off it + // get the current system time + let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); + // start making off a block using the txns from the local pool + // iterate over the timestamp_to_tx map and get the txns with lowest timestamp first + for (_, tx_hash) in self.timestamp_to_tx.iter() { + // get the transaction from the tx_hash_to_tx map + if let Some((_, tx, _)) = self.tx_hash_to_tx.get(tx_hash){ + // add the transaction to the block_txns if it not already included + if !self.included_txns.contains(tx_hash) { + // include into the current building block + block_txns.push(tx.clone()); + // include in the included tx set + self.included_txns.insert(tx_hash.clone()); + + } + } + } + + } } /// processing the decide event @@ -297,7 +347,7 @@ impl BuilderProgress for BuilderState{ // do local pruning based on decide event data // iterate over all the decide leaves and extract out the transactions contained inside it - // for each transaction, check if it exists in the included_txns set, if yes, then ignore it, otherwise add it to the included_txns set + // for each transaction, check if it exists in the local tx pool, if yes, then remove it from the local tx pool for leaf in leaf_chain.iter() { // get the block payload // constrain its type to be of type TestBlockPayload @@ -307,15 +357,9 @@ impl BuilderProgress for BuilderState{ println!("Block payload in decide event {:?}", block_payload); let metadata = leaf.get_block_header().metadata(); let transactions_commitments = block_payload.transaction_commitments(&metadata); - // iterate over the transactions and remove them from tx_hash_to_tx and timestamp_to_tx, and included tx map + // iterate over the transactions and remove them from tx_hash_to_tx and timestamp_to_tx //let transactions:Vec = vec![]; for tx_hash in transactions_commitments.iter() { - // get the transaction hash - //let tx_hash = transaction.commit(); - // check if the transaction already exists in the included_txns set, if yes, then ignore it, otherwise add it to the included_txns set - if self.included_txns.contains(&tx_hash) { - self.included_txns.remove(&tx_hash); - } // remove the transaction from the timestamp_to_tx map if let Some((timestamp, _, _)) = self.tx_hash_to_tx.get(&tx_hash) { if self.timestamp_to_tx.contains_key(timestamp) { @@ -328,6 +372,8 @@ impl BuilderProgress for BuilderState{ } } + // TODO Is it safe to re-initialise the included_txns here, as we need to start fresh + self.included_txns = HashSet::new(); }, None => { println!("Block payload is none"); From f12a7d2b96985bc72871204cd9a27028de733475 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Tue, 30 Jan 2024 10:26:01 -0500 Subject: [PATCH 09/47] remove duplication --- src/builder_state.rs | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 16d70b8c..fdd07864 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -172,6 +172,9 @@ pub trait BuilderProgress { /// process the decide event async fn process_decide_event(&mut self, decide_msg: DecideMessage); + + /// build a block + async fn build_block(&mut self, payload_vid_commitment: VidCommitment) -> Option>; } @@ -257,30 +260,7 @@ impl BuilderProgress for BuilderState{ self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data); } } - let mut block_txns:Vec = vec![]; - - // if we have a matching qc for the current da proposal, then we can build a block off it - if self.qc_payload_commit_to_qc.contains_key(&payload_vid_commitment){ - // can spawn or call a function to build a block off it - // get the current system time - let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); - // start making off a block using the txns from the local pool - // iterate over the timestamp_to_tx map and get the txns with lowest timestamp first - for (_, tx_hash) in self.timestamp_to_tx.iter() { - // get the transaction from the tx_hash_to_tx map - if let Some((_, tx, _)) = self.tx_hash_to_tx.get(tx_hash){ - // add the transaction to the block_txns if it not already included - if !self.included_txns.contains(tx_hash) { - // include into the current building block - block_txns.push(tx.clone()); - // include in the included tx set - self.included_txns.insert(tx_hash.clone()); - - } - } - } - - } + let block = self.build_block(payload_vid_commitment).await; } @@ -304,12 +284,15 @@ impl BuilderProgress for BuilderState{ } } - + let block = self.build_block(payload_vid_commitment).await; + } + // build a block + async fn build_block(&mut self, payload_vid_commitment: VidCommitment) -> Option>{ //TODO: see how to build multiplie blocks using this same VID commitment let mut block_txns:Vec = vec![]; // if we have a matching da for the current da proposal, then we can build a block off it - if self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment){ + if self.qc_payload_commit_to_qc.contains_key(&payload_vid_commitment) && self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment){ // can spawn or call a function to build a block off it // get the current system time let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); @@ -328,8 +311,9 @@ impl BuilderProgress for BuilderState{ } } } - + return Some(block_txns); } + None } /// processing the decide event From f21425a58712cf418fe6b7a0f563cc3ea2446cf9 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Wed, 31 Jan 2024 18:41:00 -0500 Subject: [PATCH 10/47] refactoring --- Cargo.toml | 3 +- src/builder_state.rs | 276 ++++++++++++++++++++------------------ src/service.rs | 91 +++++++------ src/testing/basic_test.rs | 41 ++++-- 4 files changed, 221 insertions(+), 190 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 05df7f32..96230f3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,4 +43,5 @@ tokio = { version = "1"} atomic_store = { git = "https://github.com/EspressoSystems/atomicstore.git", tag = "0.1.3", optional = true } unix-time = "0.1.5" async-broadcast = "0.6.0" -sha2 = "0.10" \ No newline at end of file +sha2 = "0.10" +jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish" } \ No newline at end of file diff --git a/src/builder_state.rs b/src/builder_state.rs index fdd07864..bd6fd512 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -4,6 +4,7 @@ #![allow(unused_imports)] #![allow(unused_variables)] +use std::collections::hash_map::Entry; use std::collections::{BTreeMap, HashMap, HashSet}; use std::hash::BuildHasher; use std::marker::PhantomData; @@ -17,6 +18,7 @@ use async_trait::async_trait; use async_lock::RwLock; use hotshot_task_impls::transactions; use hotshot_types::traits::block_contents::vid_commitment; +use hotshot_types::vote::Certificate; use sha2::{Digest, Sha256}; use hotshot::rand::seq::index; @@ -46,100 +48,71 @@ use hotshot_types::{ }; use commit::{Commitment, Committable}; +use jf_primitives::signatures::bls_over_bn254::{BLSOverBN254CurveSignatureScheme, KeyPair, SignKey, VerKey}; + pub type TxTimeStamp = u128; -const NODES_IN_VID_COMPUTATION: usize = 8; +const NUM_NODES_IN_VID_COMPUTATION: usize = 8; #[derive(Clone, Debug, PartialEq)] -pub enum TransactionType { +pub enum TransactionSource { External, // txn from the external source i.e private mempool HotShot, // txn from the HotShot network i.e public mempool } #[derive(Clone, Debug, PartialEq)] pub struct TransactionMessage{ - //tx_hash: T::TransactionCommit, - //tx: T::Transaction, pub tx: TYPES::Transaction, - pub tx_type: TransactionType, + pub tx_type: TransactionSource, } #[derive(Clone, Debug, PartialEq)] pub struct DecideMessage{ - //block_hash: T::BlockCommit, pub leaf_chain: Arc>>, pub qc: Arc>, pub block_size: Option } #[derive(Clone, Debug, PartialEq)] pub struct DAProposalMessage{ - //block_hash: T::BlockCommit, - //block: T::Block, pub proposal: Proposal>, - pub sender: TYPES::SignatureKey + pub sender: TYPES::SignatureKey, + pub total_nodes: usize, } #[derive(Clone, Debug, PartialEq)] pub struct QCMessage{ - //block_hash: T::BlockCommit, - //block: T::Block, pub proposal: Proposal>, - pub sender: TYPES::SignatureKey + pub sender: TYPES::SignatureKey, } use std::cmp::{PartialEq, Ord, PartialOrd}; use std::hash::Hash; -/* -Note: Discarded this idea of having a generic trait since Leaf depends on Nodetype -pub trait BuilderType{ - /// The time type that this hotshot setup is using. - /// - /// This should be the same `Time` that `StateType::Time` is using. - type Time: ConsensusTime; - /// The block header type that this hotshot setup is using. - type BlockHeader: BlockHeader; - /// The block type that this hotshot setup is using. - /// - /// This should be the same block that `StateType::BlockPayload` is using. - type BlockPayload: BlockPayload; - /// The signature key that this hotshot setup is using. - type SignatureKey: SignatureKey; - /// The transaction type that this hotshot setup is using. - /// - /// This should be equal to `BlockPayload::Transaction` - type Transaction: Transaction; - /// The builder ID type - type BuilderID; -} -*/ - #[derive(Debug, Clone)] -pub struct BuilderState { +pub struct BuilderState{ - pub builder_id: usize, + pub builder_id: (VerKey, SignKey), //TODO (pub,priv) key of the builder, may be good to keep a ref // timestamp to tx hash, used for ordering for the transactions pub timestamp_to_tx: BTreeMap>, // transaction hash to transaction data for efficient lookup - pub tx_hash_to_tx: HashMap,(TxTimeStamp, TYPES::Transaction, TransactionType)>, + pub tx_hash_to_available_txns: HashMap,(TxTimeStamp, TYPES::Transaction, TransactionSource)>, /// Included txs set while building blocks pub included_txns: HashSet>, - - /// parent hash to set of block hashes - pub parent_hash_to_block_hash: HashMap>, - + /// block hash to the full block pub block_hash_to_block: HashMap, /// da_proposal_payload_commit to da_proposal pub da_proposal_payload_commit_to_da_proposal: HashMap>, - /// qc_payload_commit to qc - pub qc_payload_commit_to_qc: HashMap>, + /// quorum_proposal_payload_commit to quorum_proposal + pub quorum_proposal_payload_commit_to_quorum_proposal: HashMap>, - /// processed views - pub processed_views: HashMap>, + /// view number of the basis for this block + /// vid commitment of the basis for this block + /// Commitment> => QuorumCertificate::vote_commitment + pub built_from_view_vid_leaf: (TYPES::Time, VidCommitment, Commitment>), // Channel Receivers for the HotShot events, Tx_receiver could also receive the external transactions /// transaction receiver @@ -148,12 +121,14 @@ pub struct BuilderState { /// decide receiver pub decide_receiver: BroadcastReceiver>, - // TODO: Currently make it receivers, but later we might need to change it /// da proposal event channel pub da_proposal_receiver: BroadcastReceiver>, /// quorum proposal event channel pub qc_receiver: BroadcastReceiver>, + + // channel receiver for the requests + pub req_receiver: BroadcastReceiver>, } /// Trait to hold the helper functions for the builder #[async_trait] @@ -173,8 +148,11 @@ pub trait BuilderProgress { /// process the decide event async fn process_decide_event(&mut self, decide_msg: DecideMessage); + /// spawn a clone of builder + async fn spawn_clone(self, da_proposal: DAProposal, quorum_proposal: QuorumProposal); + /// build a block - async fn build_block(&mut self, payload_vid_commitment: VidCommitment) -> Option>; + async fn build_block(&mut self, matching_vid: VidCommitment) -> Option>; } @@ -192,8 +170,9 @@ impl BuilderProgress for BuilderState{ // get tx_hash as keu let tx_hash = tx.commit(); // If it already exists, then discard it. Decide the existence based on the tx_hash_tx and check in both the local pool and already included txns - if self.tx_hash_to_tx.contains_key(&tx_hash) || self.included_txns.contains(&tx_hash) { + if self.tx_hash_to_available_txns.contains_key(&tx_hash) || self.included_txns.contains(&tx_hash) { println!("Transaction already exists in the builderinfo.txid_to_tx hashmap, So we can ignore it"); + return; } else { // get the current timestamp in nanoseconds; it used for ordering the transactions @@ -201,7 +180,7 @@ impl BuilderProgress for BuilderState{ // insert into both timestamp_tx and tx_hash_tx maps self.timestamp_to_tx.insert(tx_timestamp, tx_hash.clone()); - self.tx_hash_to_tx.insert(tx_hash, (tx_timestamp, tx, TransactionType::External)); + self.tx_hash_to_available_txns.insert(tx_hash, (tx_timestamp, tx, TransactionSource::External)); } } @@ -211,25 +190,31 @@ impl BuilderProgress for BuilderState{ let tx_hash = tx.commit(); // HOTSHOT MEMPOOL TRANSACTION PROCESSING // If it already exists, then discard it. Decide the existence based on the tx_hash_tx and check in both the local pool and already included txns - if self.tx_hash_to_tx.contains_key(&tx_hash) && self.included_txns.contains(&tx_hash) { + if self.tx_hash_to_available_txns.contains_key(&tx_hash) || self.included_txns.contains(&tx_hash) { println!("Transaction already exists in the builderinfo.txid_to_tx hashmap, So we can ignore it"); - } - else { + return; + } else { // get the current timestamp in nanoseconds let tx_timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); // insert into both timestamp_tx and tx_hash_tx maps self.timestamp_to_tx.insert(tx_timestamp, tx_hash.clone()); - self.tx_hash_to_tx.insert(tx_hash, (tx_timestamp, tx, TransactionType::HotShot)); + self.tx_hash_to_available_txns.insert(tx_hash, (tx_timestamp, tx, TransactionSource::HotShot)); } } /// processing the DA proposal async fn process_da_proposal(&mut self, da_msg: DAProposalMessage) { - //println!("Processing DA proposal"); - //todo!("process_da_proposal"); - + // Validation + // check for view number + // check for signature validation and correct leader (both of these are done in the service.rs i.e. before putting hotshot events onto the da channel) + + if da_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0{ + println!("View number does not match the built_from_view, so ignoring it"); + return; + } + let da_proposal_data = da_msg.proposal.data.clone(); let sender = da_msg.sender; @@ -239,93 +224,72 @@ impl BuilderProgress for BuilderState{ let metadata: <::BlockPayload as BlockPayload>::Metadata = da_proposal_data.metadata; - // get the block payload from the encoded_txns - let block_payload_txns = TestBlockPayload::from_bytes(encoded_txns.clone().into_iter(), &()).transactions; - - let encoded_txns_hash = Sha256::digest(&encoded_txns); + // get the block payload from the encoded_txns; the following are not used currently, however might need later + // let block_payload_txns = TestBlockPayload::from_bytes(encoded_txns.clone().into_iter(), &()).transactions; + // let encoded_txns_hash = Sha256::digest(&encoded_txns); // generate the vid commitment - // TODO: Currently we are hardcoding the number of storage nodes to 8, but later read it either form sequencer/hotshot repo - let payload_vid_commitment = vid_commitment(&encoded_txns, NODES_IN_VID_COMPUTATION); + let total_nodes = da_msg.total_nodes; + let payload_vid_commitment = vid_commitment(&encoded_txns, total_nodes); if !self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment) { - // add the original da proposal to the hashmap - // verify the signature and if valid then insert into the map - if sender.validate(&da_msg.proposal.signature, &encoded_txns_hash) { - let da_proposal_data = DAProposal { - encoded_transactions: encoded_txns.clone(), - metadata: metadata.clone(), - view_number: view_number, - }; + let da_proposal_data = DAProposal { + encoded_transactions: encoded_txns.clone(), + metadata: metadata.clone(), + view_number: view_number, + }; + + // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. + if let Entry::Occupied(qc_proposal_data) = self.quorum_proposal_payload_commit_to_quorum_proposal.entry(payload_vid_commitment.clone()) { + let qc_proposal_data = qc_proposal_data.remove(); + self.clone().spawn_clone(da_proposal_data, qc_proposal_data); + } else { self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data); - } + } + } - let block = self.build_block(payload_vid_commitment).await; - } /// processing the quorum proposal async fn process_quorum_proposal(&mut self, qc_msg: QCMessage) { - //println!("Processing quorum proposal"); + // Validation + // check for view number + // check for the leaf commitment + // check for signature validation and correct leader (both of these are done in the service.rs i.e. before putting hotshot events onto the da channel) + // can use this commitment to match the da proposal or vice-versa + if qc_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0 || + qc_msg.proposal.data.justify_qc.get_data().leaf_commit != self.built_from_view_vid_leaf.2 { + println!("Either View number or leaf commit does not match the built-in info, so ignoring it"); + return; + } let qc_proposal_data = qc_msg.proposal.data; let sender = qc_msg.sender; let payload_vid_commitment = qc_proposal_data.block_header.payload_commitment(); - - // can use this commitment to match the da proposal or vice-versa // first check whether vid_commitment exists in the qc_payload_commit_to_qc hashmap, if yer, ignore it, otherwise validate it and later insert in - if !self.qc_payload_commit_to_qc.contains_key(&payload_vid_commitment){ - // Verify the signature of the QC proposal - // insert into the qc_payload_commit_to_qc hashmap if not exists already - if sender.validate(&qc_msg.proposal.signature, payload_vid_commitment.as_ref()) { - self.qc_payload_commit_to_qc.insert(payload_vid_commitment, qc_proposal_data.clone()); - - } - } - let block = self.build_block(payload_vid_commitment).await; - } - // build a block - async fn build_block(&mut self, payload_vid_commitment: VidCommitment) -> Option>{ - //TODO: see how to build multiplie blocks using this same VID commitment - let mut block_txns:Vec = vec![]; - - // if we have a matching da for the current da proposal, then we can build a block off it - if self.qc_payload_commit_to_qc.contains_key(&payload_vid_commitment) && self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment){ - // can spawn or call a function to build a block off it - // get the current system time - let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); - // start making off a block using the txns from the local pool - // iterate over the timestamp_to_tx map and get the txns with lowest timestamp first - for (_, tx_hash) in self.timestamp_to_tx.iter() { - // get the transaction from the tx_hash_to_tx map - if let Some((_, tx, _)) = self.tx_hash_to_tx.get(tx_hash){ - // add the transaction to the block_txns if it not already included - if !self.included_txns.contains(tx_hash) { - // include into the current building block - block_txns.push(tx.clone()); - // include in the included tx set - self.included_txns.insert(tx_hash.clone()); - - } + if !self.quorum_proposal_payload_commit_to_quorum_proposal.contains_key(&payload_vid_commitment){ + // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. + if let Entry::Occupied(da_proposal_data) = self.da_proposal_payload_commit_to_da_proposal.entry(payload_vid_commitment.clone()) { + let da_proposal_data = da_proposal_data.remove(); + self.clone().spawn_clone(da_proposal_data, qc_proposal_data); + } else { + self.quorum_proposal_payload_commit_to_quorum_proposal.insert(payload_vid_commitment, qc_proposal_data.clone()); } - } - return Some(block_txns); } - None + } - + /// processing the decide event async fn process_decide_event(&mut self, decide_msg: DecideMessage) { - let leaf_chain = decide_msg.leaf_chain; let qc = decide_msg.qc; let block_size = decide_msg.block_size; // get the most recent decide parent commitment as the first entry in the leaf_chain(sorted by descreasing view number) - let latest_decide_parent_commitment = leaf_chain[0].parent_commitment; + // let latest_decide_parent_commitment = leaf_chain[0].parent_commitment; // now we use this decide_parent_commitment to build blocks off @@ -345,27 +309,77 @@ impl BuilderProgress for BuilderState{ //let transactions:Vec = vec![]; for tx_hash in transactions_commitments.iter() { // remove the transaction from the timestamp_to_tx map - if let Some((timestamp, _, _)) = self.tx_hash_to_tx.get(&tx_hash) { + if let Some((timestamp, _, _)) = self.tx_hash_to_available_txns.get(&tx_hash) { if self.timestamp_to_tx.contains_key(timestamp) { self.timestamp_to_tx.remove(timestamp); } - } - // remove the transaction from the tx_hash_to_tx map also - if self.tx_hash_to_tx.contains_key(&tx_hash) { - self.tx_hash_to_tx.remove(&tx_hash); + self.tx_hash_to_available_txns.remove(&tx_hash); } + // remove from the included_txns set also + self.included_txns.remove(&tx_hash); } - // TODO Is it safe to re-initialise the included_txns here, as we need to start fresh - self.included_txns = HashSet::new(); }, None => { println!("Block payload is none"); } } } + } + + // spawn a clone of the builder state + async fn spawn_clone(self, da_proposal: DAProposal, quorum_proposal: QuorumProposal) + { + // spawn a clone of the builder + // let mut cloned_builder = self.clone(); + // // spawn a new task to build a block off the matching da and quorum proposals + // let cloned_builder_handle = task::spawn(async move { + // //cloned_builder.build_block(da_proposal, quorum_proposal).await; + // }); + print!("Spawned a new task to build a block off the matching da and quorum proposals"); + } + + // build a block + async fn build_block(&mut self, matching_vid: VidCommitment) -> Option>{ + let mut block_txns:Vec = vec![]; + + // if we have a matching da for the current da proposal, then we can build a block off it + if self.quorum_proposal_payload_commit_to_quorum_proposal.contains_key(&matching_vid) && self.da_proposal_payload_commit_to_da_proposal.contains_key(&matching_vid){ + // can spawn or call a function to build a block off it + // get the current system time + let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); + // start making off a block using the txns from the local pool + // iterate over the timestamp_to_tx map and get the txns with lowest timestamp first + let mut to_remove_timestamps:Vec = vec![]; + let mut to_remove_tx_hashes:Vec> = vec![]; - // TODO: Think how to make use of the latest_decide_parent_commitment to build blocks off + for (timestamp, tx_hash) in self.timestamp_to_tx.iter() { + // get the transaction from the tx_hash_to_tx map + if let Some((_, tx, _)) = self.tx_hash_to_available_txns.get(tx_hash){ + // add the transaction to the block_txns if it not already included + if !self.included_txns.contains(tx_hash) { + // include into the current building block + block_txns.push(tx.clone()); + // include in the included tx set + self.included_txns.insert(tx_hash.clone()); + + } + to_remove_tx_hashes.push(*tx_hash); + } + to_remove_timestamps.push(*timestamp); + } + + // iterate over the to_remove_tx_hashes and remove them from the tx_hash_to_available_txns map + for tx_hash in to_remove_tx_hashes.iter() { + self.tx_hash_to_available_txns.remove(tx_hash); + } + // iterate over the to_remove_timestamps and remove them from the timestamp_to_tx map + for timestamp in to_remove_timestamps.iter() { + self.timestamp_to_tx.remove(timestamp); + } + return Some(block_txns); + } + None } } @@ -379,21 +393,21 @@ pub enum MessageType{ } impl BuilderState{ - pub fn new(builder_id: usize, tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>)-> Self{ + pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>)-> Self{ BuilderState{ - builder_id, + builder_id: builder_id, timestamp_to_tx: BTreeMap::new(), - tx_hash_to_tx: HashMap::new(), + tx_hash_to_available_txns: HashMap::new(), included_txns: HashSet::new(), - parent_hash_to_block_hash: HashMap::new(), block_hash_to_block: HashMap::new(), - processed_views: HashMap::new(), + built_from_view_vid_leaf: view_vid_leaf, tx_receiver: tx_receiver, decide_receiver: decide_receiver, da_proposal_receiver: da_proposal_receiver, qc_receiver: qc_receiver, + req_receiver: req_receiver, da_proposal_payload_commit_to_da_proposal: HashMap::new(), - qc_payload_commit_to_qc: HashMap::new(), + quorum_proposal_payload_commit_to_quorum_proposal: HashMap::new(), } } diff --git a/src/service.rs b/src/service.rs index bd4a2798..4bbf9e92 100644 --- a/src/service.rs +++ b/src/service.rs @@ -18,7 +18,7 @@ // TODO no warning for unused imports #![allow(unused_imports)] #![allow(unused_variables)] -pub use hotshot::{traits::NodeImplementation, types::SystemContextHandle}; +pub use hotshot::{traits::NodeImplementation, types::SystemContextHandle, HotShotConsensusApi}; //use async_compatibility_layer::{channel::UnboundedStream, art::async_spawn}; use async_lock::RwLock; use commit::Committable; @@ -32,7 +32,7 @@ use hotshot_task::{ }; use hotshot_task_impls::events::HotShotEvent; use hotshot_testing::state_types::TestTypes; -use hotshot_types::simple_vote::QuorumData; +use hotshot_types::{data::VidCommitment, simple_vote::QuorumData}; use hotshot_types::{ consensus::Consensus, error::HotShotError, @@ -40,49 +40,29 @@ use hotshot_types::{ message::{MessageKind, SequencingMessage}, traits::{ election::Membership, node_implementation::NodeType as BuilderType, state::ConsensusTime, storage::Storage, + signature_key::SignatureKey,block_contents::BlockHeader, consensus_api::ConsensusApi }, }; use hotshot_types::{data::Leaf, simple_certificate::QuorumCertificate}; - -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; use tracing::error; //use crate::builder_state::{MessageType, BuilderType, TransactionMessage, DecideMessage, QuorumProposalMessage, QCMessage}; use async_broadcast::{broadcast, Sender as BroadcastSender, Receiver as BroadcastReceiver}; use futures::future::ready; use crate::builder_state::{BuilderState, MessageType}; -use crate::builder_state::{TransactionMessage, TransactionType, DecideMessage, DAProposalMessage, QCMessage}; +use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage}; + +use sha2::{Digest, Sha256}; #[derive(clap::Args, Default)] pub struct Options { #[clap(short, long, env = "ESPRESSO_BUILDER_PORT")] pub port: u16 } - - -// async fn process_events() -> Result<(), Error> { -// loop { -// // wait for an event -// // process the event -// // if the event is a transaction, then process it -// // if the event is a DA proposal, then process it -// // if the event is a QC proposal, then process it -// // if the event is a decide event, then process it -// } -// } - -// following could be used if we need additiona processing for the events we received before passing to a builder -async fn process_da_proposal(builder_info: &mut BuilderState){ - unimplemented!("Process DA Proposal"); -} - - -async fn process_qc_proposal(builder_info: &mut BuilderState){ - unimplemented!("Process QC Proposal"); -} - - -async fn process_decide_event(builder_info: &mut BuilderState, ) { - unimplemented!("Process Decide Event"); +// +pub struct GlobalState{ + pub block_hash_to_block: HashMap, + pub vid_to_potential_builder_state: HashMap>, } /// Run an instance of the default Espresso builder service. @@ -100,8 +80,6 @@ pub async fn run_standalone_builder_service: availability::QueryablePayload // Might need to bound D with something... { - - // hear out for events from the context handle and execute them loop { let (mut event_stream, _streamid) = hotshot.get_event_stream(FilterEvent::default()).await; match event_stream.next().await { @@ -123,7 +101,7 @@ pub async fn run_standalone_builder_service{ tx: tx_message, - tx_type: TransactionType::HotShot, + tx_type: TransactionSource::HotShot, }; tx_sender.broadcast(MessageType::TransactionMessage(tx_msg)).await.unwrap(); } @@ -131,22 +109,43 @@ pub async fn run_standalone_builder_service { // process the DA proposal - // process_da_proposal(da_proposal, data_source.clone()).await?; - let da_msg = DAProposalMessage::{ - proposal: proposal, - sender: sender, - }; - da_sender.broadcast(MessageType::DAProposalMessage(da_msg)).await.unwrap(); - + // get the leader for current view + let leader = hotshot.get_leader(proposal.data.view_number).await; + // get the encoded transactions hash + let encoded_txns_hash = Sha256::digest(&proposal.data.encoded_transactions); + // check if the sender is the leader and the signature is valid; if yes, broadcast the DA proposal + if leader == sender && sender.validate(&proposal.signature, &encoded_txns_hash){ + + // get the num of VID nodes + let c_api: HotShotConsensusApi = HotShotConsensusApi { + inner: hotshot.hotshot.inner.clone(), + }; + + let total_nodes = c_api.total_nodes(); + + let da_msg = DAProposalMessage::{ + proposal: proposal, + sender: sender, + total_nodes: total_nodes.into(), + }; + da_sender.broadcast(MessageType::DAProposalMessage(da_msg)).await.unwrap(); + } } // QC proposal event EventType::QuorumProposal{proposal, sender} => { // process the QC proposal - let qc_msg = QCMessage::{ - proposal: proposal, - sender: sender, - }; - qc_sender.broadcast(MessageType::QCMessage(qc_msg)).await.unwrap(); + // get the leader for current view + let leader = hotshot.get_leader(proposal.data.view_number).await; + // get the payload commitment + let payload_commitment = proposal.data.block_header.payload_commitment(); + // check if the sender is the leader and the signature is valid; if yes, broadcast the QC proposal + if sender == leader && sender.validate(&proposal.signature, payload_commitment.as_ref()) { + let qc_msg = QCMessage::{ + proposal: proposal, + sender: sender, + }; + qc_sender.broadcast(MessageType::QCMessage(qc_msg)).await.unwrap(); + } } // decide event EventType::Decide { diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index e9f6f961..35d665b4 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -10,7 +10,7 @@ use async_std::task::{self, Builder}; use std::sync::Arc; use sha2::{Digest, Sha256}; use futures::future::select_all; -pub use hotshot_testing::{block_types::{TestTransaction, TestBlockHeader, TestBlockPayload}, state_types::TestState}; +pub use hotshot_testing::{block_types::{TestTransaction, TestBlockHeader, TestBlockPayload, genesis_vid_commitment}, state_types::TestState}; pub use hotshot_types::{ traits::node_implementation::NodeType as BuilderType, data::{ViewNumber, Leaf, DAProposal, QuorumProposal}, @@ -23,7 +23,7 @@ pub use hotshot::traits::election::static_committee::{GeneralStaticCommittee, St pub use crate::builder_state::{BuilderState,MessageType, BuilderProgress}; pub use async_broadcast::{broadcast, TryRecvError, Sender as BroadcastSender, Receiver as BroadcastReceiver, RecvError}; // tests - +use commit::{Commitment, Committable, CommitmentBoundsArkless}; /// The following tests are performed: #[cfg(test)] mod tests { @@ -31,11 +31,10 @@ mod tests { use core::num; use std::{collections::HashSet, env, hash::Hash, marker::PhantomData}; - use commit::Committable; use hotshot::{rand::seq::index, types::SignatureKey}; use hotshot_types::{data::QuorumProposal, traits::{block_contents::BlockHeader, state::ConsensusTime}, vote::HasViewNumber}; - use crate::builder_state::{TransactionMessage, TransactionType, DecideMessage, DAProposalMessage, QCMessage}; + use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage}; #[derive(Debug, Clone)] @@ -75,12 +74,14 @@ mod tests { type Membership = GeneralStaticCommittee; } - let num_test_messages = 100; + let num_test_messages = 3; let (tx_sender, tx_receiver) = broadcast::>(num_test_messages*2); let (decide_sender, decide_receiver) = broadcast::>(num_test_messages*2); let (da_sender, da_receiver) = broadcast::>(num_test_messages*2); let (qc_sender, qc_receiver) = broadcast::>(num_test_messages*2); - + let (req_sender, req_receiver) = broadcast::>(num_test_messages*2); + + let mut stx_msgs = Vec::new(); let mut sdecide_msgs = Vec::new(); let mut sda_msgs = Vec::new(); @@ -94,7 +95,7 @@ mod tests { // Prepare the transaction message let stx_msg = TransactionMessage::{ tx: tx.clone(), - tx_type: TransactionType::HotShot, + tx_type: TransactionSource::HotShot, }; // Prepare the decide message @@ -127,6 +128,7 @@ mod tests { _pd: PhantomData }, sender: pub_key, + total_nodes: 8, }; // Prepare the QC proposal message @@ -162,20 +164,24 @@ mod tests { } // spwan 10 builder instances, later try receing on each of the instance let mut handles = Vec::new(); - for i in 0..10 { + for i in 0..2 { let tx_receiver_clone = tx_receiver.clone(); let decide_receiver_clone = decide_receiver.clone(); let da_receiver_clone = da_receiver.clone(); let qc_receiver_clone = qc_receiver.clone(); + let req_receiver_clone = req_receiver.clone(); let stx_msgs: Vec> = stx_msgs.clone(); let sdecide_msgs: Vec> = sdecide_msgs.clone(); let sda_msgs: Vec> = sda_msgs.clone(); let sqc_msgs: Vec> = sqc_msgs.clone(); - + // TODO clone a handle and check it contains the remaining messages and don't contain the messages before cloning it let handle = task::spawn(async move { - let mut builder_state = BuilderState::::new(i, tx_receiver_clone, decide_receiver_clone, da_receiver_clone, qc_receiver_clone); + let built_from_view_vid_leaf = (ViewNumber::new(i as u64), genesis_vid_commitment(), Commitment::>::default_commitment_no_preimage()); + let (pub_key, private_key) = BLSPubKey::generated_from_seed_indexed([i as u8; 32],i as u64); + + let mut builder_state = BuilderState::::new((pub_key, private_key), built_from_view_vid_leaf, tx_receiver_clone, decide_receiver_clone, da_receiver_clone, qc_receiver_clone,req_receiver_clone); // to keep track of the messages received by the builder let mut rtx_msgs: Vec> = Vec::new(); @@ -186,12 +192,20 @@ mod tests { let mut channel_close_index = HashSet::::new(); loop{ - let (received_msg, channel_index, _)= select_all([builder_state.tx_receiver.recv(), builder_state.decide_receiver.recv(), builder_state.da_proposal_receiver.recv(), builder_state.qc_receiver.recv()]).await; + // while Ok(req) = builder_state.req_receiver.try_recv() { + // //... handle requests + // // it says do I have a block for this set of txns? if so, return that header?? MPSC [async_compatility] + // // else iterate through and call build block, and add block to blockmap in globalstate + // // do validity check for the requester as well i.e are they leader for one of the next k views + + // } + let (received_msg, channel_index, _)= select_all([builder_state.req_receiver.recv(), builder_state.tx_receiver.recv(), builder_state.decide_receiver.recv(), builder_state.da_proposal_receiver.recv(), builder_state.qc_receiver.recv()]).await; match received_msg { Ok(received_msg) => { match received_msg { MessageType::TransactionMessage(rtx_msg) => { + println!("Received tx msg from builder {}: {:?} from index {}", i, rtx_msg, channel_index); // store in the rtx_msgs rtx_msgs.push(rtx_msg.clone()); @@ -200,7 +214,7 @@ mod tests { //println!("Received tx msg from builder {}: {:?} from index {}", i, rtx_msg, index); assert_eq!(stx_msgs.get(index).unwrap().tx.commit(), rtx_msg.tx.commit()); // Pass the tx msg to the handler - if rtx_msg.tx_type == TransactionType::HotShot { + if rtx_msg.tx_type == TransactionSource::HotShot { builder_state.process_hotshot_transaction(rtx_msg.tx).await; } else { builder_state.process_external_transaction(rtx_msg.tx).await; @@ -208,6 +222,7 @@ mod tests { } MessageType::DecideMessage(rdecide_msg) => { + println!("Received decide msg from builder {}: {:?} from index {}", i, rdecide_msg, channel_index); // store in the rdecide_msgs rdecide_msgs.push(rdecide_msg.clone()); @@ -216,6 +231,7 @@ mod tests { builder_state.process_decide_event(rdecide_msg).await; } MessageType::DAProposalMessage(rda_msg) => { + println!("Received da msg from builder {}: {:?} from index {}", i, rda_msg, channel_index); // store in the rda_msgs rda_msgs.push(rda_msg.clone()); @@ -225,6 +241,7 @@ mod tests { builder_state.process_da_proposal(rda_msg).await; } MessageType::QCMessage(rqc_msg) => { + println!("Received qc msg from builder {}: {:?} from index {}", i, rqc_msg, channel_index); // store in the rqc_msgs rqc_msgs.push(rqc_msg.clone()); From 8abf8520ac81f4ec9dba6982b99ca352812fc7b2 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Thu, 1 Feb 2024 13:30:57 -0500 Subject: [PATCH 11/47] add request message --- src/builder_state.rs | 10 +++++-- src/testing/basic_test.rs | 56 ++++++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index bd6fd512..2109dbf3 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -82,6 +82,11 @@ pub struct QCMessage{ pub sender: TYPES::SignatureKey, } +#[derive(Clone, Debug, PartialEq)] +pub struct RequestMessage{ + pub requested_vid_commitment: VidCommitment, +} + use std::cmp::{PartialEq, Ord, PartialOrd}; use std::hash::Hash; @@ -267,7 +272,7 @@ impl BuilderProgress for BuilderState{ let sender = qc_msg.sender; let payload_vid_commitment = qc_proposal_data.block_header.payload_commitment(); - + // first check whether vid_commitment exists in the qc_payload_commit_to_qc hashmap, if yer, ignore it, otherwise validate it and later insert in if !self.quorum_proposal_payload_commit_to_quorum_proposal.contains_key(&payload_vid_commitment){ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. @@ -389,7 +394,8 @@ pub enum MessageType{ TransactionMessage(TransactionMessage), DecideMessage(DecideMessage), DAProposalMessage(DAProposalMessage), - QCMessage(QCMessage) + QCMessage(QCMessage), + RequestMessage(RequestMessage), } impl BuilderState{ diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 35d665b4..2173cfab 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -7,7 +7,7 @@ #![allow(unused_imports)] use async_std::task::{self, Builder}; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use sha2::{Digest, Sha256}; use futures::future::select_all; pub use hotshot_testing::{block_types::{TestTransaction, TestBlockHeader, TestBlockPayload, genesis_vid_commitment}, state_types::TestState}; @@ -32,7 +32,7 @@ mod tests { use std::{collections::HashSet, env, hash::Hash, marker::PhantomData}; use hotshot::{rand::seq::index, types::SignatureKey}; - use hotshot_types::{data::QuorumProposal, traits::{block_contents::BlockHeader, state::ConsensusTime}, vote::HasViewNumber}; + use hotshot_types::{data::QuorumProposal, message::Message, traits::{block_contents::BlockHeader, state::ConsensusTime}, vote::HasViewNumber}; use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage}; @@ -165,6 +165,7 @@ mod tests { // spwan 10 builder instances, later try receing on each of the instance let mut handles = Vec::new(); for i in 0..2 { + let tx_receiver_clone = tx_receiver.clone(); let decide_receiver_clone = decide_receiver.clone(); let da_receiver_clone = da_receiver.clone(); @@ -175,13 +176,18 @@ mod tests { let sdecide_msgs: Vec> = sdecide_msgs.clone(); let sda_msgs: Vec> = sda_msgs.clone(); let sqc_msgs: Vec> = sqc_msgs.clone(); + // TODO clone a handle and check it contains the remaining messages and don't contain the messages before cloning it let handle = task::spawn(async move { let built_from_view_vid_leaf = (ViewNumber::new(i as u64), genesis_vid_commitment(), Commitment::>::default_commitment_no_preimage()); + let (pub_key, private_key) = BLSPubKey::generated_from_seed_indexed([i as u8; 32],i as u64); - let mut builder_state = BuilderState::::new((pub_key, private_key), built_from_view_vid_leaf, tx_receiver_clone, decide_receiver_clone, da_receiver_clone, qc_receiver_clone,req_receiver_clone); + //let mut builder_state = Arc::new(Mutex::new(BuilderState::::new((pub_key, private_key), built_from_view_vid_leaf, tx_receiver_clone, decide_receiver_clone, da_receiver_clone, qc_receiver_clone,req_receiver_clone))); + let mut builder_state = BuilderState::::new((pub_key, private_key), built_from_view_vid_leaf, + tx_receiver_clone, decide_receiver_clone, da_receiver_clone, + qc_receiver_clone, req_receiver_clone); // to keep track of the messages received by the builder let mut rtx_msgs: Vec> = Vec::new(); @@ -190,22 +196,46 @@ mod tests { let mut rqc_msgs:Vec> = Vec::new(); let mut channel_close_index = HashSet::::new(); + //let shared_builder_state = Arc::clone(&builder_state); loop{ - // while Ok(req) = builder_state.req_receiver.try_recv() { + while let Ok(req) = builder_state.req_receiver.recv().await { + println!("Received request in builder {}: {:?}", i, req); + if let MessageType::RequestMessage(req) = req { + + let requested_vid_commitment = req.requested_vid_commitment; + + } // //... handle requests // // it says do I have a block for this set of txns? if so, return that header?? MPSC [async_compatility] // // else iterate through and call build block, and add block to blockmap in globalstate // // do validity check for the requester as well i.e are they leader for one of the next k views - // } - let (received_msg, channel_index, _)= select_all([builder_state.req_receiver.recv(), builder_state.tx_receiver.recv(), builder_state.decide_receiver.recv(), builder_state.da_proposal_receiver.recv(), builder_state.qc_receiver.recv()]).await; + } + + + // unlock the builder state + //let mut builder_state = builder_state.lock().unwrap(); + + let (received_msg, channel_index, _)= select_all([builder_state.tx_receiver.recv(), + builder_state.decide_receiver.recv(), builder_state.da_proposal_receiver.recv(), + builder_state.qc_receiver.recv(), builder_state.req_receiver.recv()]).await; match received_msg { Ok(received_msg) => { match received_msg { + + // request message + MessageType::RequestMessage(req) => { + println!("Received request msg in builder {}: {:?} from index {}", i, req, channel_index); + // store in the rtx_msgs + //rreq_msgs.push(req.clone()); + //builder_state.process_request(req).await; + } + + // transaction message MessageType::TransactionMessage(rtx_msg) => { - println!("Received tx msg from builder {}: {:?} from index {}", i, rtx_msg, channel_index); + println!("Received tx msg in builder {}: {:?} from index {}", i, rtx_msg, channel_index); // store in the rtx_msgs rtx_msgs.push(rtx_msg.clone()); @@ -221,8 +251,10 @@ mod tests { } } + + // decide message MessageType::DecideMessage(rdecide_msg) => { - println!("Received decide msg from builder {}: {:?} from index {}", i, rdecide_msg, channel_index); + println!("Received decide msg in builder {}: {:?} from index {}", i, rdecide_msg, channel_index); // store in the rdecide_msgs rdecide_msgs.push(rdecide_msg.clone()); @@ -230,8 +262,10 @@ mod tests { assert_eq!(sdecide_msgs.get(rdecide_msg.block_size.unwrap() as usize).unwrap().block_size, rdecide_msg.block_size); builder_state.process_decide_event(rdecide_msg).await; } + + // DA proposal message MessageType::DAProposalMessage(rda_msg) => { - println!("Received da msg from builder {}: {:?} from index {}", i, rda_msg, channel_index); + println!("Received da msg in builder {}: {:?} from index {}", i, rda_msg, channel_index); // store in the rda_msgs rda_msgs.push(rda_msg.clone()); @@ -240,8 +274,10 @@ mod tests { assert_eq!(sda_msgs.get(view_number as usize).unwrap().proposal.data.view_number.get_u64(), rda_msg.proposal.data.view_number.get_u64()); builder_state.process_da_proposal(rda_msg).await; } + + // QC proposal message MessageType::QCMessage(rqc_msg) => { - println!("Received qc msg from builder {}: {:?} from index {}", i, rqc_msg, channel_index); + println!("Received qc msg in builder {}: {:?} from index {}", i, rqc_msg, channel_index); // store in the rqc_msgs rqc_msgs.push(rqc_msg.clone()); From 7cc0a5e64b7f632b7090ad2e6b792bb3653e83d7 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 2 Feb 2024 10:43:37 -0500 Subject: [PATCH 12/47] add action items --- src/builder_state.rs | 135 +++++++++++++++++++++++++++++++++----- src/testing/basic_test.rs | 7 +- 2 files changed, 122 insertions(+), 20 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 2109dbf3..61d165ce 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -36,7 +36,7 @@ use std::{ use futures::Stream; use std::time::{SystemTime, UNIX_EPOCH}; -use async_broadcast::{broadcast, TryRecvError, Sender as BroadcastSender, Receiver as BroadcastReceiver}; +use async_broadcast::{broadcast, TryRecvError, Sender as BroadcastSender, Receiver as BroadcastReceiver, RecvError}; // including the following from the hotshot use hotshot_types::{ @@ -154,10 +154,13 @@ pub trait BuilderProgress { async fn process_decide_event(&mut self, decide_msg: DecideMessage); /// spawn a clone of builder - async fn spawn_clone(self, da_proposal: DAProposal, quorum_proposal: QuorumProposal); + async fn spawn_clone(self, da_proposal: DAProposal, quorum_proposal: QuorumProposal, leader: TYPES::SignatureKey); /// build a block async fn build_block(&mut self, matching_vid: VidCommitment) -> Option>; + + /// Event Loop + async fn event_loop(mut self); } @@ -228,12 +231,8 @@ impl BuilderProgress for BuilderState{ let encoded_txns = da_proposal_data.encoded_transactions; let metadata: <::BlockPayload as BlockPayload>::Metadata = da_proposal_data.metadata; - - // get the block payload from the encoded_txns; the following are not used currently, however might need later - // let block_payload_txns = TestBlockPayload::from_bytes(encoded_txns.clone().into_iter(), &()).transactions; - // let encoded_txns_hash = Sha256::digest(&encoded_txns); - // generate the vid commitment + // generate the vid commitment; num nodes are received through hotshot api in service.rs and passed along with message onto channel let total_nodes = da_msg.total_nodes; let payload_vid_commitment = vid_commitment(&encoded_txns, total_nodes); @@ -247,7 +246,7 @@ impl BuilderProgress for BuilderState{ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(qc_proposal_data) = self.quorum_proposal_payload_commit_to_quorum_proposal.entry(payload_vid_commitment.clone()) { let qc_proposal_data = qc_proposal_data.remove(); - self.clone().spawn_clone(da_proposal_data, qc_proposal_data); + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender); } else { self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data); } @@ -278,7 +277,7 @@ impl BuilderProgress for BuilderState{ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(da_proposal_data) = self.da_proposal_payload_commit_to_da_proposal.entry(payload_vid_commitment.clone()) { let da_proposal_data = da_proposal_data.remove(); - self.clone().spawn_clone(da_proposal_data, qc_proposal_data); + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender); } else { self.quorum_proposal_payload_commit_to_quorum_proposal.insert(payload_vid_commitment, qc_proposal_data.clone()); } @@ -333,15 +332,37 @@ impl BuilderProgress for BuilderState{ } // spawn a clone of the builder state - async fn spawn_clone(self, da_proposal: DAProposal, quorum_proposal: QuorumProposal) + async fn spawn_clone(mut self, da_proposal: DAProposal, quorum_proposal: QuorumProposal, leader: TYPES::SignatureKey) { - // spawn a clone of the builder - // let mut cloned_builder = self.clone(); - // // spawn a new task to build a block off the matching da and quorum proposals - // let cloned_builder_handle = task::spawn(async move { - // //cloned_builder.build_block(da_proposal, quorum_proposal).await; - // }); - print!("Spawned a new task to build a block off the matching da and quorum proposals"); + self.built_from_view_vid_leaf.0 = quorum_proposal.view_number; + self.built_from_view_vid_leaf.1 = quorum_proposal.block_header.payload_commitment(); + + let leaf: Leaf<_> = Leaf { + view_number: quorum_proposal.view_number, + justify_qc: quorum_proposal.justify_qc.clone(), + parent_commitment: quorum_proposal.justify_qc.get_data().leaf_commit, + block_header: quorum_proposal.block_header.clone(), + block_payload: None, + rejected: vec![], + proposer_id: leader, + }; + self.built_from_view_vid_leaf.2 = leaf.commit(); + + // let block_payload_txns = TestBlockPayload::from_bytes(encoded_txns.clone().into_iter(), &()).transactions; + // let encoded_txns_hash = Sha256::digest(&encoded_txns); + let payload = ::from_bytes( + da_proposal.encoded_transactions.clone().into_iter(), + quorum_proposal.block_header.metadata(), + ); + + payload.transaction_commitments(quorum_proposal.block_header.metadata()).iter().for_each(|txn| + if let Entry::Occupied(txn_info) = self.tx_hash_to_available_txns.entry(*txn) { + self.timestamp_to_tx.remove(&txn_info.get().0); + self.included_txns.insert(*txn); + txn_info.remove_entry(); + }); + + self.event_loop(); } // build a block @@ -386,8 +407,86 @@ impl BuilderProgress for BuilderState{ } None } -} + async fn event_loop(mut self) { + task::spawn( + loop{ + //let builder_state = builder_state.lock().unwrap(); + while let Ok(req) = self.req_receiver.recv().await { + if let MessageType::RequestMessage(req) = req { + + let requested_vid_commitment = req.requested_vid_commitment; + + } + // //... handle requests + //selft says do I have a block for this set of txns? if so, return that header?? MPSC [async_compatility] + // // else iterate through and call build block, and add block to blockmap in globalstate + // // do validity check for the requester as well i.e are they leader for one of the next k views + + } + + let (received_msg, channel_index, _)= select_all([self.tx_receiver.recv(), self.decide_receiver.recv(), self.da_proposal_receiver.recv(), + self.qc_receiver.recv(), self.req_receiver.recv()]).await; + + match received_msg { + Ok(received_msg) => { + match received_msg { + + // request message + MessageType::RequestMessage(req) => { + println!("Received request msg in builder {}: {:?} from index {}", self.builder_id.0, req, channel_index); + // store in the rtx_msgs + //rreq_msgs.push(req.clone()); + //builder_state.process_request(req).await; + } + + // transaction message + MessageType::TransactionMessage(rtx_msg) => { + println!("Received tx msg in builder {}: {:?} from index {}", self.builder_id.0, rtx_msg, channel_index); + + // get the content from the rtx_msg's inside vec + // Pass the tx msg to the handler + if rtx_msg.tx_type == TransactionSource::HotShot { + self.process_hotshot_transaction(rtx_msg.tx).await; + } else { + self.process_external_transaction(rtx_msg.tx).await; + } + + } + + // decide message + MessageType::DecideMessage(rdecide_msg) => { + println!("Received decide msg in builder {}: {:?} from index {}", self.builder_id.0, rdecide_msg, channel_index); + // store in the rdecide_msgs + self.process_decide_event(rdecide_msg).await; + } + + // DA proposal message + MessageType::DAProposalMessage(rda_msg) => { + println!("Received da proposal msg in builder {}: {:?} from index {}", self.builder_id.0, rda_msg, channel_index); + + self.process_da_proposal(rda_msg).await; + } + // QC proposal message + MessageType::QCMessage(rqc_msg) => { + println!("Received qc msg in builder {}: {:?} from index {}", self.builder_id.0, rqc_msg, channel_index); + self.process_quorum_proposal(rqc_msg).await; + } + } + } + Err(err) => { + if err == RecvError::Closed { + println!("The channel {} is closed", channel_index); + //break; + //channel_close_index.insert(channel_index); + } + } + } + + } + ); + } +} /// Unifies the possible messages that can be received by the builder #[derive(Debug, Clone)] pub enum MessageType{ diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 2173cfab..91242a8d 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -177,6 +177,8 @@ mod tests { let sda_msgs: Vec> = sda_msgs.clone(); let sqc_msgs: Vec> = sqc_msgs.clone(); + let mut builder_state = Arc::new(Mutex::new(BuilderState::::new((pub_key, private_key), built_from_view_vid_leaf, tx_receiver_clone, decide_receiver_clone, da_receiver_clone, qc_receiver_clone, req_receiver_clone))); + // TODO clone a handle and check it contains the remaining messages and don't contain the messages before cloning it let handle = task::spawn(async move { @@ -184,8 +186,7 @@ mod tests { let (pub_key, private_key) = BLSPubKey::generated_from_seed_indexed([i as u8; 32],i as u64); - //let mut builder_state = Arc::new(Mutex::new(BuilderState::::new((pub_key, private_key), built_from_view_vid_leaf, tx_receiver_clone, decide_receiver_clone, da_receiver_clone, qc_receiver_clone,req_receiver_clone))); - let mut builder_state = BuilderState::::new((pub_key, private_key), built_from_view_vid_leaf, + let mut builder_state = BuilderState::::new((pub_key, private_key), built_from_view_vid_leaf, tx_receiver_clone, decide_receiver_clone, da_receiver_clone, qc_receiver_clone, req_receiver_clone); @@ -197,8 +198,10 @@ mod tests { let mut channel_close_index = HashSet::::new(); //let shared_builder_state = Arc::clone(&builder_state); + loop{ + //let builder_state = builder_state.lock().unwrap(); while let Ok(req) = builder_state.req_receiver.recv().await { println!("Received request in builder {}: {:?}", i, req); if let MessageType::RequestMessage(req) = req { From 40e209640d098ae11bab3f7509208a2969e36837 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 2 Feb 2024 11:00:02 -0500 Subject: [PATCH 13/47] fix select_all --- src/builder_state.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 61d165ce..997c8ba4 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -10,7 +10,6 @@ use std::hash::BuildHasher; use std::marker::PhantomData; use std::sync::{Arc, Mutex}; use bincode::de; -use futures::stream::select_all; use futures::{Future, select}; use async_std::task::{self, Builder}; use async_trait::async_trait; @@ -49,6 +48,7 @@ use hotshot_types::{ use commit::{Commitment, Committable}; use jf_primitives::signatures::bls_over_bn254::{BLSOverBN254CurveSignatureScheme, KeyPair, SignKey, VerKey}; +use futures::future::select_all; pub type TxTimeStamp = u128; const NUM_NODES_IN_VID_COMPUTATION: usize = 8; @@ -409,7 +409,7 @@ impl BuilderProgress for BuilderState{ } async fn event_loop(mut self) { - task::spawn( + task::spawn(async move{ loop{ //let builder_state = builder_state.lock().unwrap(); while let Ok(req) = self.req_receiver.recv().await { @@ -484,7 +484,7 @@ impl BuilderProgress for BuilderState{ } } - ); + }); } } /// Unifies the possible messages that can be received by the builder From f1eee6d3df7c91609aa2e387bd21a40026a776ce Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 5 Feb 2024 12:30:13 -0500 Subject: [PATCH 14/47] some minor fixes --- src/builder_state.rs | 171 ++++++++++++++++++++++++------------------- src/data_source.rs | 2 +- src/service.rs | 15 +++- 3 files changed, 108 insertions(+), 80 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 997c8ba4..b4a0370e 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -43,7 +43,8 @@ use hotshot_types::{ data::{DAProposal, Leaf, QuorumProposal, VidCommitment}, simple_certificate::QuorumCertificate, message::Proposal, - traits::{block_contents::{BlockPayload, BlockHeader, Transaction}, state::ConsensusTime, signature_key::SignatureKey}, + traits::{block_contents::{BlockPayload, BlockHeader, Transaction}, signature_key::SignatureKey}, + utils::BuilderCommitment }; use commit::{Commitment, Committable}; @@ -87,10 +88,23 @@ pub struct RequestMessage{ pub requested_vid_commitment: VidCommitment, } +#[derive(Clone, Debug, PartialEq)] +pub struct ResponseMessage{ + pub block_hash: BuilderCommitment, //TODO: Need to pull out from hotshot + pub block_size: u64, + pub offered_fee: u64, +} + +pub enum Status { + ShouldExit, + ShouldContinue, +} use std::cmp::{PartialEq, Ord, PartialOrd}; use std::hash::Hash; +use crate::service::GlobalState; + #[derive(Debug, Clone)] pub struct BuilderState{ @@ -134,6 +148,9 @@ pub struct BuilderState{ // channel receiver for the requests pub req_receiver: BroadcastReceiver>, + + // global state handle + pub global_state: Arc::>>, } /// Trait to hold the helper functions for the builder #[async_trait] @@ -246,7 +263,7 @@ impl BuilderProgress for BuilderState{ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(qc_proposal_data) = self.quorum_proposal_payload_commit_to_quorum_proposal.entry(payload_vid_commitment.clone()) { let qc_proposal_data = qc_proposal_data.remove(); - self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender); + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; } else { self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data); } @@ -277,7 +294,7 @@ impl BuilderProgress for BuilderState{ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(da_proposal_data) = self.da_proposal_payload_commit_to_da_proposal.entry(payload_vid_commitment.clone()) { let da_proposal_data = da_proposal_data.remove(); - self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender); + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; } else { self.quorum_proposal_payload_commit_to_quorum_proposal.insert(payload_vid_commitment, qc_proposal_data.clone()); } @@ -286,49 +303,54 @@ impl BuilderProgress for BuilderState{ } /// processing the decide event - async fn process_decide_event(&mut self, decide_msg: DecideMessage) + async fn process_decide_event(&mut self, decide_msg: DecideMessage) -> Option { + let leaf_chain = decide_msg.leaf_chain; let qc = decide_msg.qc; let block_size = decide_msg.block_size; - // get the most recent decide parent commitment as the first entry in the leaf_chain(sorted by descreasing view number) - // let latest_decide_parent_commitment = leaf_chain[0].parent_commitment; - // now we use this decide_parent_commitment to build blocks off - - - // do local pruning based on decide event data - // iterate over all the decide leaves and extract out the transactions contained inside it - // for each transaction, check if it exists in the local tx pool, if yes, then remove it from the local tx pool - for leaf in leaf_chain.iter() { - // get the block payload - // constrain its type to be of type TestBlockPayload - let block_payload = leaf.get_block_payload(); - match block_payload{ - Some(block_payload) => { - println!("Block payload in decide event {:?}", block_payload); - let metadata = leaf.get_block_header().metadata(); - let transactions_commitments = block_payload.transaction_commitments(&metadata); - // iterate over the transactions and remove them from tx_hash_to_tx and timestamp_to_tx - //let transactions:Vec = vec![]; - for tx_hash in transactions_commitments.iter() { - // remove the transaction from the timestamp_to_tx map - if let Some((timestamp, _, _)) = self.tx_hash_to_available_txns.get(&tx_hash) { - if self.timestamp_to_tx.contains_key(timestamp) { - self.timestamp_to_tx.remove(timestamp); - } - self.tx_hash_to_available_txns.remove(&tx_hash); + + let latest_decide_parent_commitment = leaf_chain[0].parent_commitment; + + let latest_decide_commitment = leaf_chain[0].commit(); + + let leaf_view_number = leaf_chain[0].view_number; + + if self.built_from_view_vid_leaf.0 <= leaf_view_number{ + println!("The decide event is not for the next view, so ignoring it"); + return Some(Status::ShouldExit); + } + + let block_payload = leaf_chain[0].get_block_payload(); + match block_payload{ + Some(block_payload) => { + println!("Block payload in decide event {:?}", block_payload); + let metadata = leaf_chain[0].get_block_header().metadata(); + let transactions_commitments = block_payload.transaction_commitments(&metadata); + // iterate over the transactions and remove them from tx_hash_to_tx and timestamp_to_tx + //let transactions:Vec = vec![]; + for tx_hash in transactions_commitments.iter() { + // remove the transaction from the timestamp_to_tx map + if let Some((timestamp, _, _)) = self.tx_hash_to_available_txns.get(&tx_hash) { + if self.timestamp_to_tx.contains_key(timestamp) { + self.timestamp_to_tx.remove(timestamp); } - - // remove from the included_txns set also - self.included_txns.remove(&tx_hash); + self.tx_hash_to_available_txns.remove(&tx_hash); } - }, - None => { - println!("Block payload is none"); + + // maybe in the future, remove from the included_txns set also + // self.included_txns.remove(&tx_hash); } + }, + None => { + println!("Block payload is none"); } } + + self.global_state.lock().remove_handles(self.built_from_view_vid_leaf.1, self.block_hashes).await; + + return Some(Status::ShouldContinue); } // spawn a clone of the builder state @@ -343,7 +365,6 @@ impl BuilderProgress for BuilderState{ parent_commitment: quorum_proposal.justify_qc.get_data().leaf_commit, block_header: quorum_proposal.block_header.clone(), block_payload: None, - rejected: vec![], proposer_id: leader, }; self.built_from_view_vid_leaf.2 = leaf.commit(); @@ -362,49 +383,41 @@ impl BuilderProgress for BuilderState{ txn_info.remove_entry(); }); - self.event_loop(); + self.event_loop().await; } // build a block - async fn build_block(&mut self, matching_vid: VidCommitment) -> Option>{ - let mut block_txns:Vec = vec![]; - - // if we have a matching da for the current da proposal, then we can build a block off it - if self.quorum_proposal_payload_commit_to_quorum_proposal.contains_key(&matching_vid) && self.da_proposal_payload_commit_to_da_proposal.contains_key(&matching_vid){ - // can spawn or call a function to build a block off it - // get the current system time - let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos(); - // start making off a block using the txns from the local pool - // iterate over the timestamp_to_tx map and get the txns with lowest timestamp first - let mut to_remove_timestamps:Vec = vec![]; - let mut to_remove_tx_hashes:Vec> = vec![]; - - for (timestamp, tx_hash) in self.timestamp_to_tx.iter() { - // get the transaction from the tx_hash_to_tx map - if let Some((_, tx, _)) = self.tx_hash_to_available_txns.get(tx_hash){ - // add the transaction to the block_txns if it not already included - if !self.included_txns.contains(tx_hash) { - // include into the current building block - block_txns.push(tx.clone()); - // include in the included tx set - self.included_txns.insert(tx_hash.clone()); - - } - to_remove_tx_hashes.push(*tx_hash); - } - to_remove_timestamps.push(*timestamp); - } - - // iterate over the to_remove_tx_hashes and remove them from the tx_hash_to_available_txns map - for tx_hash in to_remove_tx_hashes.iter() { - self.tx_hash_to_available_txns.remove(tx_hash); - } - // iterate over the to_remove_timestamps and remove them from the timestamp_to_tx map - for timestamp in to_remove_timestamps.iter() { - self.timestamp_to_tx.remove(timestamp); - } - return Some(block_txns); + async fn build_block(&mut self, matching_vid: VidCommitment) -> Option{ + + if let Ok((payload, metadata)) = ::from_transactions( + self.timestamp_to_tx.iter().filter_map(|(ts, tx_hash)| { + self.tx_hash_to_available_txns.get(tx_hash).map(|(ts, tx, source)| { + tx.clone() + }) + })) { + + let block_hash = payload.builder_hash(&metadata); + let block_size = payload.size(&metadata); // TODO: figure out + let offered_fee = 0; + + + + let join_handle = task::spawn(async move |block_hash, payload, metadata| { + // TODO: Disperse Operation: May be talk to @Gus about it // https://github.com/EspressoSystems/HotShot/blob/main/crates/task-impls/src/vid.rs#L97-L98 + // calculate vid shares + let vid = VidScheme::new(chunk_size, num_quorum_committee, &srs).unwrap(); + vid.disperse(encoded_transactions.clone()).unwrap(); + + + + }); + + + self.service_handle.global_state.block_map.insert(block_hash, (payload, metadata, join_handle)); + + return ResponseMessage(block_hash, block_size, offered_fee); } + None } @@ -417,6 +430,9 @@ impl BuilderProgress for BuilderState{ let requested_vid_commitment = req.requested_vid_commitment; + if requested_vid_commitment == self.built_from_view_vid_leaf.1{ + self.build_block(requested_vid_commitment).await; + } } // //... handle requests //selft says do I have a block for this set of txns? if so, return that header?? MPSC [async_compatility] @@ -498,7 +514,7 @@ pub enum MessageType{ } impl BuilderState{ - pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>)-> Self{ + pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>, global_state: Arc>>)-> Self{ BuilderState{ builder_id: builder_id, timestamp_to_tx: BTreeMap::new(), @@ -513,6 +529,7 @@ impl BuilderState{ req_receiver: req_receiver, da_proposal_payload_commit_to_da_proposal: HashMap::new(), quorum_proposal_payload_commit_to_quorum_proposal: HashMap::new(), + global_state: global_state, } } diff --git a/src/data_source.rs b/src/data_source.rs index 932721e6..f036eb3d 100644 --- a/src/data_source.rs +++ b/src/data_source.rs @@ -37,7 +37,7 @@ use hotshot_types::{ event::EventType, message::{MessageKind, SequencingMessage}, traits::{ - election::Membership, node_implementation::NodeType, state::ConsensusTime, storage::Storage, + election::Membership, node_implementation::NodeType, storage::Storage, }, }; use hotshot_types::{data::Leaf, simple_certificate::QuorumCertificate}; diff --git a/src/service.rs b/src/service.rs index 4bbf9e92..37ae6a42 100644 --- a/src/service.rs +++ b/src/service.rs @@ -39,7 +39,7 @@ use hotshot_types::{ event::{EventType, Event}, message::{MessageKind, SequencingMessage}, traits::{ - election::Membership, node_implementation::NodeType as BuilderType, state::ConsensusTime, storage::Storage, + election::Membership, node_implementation::NodeType as BuilderType, storage::Storage, signature_key::SignatureKey,block_contents::BlockHeader, consensus_api::ConsensusApi }, }; @@ -65,6 +65,15 @@ pub struct GlobalState{ pub vid_to_potential_builder_state: HashMap>, } +impl GlobalState{ + pub fn removed_handles(&mut self, vidcommitment: VidCommitment, block_hashes: Vec) { + self.vid_to_potential_builder_state.remove(&vidcommitment); + for block_hash in block_hashes { + self.block_hash_to_block.remove(&block_hash); + } + } +} +// impl api // from the hs-builder-api/src/ /// Run an instance of the default Espresso builder service. pub async fn run_standalone_builder_service, D>( options: Options, @@ -73,7 +82,9 @@ pub async fn run_standalone_builder_service>, decide_sender: BroadcastSender>, da_sender: BroadcastSender>, - qc_sender: BroadcastSender> + qc_sender: BroadcastSender>, + req_sender: BroadcastSender>, + response_receiver: BroadcastReceiver>, ) -> Result<(),()> //where //TODO From 50459f21a8ce452cee788eec33a585493f1bf235 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 5 Feb 2024 14:15:05 -0500 Subject: [PATCH 15/47] add event details --- src/builder_state.rs | 124 +++++++++++++++++++++++++++++-------------- src/service.rs | 12 +++-- 2 files changed, 90 insertions(+), 46 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index b4a0370e..a2874e4c 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -16,7 +16,7 @@ use async_trait::async_trait; //use async_compatibility_layer::channel::{unbounded, UnboundedSender, UnboundedStream, UnboundedReceiver}; use async_lock::RwLock; use hotshot_task_impls::transactions; -use hotshot_types::traits::block_contents::vid_commitment; +use hotshot_types::traits::block_contents::{vid_commitment, TestableBlock}; use hotshot_types::vote::Certificate; use sha2::{Digest, Sha256}; @@ -40,7 +40,7 @@ use async_broadcast::{broadcast, TryRecvError, Sender as BroadcastSender, Receiv // including the following from the hotshot use hotshot_types::{ traits::node_implementation::NodeType as BuilderType, - data::{DAProposal, Leaf, QuorumProposal, VidCommitment}, + data::{DAProposal, Leaf, QuorumProposal, VidCommitment, VidScheme, VidSchemeTrait, test_srs}, simple_certificate::QuorumCertificate, message::Proposal, traits::{block_contents::{BlockPayload, BlockHeader, Transaction}, signature_key::SignatureKey}, @@ -86,6 +86,7 @@ pub struct QCMessage{ #[derive(Clone, Debug, PartialEq)] pub struct RequestMessage{ pub requested_vid_commitment: VidCommitment, + pub total_nodes: usize } #[derive(Clone, Debug, PartialEq)] @@ -151,6 +152,9 @@ pub struct BuilderState{ // global state handle pub global_state: Arc::>>, + + // response sender + pub response_sender: BroadcastSender, } /// Trait to hold the helper functions for the builder #[async_trait] @@ -168,13 +172,13 @@ pub trait BuilderProgress { async fn process_quorum_proposal(&mut self, qc_msg: QCMessage); /// process the decide event - async fn process_decide_event(&mut self, decide_msg: DecideMessage); + async fn process_decide_event(&mut self, decide_msg: DecideMessage) -> Option; /// spawn a clone of builder async fn spawn_clone(self, da_proposal: DAProposal, quorum_proposal: QuorumProposal, leader: TYPES::SignatureKey); /// build a block - async fn build_block(&mut self, matching_vid: VidCommitment) -> Option>; + async fn build_block(&mut self, matching_vid: VidCommitment, num_quorum_committee: usize) -> Option; /// Event Loop async fn event_loop(mut self); @@ -322,33 +326,39 @@ impl BuilderProgress for BuilderState{ return Some(Status::ShouldExit); } - let block_payload = leaf_chain[0].get_block_payload(); - match block_payload{ - Some(block_payload) => { - println!("Block payload in decide event {:?}", block_payload); - let metadata = leaf_chain[0].get_block_header().metadata(); - let transactions_commitments = block_payload.transaction_commitments(&metadata); - // iterate over the transactions and remove them from tx_hash_to_tx and timestamp_to_tx - //let transactions:Vec = vec![]; - for tx_hash in transactions_commitments.iter() { - // remove the transaction from the timestamp_to_tx map - if let Some((timestamp, _, _)) = self.tx_hash_to_available_txns.get(&tx_hash) { - if self.timestamp_to_tx.contains_key(timestamp) { - self.timestamp_to_tx.remove(timestamp); + // go through all the leafs + for leaf in leaf_chain.iter(){ + let block_payload = leaf.get_block_payload(); + match block_payload{ + Some(block_payload) => { + println!("Block payload in decide event {:?}", block_payload); + let metadata = leaf_chain[0].get_block_header().metadata(); + let transactions_commitments = block_payload.transaction_commitments(&metadata); + // iterate over the transactions and remove them from tx_hash_to_tx and timestamp_to_tx + //let transactions:Vec = vec![]; + for tx_hash in transactions_commitments.iter() { + // remove the transaction from the timestamp_to_tx map + if let Some((timestamp, _, _)) = self.tx_hash_to_available_txns.get(&tx_hash) { + if self.timestamp_to_tx.contains_key(timestamp) { + self.timestamp_to_tx.remove(timestamp); + } + self.tx_hash_to_available_txns.remove(&tx_hash); } - self.tx_hash_to_available_txns.remove(&tx_hash); + + // maybe in the future, remove from the included_txns set also + // self.included_txns.remove(&tx_hash); } - - // maybe in the future, remove from the included_txns set also - // self.included_txns.remove(&tx_hash); + }, + None => { + println!("Block payload is none"); } - }, - None => { - println!("Block payload is none"); } } + // convert leaf commitments into buildercommiments + let leaf_commitments:Vec = leaf_chain.iter().map(|leaf| leaf.get_block_payload().unwrap().builder_commitment(&leaf.get_block_header().metadata())).collect(); - self.global_state.lock().remove_handles(self.built_from_view_vid_leaf.1, self.block_hashes).await; + self.global_state.write_arc().await.remove_handles(self.built_from_view_vid_leaf.1, leaf_commitments); + // can use get_mut() also return Some(Status::ShouldContinue); } @@ -387,7 +397,7 @@ impl BuilderProgress for BuilderState{ } // build a block - async fn build_block(&mut self, matching_vid: VidCommitment) -> Option{ + async fn build_block(&mut self, matching_vid: VidCommitment, num_quorum_committee: usize) -> Option{ if let Ok((payload, metadata)) = ::from_transactions( self.timestamp_to_tx.iter().filter_map(|(ts, tx_hash)| { @@ -396,27 +406,49 @@ impl BuilderProgress for BuilderState{ }) })) { - let block_hash = payload.builder_hash(&metadata); - let block_size = payload.size(&metadata); // TODO: figure out - let offered_fee = 0; + let block_hash = payload.builder_commitment(&metadata); + + //let num_txns = ::txn_count(&payload);// TODO: figure out + let encoded_txns:Vec = payload.encode().unwrap().into_iter().collect(); + + + let block_size = encoded_txns.len() as u64; + let offered_fee = 0; - let join_handle = task::spawn(async move |block_hash, payload, metadata| { + // get the number of quorum committee members to be used for VID calculation + //let num_quorum_committee = self.membership.total_nodes(); + + // TODO + let srs = test_srs(num_quorum_committee); + + // calculate the last power of two + // TODO change after https://github.com/EspressoSystems/jellyfish/issues/339 + // issue: https://github.com/EspressoSystems/HotShot/issues/2152 + let chunk_size = 1 << num_quorum_committee.ilog2(); + + let join_handle = task::spawn(async move{ // TODO: Disperse Operation: May be talk to @Gus about it // https://github.com/EspressoSystems/HotShot/blob/main/crates/task-impls/src/vid.rs#L97-L98 // calculate vid shares let vid = VidScheme::new(chunk_size, num_quorum_committee, &srs).unwrap(); - vid.disperse(encoded_transactions.clone()).unwrap(); - - - + vid.disperse(encoded_txns).unwrap(); }); + + // // calculate vid shares + // let vid_disperse = spawn_blocking(move || { + // let vid = VidScheme::new(chunk_size, num_quorum_committee, &srs).unwrap(); + // vid.disperse(encoded_transactions.clone()).unwrap() + // }) + // .await; + - self.service_handle.global_state.block_map.insert(block_hash, (payload, metadata, join_handle)); - - return ResponseMessage(block_hash, block_size, offered_fee); - } + //self.global_state.write().block_hash_to_block.insert(block_hash, (payload, metadata, join_handle)); + //let mut global_state = self.global_state.write().unwrap(); + self.global_state.write_arc().await.block_hash_to_block.insert(block_hash, payload); + return Some(ResponseMessage{block_hash: block_hash, block_size: block_size, offered_fee: offered_fee}); + }; None } @@ -429,9 +461,18 @@ impl BuilderProgress for BuilderState{ if let MessageType::RequestMessage(req) = req { let requested_vid_commitment = req.requested_vid_commitment; - + let vid_nodes = req.total_nodes; if requested_vid_commitment == self.built_from_view_vid_leaf.1{ - self.build_block(requested_vid_commitment).await; + let response = self.build_block(requested_vid_commitment, vid_nodes).await; + match response{ + Some(response)=>{ + // send the response back + self.response_sender.broadcast(response).await.unwrap(); + } + None => { + println!("No response to send"); + } + } } } // //... handle requests @@ -514,7 +555,7 @@ pub enum MessageType{ } impl BuilderState{ - pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>, global_state: Arc>>)-> Self{ + pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>, global_state: Arc>>, response_sender: BroadcastSender)-> Self{ BuilderState{ builder_id: builder_id, timestamp_to_tx: BTreeMap::new(), @@ -530,6 +571,7 @@ impl BuilderState{ da_proposal_payload_commit_to_da_proposal: HashMap::new(), quorum_proposal_payload_commit_to_quorum_proposal: HashMap::new(), global_state: global_state, + response_sender: response_sender, } } diff --git a/src/service.rs b/src/service.rs index 37ae6a42..b611fce9 100644 --- a/src/service.rs +++ b/src/service.rs @@ -42,6 +42,7 @@ use hotshot_types::{ election::Membership, node_implementation::NodeType as BuilderType, storage::Storage, signature_key::SignatureKey,block_contents::BlockHeader, consensus_api::ConsensusApi }, + utils::BuilderCommitment }; use hotshot_types::{data::Leaf, simple_certificate::QuorumCertificate}; use std::{collections::HashMap, sync::Arc}; @@ -50,7 +51,7 @@ use tracing::error; //use crate::builder_state::{MessageType, BuilderType, TransactionMessage, DecideMessage, QuorumProposalMessage, QCMessage}; use async_broadcast::{broadcast, Sender as BroadcastSender, Receiver as BroadcastReceiver}; use futures::future::ready; -use crate::builder_state::{BuilderState, MessageType}; +use crate::builder_state::{BuilderState, MessageType, ResponseMessage}; use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage}; use sha2::{Digest, Sha256}; @@ -60,13 +61,14 @@ pub struct Options { pub port: u16 } // +#[derive(Clone, Debug)] pub struct GlobalState{ - pub block_hash_to_block: HashMap, + pub block_hash_to_block: HashMap, pub vid_to_potential_builder_state: HashMap>, } -impl GlobalState{ - pub fn removed_handles(&mut self, vidcommitment: VidCommitment, block_hashes: Vec) { +impl GlobalState{ + pub fn remove_handles(&mut self, vidcommitment: VidCommitment, block_hashes: Vec) { self.vid_to_potential_builder_state.remove(&vidcommitment); for block_hash in block_hashes { self.block_hash_to_block.remove(&block_hash); @@ -84,7 +86,7 @@ pub async fn run_standalone_builder_service>, qc_sender: BroadcastSender>, req_sender: BroadcastSender>, - response_receiver: BroadcastReceiver>, + response_receiver: BroadcastReceiver, ) -> Result<(),()> //where //TODO From 4ca80bc2b396e5eb409b69f6fb3e95031286705a Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 5 Feb 2024 15:08:17 -0500 Subject: [PATCH 16/47] impl builderdatasource --- Cargo.toml | 4 +++- src/service.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 96230f3b..610dbfd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,4 +44,6 @@ atomic_store = { git = "https://github.com/EspressoSystems/atomicstore.git", tag unix-time = "0.1.5" async-broadcast = "0.6.0" sha2 = "0.10" -jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish" } \ No newline at end of file +jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish" } + +builder-api = {git = "https://github.com/EspressoSystems/hs-builder-api", branch="main"} \ No newline at end of file diff --git a/src/service.rs b/src/service.rs index b611fce9..afe4cdd1 100644 --- a/src/service.rs +++ b/src/service.rs @@ -54,6 +54,9 @@ use futures::future::ready; use crate::builder_state::{BuilderState, MessageType, ResponseMessage}; use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage}; + +use builder_api::data_source::BuilderDataSource; + use sha2::{Digest, Sha256}; #[derive(clap::Args, Default)] pub struct Options { @@ -65,6 +68,7 @@ pub struct Options { pub struct GlobalState{ pub block_hash_to_block: HashMap, pub vid_to_potential_builder_state: HashMap>, + pub request_sender: BroadcastSender>, } impl GlobalState{ @@ -75,6 +79,27 @@ impl GlobalState{ } } } + +impl BuilderDataSourc for GlobalState +{ + async fn get_available_blocks( + &self, + for_parent: &VidCommitment, + ) -> Result>, BuildError> { + unimplemented!() + } + async fn claim_block( + &self, + block_hash: &BuilderCommitment, + signature: &<::SignatureKey as SignatureKey>::PureAssembledSignatureType, + ) -> Result { + unimplemented!() + } + async fn submit_txn(&self, txn: ::Transaction) -> Result<(), BuildError> { + unimplemented!() + } +} + // impl api // from the hs-builder-api/src/ /// Run an instance of the default Espresso builder service. pub async fn run_standalone_builder_service, D>( @@ -187,3 +212,4 @@ pub async fn run_standalone_builder_service Date: Mon, 5 Feb 2024 15:58:59 -0500 Subject: [PATCH 17/47] fix quorum membership --- Cargo.toml | 2 +- src/builder_state.rs | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 610dbfd5..2babcda1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,4 +46,4 @@ async-broadcast = "0.6.0" sha2 = "0.10" jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish" } -builder-api = {git = "https://github.com/EspressoSystems/hs-builder-api", branch="main"} \ No newline at end of file +hs-builder-api = {git = "https://github.com/EspressoSystems/hs-builder-api", branch="main"} \ No newline at end of file diff --git a/src/builder_state.rs b/src/builder_state.rs index a2874e4c..585d3dd5 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -86,7 +86,7 @@ pub struct QCMessage{ #[derive(Clone, Debug, PartialEq)] pub struct RequestMessage{ pub requested_vid_commitment: VidCommitment, - pub total_nodes: usize + //pub total_nodes: usize } #[derive(Clone, Debug, PartialEq)] @@ -155,6 +155,9 @@ pub struct BuilderState{ // response sender pub response_sender: BroadcastSender, + + // quorum membership + pub quorum_membership: Arc, } /// Trait to hold the helper functions for the builder #[async_trait] @@ -178,7 +181,7 @@ pub trait BuilderProgress { async fn spawn_clone(self, da_proposal: DAProposal, quorum_proposal: QuorumProposal, leader: TYPES::SignatureKey); /// build a block - async fn build_block(&mut self, matching_vid: VidCommitment, num_quorum_committee: usize) -> Option; + async fn build_block(&mut self, matching_vid: VidCommitment) -> Option; /// Event Loop async fn event_loop(mut self); @@ -397,7 +400,7 @@ impl BuilderProgress for BuilderState{ } // build a block - async fn build_block(&mut self, matching_vid: VidCommitment, num_quorum_committee: usize) -> Option{ + async fn build_block(&mut self, matching_vid: VidCommitment) -> Option{ if let Ok((payload, metadata)) = ::from_transactions( self.timestamp_to_tx.iter().filter_map(|(ts, tx_hash)| { @@ -418,7 +421,7 @@ impl BuilderProgress for BuilderState{ // get the number of quorum committee members to be used for VID calculation - //let num_quorum_committee = self.membership.total_nodes(); + let num_quorum_committee = self.quorum_membership.total_nodes(); // TODO let srs = test_srs(num_quorum_committee); @@ -461,9 +464,9 @@ impl BuilderProgress for BuilderState{ if let MessageType::RequestMessage(req) = req { let requested_vid_commitment = req.requested_vid_commitment; - let vid_nodes = req.total_nodes; + //let vid_nodes = req.total_nodes; if requested_vid_commitment == self.built_from_view_vid_leaf.1{ - let response = self.build_block(requested_vid_commitment, vid_nodes).await; + let response = self.build_block(requested_vid_commitment).await; match response{ Some(response)=>{ // send the response back @@ -555,7 +558,7 @@ pub enum MessageType{ } impl BuilderState{ - pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>, global_state: Arc>>, response_sender: BroadcastSender)-> Self{ + pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>, global_state: Arc>>, response_sender: BroadcastSender, quorum_membership: TYPES::Membership)-> Self{ BuilderState{ builder_id: builder_id, timestamp_to_tx: BTreeMap::new(), @@ -572,6 +575,7 @@ impl BuilderState{ quorum_proposal_payload_commit_to_quorum_proposal: HashMap::new(), global_state: global_state, response_sender: response_sender, + quorum_membership: quorum_membership, } } From e922f1ff70494529a5301c06318fe704913f5f4a Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 5 Feb 2024 16:30:21 -0500 Subject: [PATCH 18/47] implement api --- src/builder_state.rs | 1 - src/service.rs | 25 ++++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 585d3dd5..874aad70 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -554,7 +554,6 @@ pub enum MessageType{ DecideMessage(DecideMessage), DAProposalMessage(DAProposalMessage), QCMessage(QCMessage), - RequestMessage(RequestMessage), } impl BuilderState{ diff --git a/src/service.rs b/src/service.rs index afe4cdd1..b692a0ef 100644 --- a/src/service.rs +++ b/src/service.rs @@ -51,11 +51,11 @@ use tracing::error; //use crate::builder_state::{MessageType, BuilderType, TransactionMessage, DecideMessage, QuorumProposalMessage, QCMessage}; use async_broadcast::{broadcast, Sender as BroadcastSender, Receiver as BroadcastReceiver}; use futures::future::ready; -use crate::builder_state::{BuilderState, MessageType, ResponseMessage}; +use crate::builder_state::{BuilderState, MessageType, ResponseMessage, RequestMessage}; use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage}; -use builder_api::data_source::BuilderDataSource; +use hs_builder_api::{data_source::BuilderDataSource, block_metadata::BlockMetadata, builder::BuildError}; use sha2::{Digest, Sha256}; #[derive(clap::Args, Default)] @@ -68,7 +68,7 @@ pub struct Options { pub struct GlobalState{ pub block_hash_to_block: HashMap, pub vid_to_potential_builder_state: HashMap>, - pub request_sender: BroadcastSender>, + pub request_sender: BroadcastSender, } impl GlobalState{ @@ -79,23 +79,30 @@ impl GlobalState{ } } } +use hotshot_types::traits::node_implementation::NodeType; -impl BuilderDataSourc for GlobalState +impl BuilderDataSource for GlobalState { async fn get_available_blocks( &self, for_parent: &VidCommitment, ) -> Result>, BuildError> { - unimplemented!() + + let req_msg = RequestMessage{ + requested_vid_commitment: for_parent.clone(), + }; + self.request_sender.broadcast(req_msg).await.unwrap(); } async fn claim_block( &self, - block_hash: &BuilderCommitment, - signature: &<::SignatureKey as SignatureKey>::PureAssembledSignatureType, + block_hash: &BuilderCommitment, + signature: &<::SignatureKey as SignatureKey>::PureAssembledSignatureType, ) -> Result { - unimplemented!() + //unimplemented!() + let block = self.block_hash_to_block.get(&block_hash).unwrap().clone(); + Ok(block) } - async fn submit_txn(&self, txn: ::Transaction) -> Result<(), BuildError> { + async fn submit_txn(&self, txn: ::Transaction) -> Result<(), BuildError> { unimplemented!() } } From 47daf64773c28b3412de85f61638aa698432c3a2 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 5 Feb 2024 16:31:19 -0500 Subject: [PATCH 19/47] remove api.rs --- src/api.rs | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 src/api.rs diff --git a/src/api.rs b/src/api.rs deleted file mode 100644 index fd3181ab..00000000 --- a/src/api.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2024 Espresso Systems (espressosys.com) -// This file is part of the HotShot Builder Protocol. -// - -//! Builder Phase 1 -//! It mainly provides two API services to external users: -//! 1. Serves a proposer(leader)'s request to provide blocks information -//! 2. Serves a proposer(leader)'s request to provide the full blocks information -//! 3. Serves a request to submit a transaction externally i.e outside the HotShot network - -//! To support the above two services, it uses the following core services: -//! 1. To facilitate the acceptance of the transactions i.e. private and public mempool -//! 2. Actions to be taken on hearning of: -//! a. DA Proposal -//! b. Quorum Proposal -//! c. Decide Event -//! - -// The return types of the API services might differ from internal BuilderType - -// Used by the first APT service i.e. to provide blocks information -async fn process_proposer_p1_request(){ - -} - -// Used by the second API service i.e to provide full blocks information -async fn process_proposer_p2_request(){ - -} - -// Used by the third API service i.e. to submit a transaction externally (priavate mempool) -async fn process_external_transaction(){ - -} \ No newline at end of file From 1788350587cbf00849b856c1512202b0158ff105 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 5 Feb 2024 18:36:00 -0500 Subject: [PATCH 20/47] replace response broadcast channel to mpsc channel --- Cargo.toml | 6 +++--- src/builder_state.rs | 8 ++++---- src/lib.rs | 2 +- src/service.rs | 3 ++- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2babcda1..2947c79a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,9 +5,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -# async-compatibility-layer = { git = "https://github.com/EspressoSystems/async-compatibility-layer.git", tag = "1.4.1", features = [ -# "logging-utils", -# ] } +async-compatibility-layer = { git = "https://github.com/EspressoSystems/async-compatibility-layer.git", tag = "1.4.1", features = [ + "logging-utils", +] } # async-compatibility-layer = { path="../async-compatibility-layer", features = [ # "logging-utils", # ] } diff --git a/src/builder_state.rs b/src/builder_state.rs index 874aad70..618c69ee 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -13,7 +13,7 @@ use bincode::de; use futures::{Future, select}; use async_std::task::{self, Builder}; use async_trait::async_trait; -//use async_compatibility_layer::channel::{unbounded, UnboundedSender, UnboundedStream, UnboundedReceiver}; +use async_compatibility_layer::{channel::{UnboundedStream,UnboundedReceiver, UnboundedSender}, art::async_spawn, }; use async_lock::RwLock; use hotshot_task_impls::transactions; use hotshot_types::traits::block_contents::{vid_commitment, TestableBlock}; @@ -154,7 +154,7 @@ pub struct BuilderState{ pub global_state: Arc::>>, // response sender - pub response_sender: BroadcastSender, + pub response_sender: UnboundedSender, // quorum membership pub quorum_membership: Arc, @@ -470,7 +470,7 @@ impl BuilderProgress for BuilderState{ match response{ Some(response)=>{ // send the response back - self.response_sender.broadcast(response).await.unwrap(); + self.response_sender.send(response).await.unwrap(); } None => { println!("No response to send"); @@ -557,7 +557,7 @@ pub enum MessageType{ } impl BuilderState{ - pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>, global_state: Arc>>, response_sender: BroadcastSender, quorum_membership: TYPES::Membership)-> Self{ + pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>, global_state: Arc>>, response_sender: UnboundedSender, quorum_membership: TYPES::Membership)-> Self{ BuilderState{ builder_id: builder_id, timestamp_to_tx: BTreeMap::new(), diff --git a/src/lib.rs b/src/lib.rs index 6c1fa618..3b75b2bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ //! // providing the API services to the external users -pub mod api; +// pub mod api; // providing the core services to support above API services pub mod builder_state; diff --git a/src/service.rs b/src/service.rs index b692a0ef..a19e8c46 100644 --- a/src/service.rs +++ b/src/service.rs @@ -19,7 +19,7 @@ #![allow(unused_imports)] #![allow(unused_variables)] pub use hotshot::{traits::NodeImplementation, types::SystemContextHandle, HotShotConsensusApi}; -//use async_compatibility_layer::{channel::UnboundedStream, art::async_spawn}; +use async_compatibility_layer::{channel::{UnboundedStream,UnboundedReceiver, UnboundedSender}, art::async_spawn, }; use async_lock::RwLock; use commit::Committable; use futures::{Stream, stream::StreamExt}; @@ -69,6 +69,7 @@ pub struct GlobalState{ pub block_hash_to_block: HashMap, pub vid_to_potential_builder_state: HashMap>, pub request_sender: BroadcastSender, + pub response_receiver: UnboundedReceiver, } impl GlobalState{ From ea56b28be71938df4f5ff84cc730f0dff7d41900 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 5 Feb 2024 18:48:55 -0500 Subject: [PATCH 21/47] add builderstate to global state --- src/builder_state.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 618c69ee..b69726da 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -270,7 +270,11 @@ impl BuilderProgress for BuilderState{ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(qc_proposal_data) = self.quorum_proposal_payload_commit_to_quorum_proposal.entry(payload_vid_commitment.clone()) { let qc_proposal_data = qc_proposal_data.remove(); - self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; + let self_clone = self.clone(); + self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await; + + // register the clone to the global state + self.global_state.write_arc().builder_states.insert(payload_vid_commitment, self_clone); } else { self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data); } @@ -301,7 +305,12 @@ impl BuilderProgress for BuilderState{ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(da_proposal_data) = self.da_proposal_payload_commit_to_da_proposal.entry(payload_vid_commitment.clone()) { let da_proposal_data = da_proposal_data.remove(); - self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; + let self_clone = self.clone(); + self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await; + + // registed the clone to the global state + self.global_state.write_arc().builder_states.insert(payload_vid_commitment, self_clone); + } else { self.quorum_proposal_payload_commit_to_quorum_proposal.insert(payload_vid_commitment, qc_proposal_data.clone()); } From 648341b671497aed01f5a41bb57bcf2462c3e488 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 5 Feb 2024 19:08:12 -0500 Subject: [PATCH 22/47] type fixes --- src/builder_state.rs | 11 +++++++---- src/service.rs | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index b69726da..b4e566ce 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -43,7 +43,7 @@ use hotshot_types::{ data::{DAProposal, Leaf, QuorumProposal, VidCommitment, VidScheme, VidSchemeTrait, test_srs}, simple_certificate::QuorumCertificate, message::Proposal, - traits::{block_contents::{BlockPayload, BlockHeader, Transaction}, signature_key::SignatureKey}, + traits::{block_contents::{BlockPayload, BlockHeader, Transaction}, signature_key::SignatureKey, election::Membership}, utils::BuilderCommitment }; use commit::{Commitment, Committable}; @@ -274,7 +274,7 @@ impl BuilderProgress for BuilderState{ self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await; // register the clone to the global state - self.global_state.write_arc().builder_states.insert(payload_vid_commitment, self_clone); + self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); } else { self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data); } @@ -309,7 +309,7 @@ impl BuilderProgress for BuilderState{ self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await; // registed the clone to the global state - self.global_state.write_arc().builder_states.insert(payload_vid_commitment, self_clone); + self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); } else { self.quorum_proposal_payload_commit_to_quorum_proposal.insert(payload_vid_commitment, qc_proposal_data.clone()); @@ -430,6 +430,8 @@ impl BuilderProgress for BuilderState{ // get the number of quorum committee members to be used for VID calculation + //let quo_membership = Arc::into_inner(self.quorum_membership).unwrap();//.clone(); + let num_quorum_committee = self.quorum_membership.total_nodes(); // TODO @@ -563,10 +565,11 @@ pub enum MessageType{ DecideMessage(DecideMessage), DAProposalMessage(DAProposalMessage), QCMessage(QCMessage), + RequestMessage(RequestMessage), } impl BuilderState{ - pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>, global_state: Arc>>, response_sender: UnboundedSender, quorum_membership: TYPES::Membership)-> Self{ + pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>, global_state: Arc>>, response_sender: UnboundedSender, quorum_membership: Arc)-> Self{ BuilderState{ builder_id: builder_id, timestamp_to_tx: BTreeMap::new(), diff --git a/src/service.rs b/src/service.rs index a19e8c46..4dff9f50 100644 --- a/src/service.rs +++ b/src/service.rs @@ -64,7 +64,7 @@ pub struct Options { pub port: u16 } // -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct GlobalState{ pub block_hash_to_block: HashMap, pub vid_to_potential_builder_state: HashMap>, @@ -108,6 +108,7 @@ impl BuilderDataSource for GlobalState, D>( From c942480b03c70d9fe01ec18b5d3cd760ea0e5130 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Tue, 6 Feb 2024 22:00:51 -0500 Subject: [PATCH 23/47] fix response message --- Cargo.toml | 4 +- src/builder_state.rs | 126 ++++++++++++++++++++++---------------- src/service.rs | 54 ++++++++++++---- src/testing/basic_test.rs | 12 ++-- 4 files changed, 124 insertions(+), 72 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2947c79a..0ae63130 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,4 +46,6 @@ async-broadcast = "0.6.0" sha2 = "0.10" jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish" } -hs-builder-api = {git = "https://github.com/EspressoSystems/hs-builder-api", branch="main"} \ No newline at end of file +#hs-builder-api = {git = "https://github.com/EspressoSystems/hs-builder-api", branch="main"} +hs-builder-api = {path="../hs-builder-api"} +tagged-base64 = { git = "https://github.com/EspressoSystems/tagged-base64", tag = "0.3.4" } \ No newline at end of file diff --git a/src/builder_state.rs b/src/builder_state.rs index b4e566ce..d1f9ddbc 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -50,6 +50,7 @@ use commit::{Commitment, Committable}; use jf_primitives::signatures::bls_over_bn254::{BLSOverBN254CurveSignatureScheme, KeyPair, SignKey, VerKey}; use futures::future::select_all; +use async_std::task::JoinHandle; pub type TxTimeStamp = u128; const NUM_NODES_IN_VID_COMPUTATION: usize = 8; @@ -89,11 +90,14 @@ pub struct RequestMessage{ //pub total_nodes: usize } -#[derive(Clone, Debug, PartialEq)] -pub struct ResponseMessage{ +#[derive(Debug, Clone)] +pub struct ResponseMessage{ pub block_hash: BuilderCommitment, //TODO: Need to pull out from hotshot pub block_size: u64, pub offered_fee: u64, + pub block_payload: TYPES::BlockPayload, + pub metadata: <::BlockPayload as BlockPayload>::Metadata, + pub join_handle: Arc::>, } pub enum Status { @@ -154,10 +158,13 @@ pub struct BuilderState{ pub global_state: Arc::>>, // response sender - pub response_sender: UnboundedSender, + pub response_sender: UnboundedSender>, // quorum membership pub quorum_membership: Arc, + + // builder Commitements + pub builder_commitments: Vec, } /// Trait to hold the helper functions for the builder #[async_trait] @@ -181,10 +188,13 @@ pub trait BuilderProgress { async fn spawn_clone(self, da_proposal: DAProposal, quorum_proposal: QuorumProposal, leader: TYPES::SignatureKey); /// build a block - async fn build_block(&mut self, matching_vid: VidCommitment) -> Option; + async fn build_block(&mut self, matching_vid: VidCommitment) -> Option>; /// Event Loop async fn event_loop(mut self); + + /// process the block request + async fn process_block_request(&mut self, req: RequestMessage); } @@ -258,6 +268,7 @@ impl BuilderProgress for BuilderState{ // generate the vid commitment; num nodes are received through hotshot api in service.rs and passed along with message onto channel let total_nodes = da_msg.total_nodes; + let payload_vid_commitment = vid_commitment(&encoded_txns, total_nodes); if !self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment) { @@ -270,11 +281,13 @@ impl BuilderProgress for BuilderState{ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(qc_proposal_data) = self.quorum_proposal_payload_commit_to_quorum_proposal.entry(payload_vid_commitment.clone()) { let qc_proposal_data = qc_proposal_data.remove(); - let self_clone = self.clone(); - self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await; + + //let self_clone = self.clone(); + + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; // register the clone to the global state - self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); + //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); } else { self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data); } @@ -290,6 +303,7 @@ impl BuilderProgress for BuilderState{ // check for the leaf commitment // check for signature validation and correct leader (both of these are done in the service.rs i.e. before putting hotshot events onto the da channel) // can use this commitment to match the da proposal or vice-versa + // TODO: if this special value if qc_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0 || qc_msg.proposal.data.justify_qc.get_data().leaf_commit != self.built_from_view_vid_leaf.2 { println!("Either View number or leaf commit does not match the built-in info, so ignoring it"); @@ -305,11 +319,11 @@ impl BuilderProgress for BuilderState{ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(da_proposal_data) = self.da_proposal_payload_commit_to_da_proposal.entry(payload_vid_commitment.clone()) { let da_proposal_data = da_proposal_data.remove(); - let self_clone = self.clone(); - self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await; + //let self_clone = self.clone(); + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; // registed the clone to the global state - self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); + //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); } else { self.quorum_proposal_payload_commit_to_quorum_proposal.insert(payload_vid_commitment, qc_proposal_data.clone()); @@ -322,6 +336,9 @@ impl BuilderProgress for BuilderState{ async fn process_decide_event(&mut self, decide_msg: DecideMessage) -> Option { + // special clone already launched the clone, then exit + // if you haven't launched the clone, then you don't exit, you need atleast one clone to function properly + // the special value can be 0 itself, or a view number 0 is also right answer let leaf_chain = decide_msg.leaf_chain; let qc = decide_msg.qc; let block_size = decide_msg.block_size; @@ -335,6 +352,11 @@ impl BuilderProgress for BuilderState{ if self.built_from_view_vid_leaf.0 <= leaf_view_number{ println!("The decide event is not for the next view, so ignoring it"); + // convert leaf commitments into buildercommiments + //let leaf_commitments:Vec = leaf_chain.iter().map(|leaf| leaf.get_block_payload().unwrap().builder_commitment(&leaf.get_block_header().metadata())).collect(); + + // remove the handles from the global state + self.global_state.write_arc().await.remove_handles(self.built_from_view_vid_leaf.1, self.builder_commitments.clone()); return Some(Status::ShouldExit); } @@ -366,12 +388,7 @@ impl BuilderProgress for BuilderState{ } } } - // convert leaf commitments into buildercommiments - let leaf_commitments:Vec = leaf_chain.iter().map(|leaf| leaf.get_block_payload().unwrap().builder_commitment(&leaf.get_block_header().metadata())).collect(); - - self.global_state.write_arc().await.remove_handles(self.built_from_view_vid_leaf.1, leaf_commitments); - // can use get_mut() also - + return Some(Status::ShouldContinue); } @@ -409,7 +426,7 @@ impl BuilderProgress for BuilderState{ } // build a block - async fn build_block(&mut self, matching_vid: VidCommitment) -> Option{ + async fn build_block(&mut self, matching_vid: VidCommitment) -> Option>{ if let Ok((payload, metadata)) = ::from_transactions( self.timestamp_to_tx.iter().filter_map(|(ts, tx_hash)| { @@ -420,7 +437,10 @@ impl BuilderProgress for BuilderState{ let block_hash = payload.builder_commitment(&metadata); - //let num_txns = ::txn_count(&payload);// TODO: figure out + // add the local builder commitment list + self.builder_commitments.push(block_hash.clone()); + + //let num_txns = ::txn_count(&payload); let encoded_txns:Vec = payload.encode().unwrap().into_iter().collect(); @@ -449,52 +469,44 @@ impl BuilderProgress for BuilderState{ vid.disperse(encoded_txns).unwrap(); }); - // // calculate vid shares - // let vid_disperse = spawn_blocking(move || { - // let vid = VidScheme::new(chunk_size, num_quorum_committee, &srs).unwrap(); - // vid.disperse(encoded_transactions.clone()).unwrap() - // }) - // .await; - - - //self.global_state.write().block_hash_to_block.insert(block_hash, (payload, metadata, join_handle)); //let mut global_state = self.global_state.write().unwrap(); - self.global_state.write_arc().await.block_hash_to_block.insert(block_hash, payload); - return Some(ResponseMessage{block_hash: block_hash, block_size: block_size, offered_fee: offered_fee}); + //self.global_state.write_arc().await.block_hash_to_block.insert(block_hash.clone(), (payload, metadata, join_handle)); + return Some(ResponseMessage{block_hash: block_hash, block_size: block_size, offered_fee: offered_fee, block_payload: payload, metadata: metadata, join_handle: Arc::new(join_handle)}); }; None } + async fn process_block_request(&mut self, req: RequestMessage){ + let requested_vid_commitment = req.requested_vid_commitment; + //let vid_nodes = req.total_nodes; + if requested_vid_commitment == self.built_from_view_vid_leaf.1{ + let response = self.build_block(requested_vid_commitment).await; + match response{ + Some(response)=>{ + // send the response back + self.response_sender.send(response.clone()).await.unwrap(); + //let inner = Arc::unwrap_or_clone(response.join_handle); + self.global_state.write_arc().await.block_hash_to_block.insert(response.block_hash, (response.block_payload, response.metadata, response.join_handle)); + } + None => { + println!("No response to send"); + } + } + + } + } + async fn event_loop(mut self) { task::spawn(async move{ loop{ //let builder_state = builder_state.lock().unwrap(); while let Ok(req) = self.req_receiver.recv().await { if let MessageType::RequestMessage(req) = req { - - let requested_vid_commitment = req.requested_vid_commitment; - //let vid_nodes = req.total_nodes; - if requested_vid_commitment == self.built_from_view_vid_leaf.1{ - let response = self.build_block(requested_vid_commitment).await; - match response{ - Some(response)=>{ - // send the response back - self.response_sender.send(response).await.unwrap(); - } - None => { - println!("No response to send"); - } - } - } + self.process_block_request(req).await; } - // //... handle requests - //selft says do I have a block for this set of txns? if so, return that header?? MPSC [async_compatility] - // // else iterate through and call build block, and add block to blockmap in globalstate - // // do validity check for the requester as well i.e are they leader for one of the next k views - - } + }; let (received_msg, channel_index, _)= select_all([self.tx_receiver.recv(), self.decide_receiver.recv(), self.da_proposal_receiver.recv(), self.qc_receiver.recv(), self.req_receiver.recv()]).await; @@ -506,9 +518,9 @@ impl BuilderProgress for BuilderState{ // request message MessageType::RequestMessage(req) => { println!("Received request msg in builder {}: {:?} from index {}", self.builder_id.0, req, channel_index); - // store in the rtx_msgs - //rreq_msgs.push(req.clone()); - //builder_state.process_request(req).await; + + self.process_block_request(req).await; + } // transaction message @@ -530,6 +542,8 @@ impl BuilderProgress for BuilderState{ println!("Received decide msg in builder {}: {:?} from index {}", self.builder_id.0, rdecide_msg, channel_index); // store in the rdecide_msgs self.process_decide_event(rdecide_msg).await; + // TODO + // if should exit, then break out of the loop } // DA proposal message @@ -569,7 +583,10 @@ pub enum MessageType{ } impl BuilderState{ - pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>, global_state: Arc>>, response_sender: UnboundedSender, quorum_membership: Arc)-> Self{ + pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, + decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, + req_receiver: BroadcastReceiver>, global_state: Arc>>, response_sender: UnboundedSender>, + quorum_membership: Arc)-> Self{ BuilderState{ builder_id: builder_id, timestamp_to_tx: BTreeMap::new(), @@ -587,6 +604,7 @@ impl BuilderState{ global_state: global_state, response_sender: response_sender, quorum_membership: quorum_membership, + builder_commitments: vec![], } } diff --git a/src/service.rs b/src/service.rs index 4dff9f50..ee728cf5 100644 --- a/src/service.rs +++ b/src/service.rs @@ -40,7 +40,7 @@ use hotshot_types::{ message::{MessageKind, SequencingMessage}, traits::{ election::Membership, node_implementation::NodeType as BuilderType, storage::Storage, - signature_key::SignatureKey,block_contents::BlockHeader, consensus_api::ConsensusApi + signature_key::SignatureKey,block_contents::{BlockHeader,BlockPayload}, consensus_api::ConsensusApi }, utils::BuilderCommitment }; @@ -53,10 +53,11 @@ use async_broadcast::{broadcast, Sender as BroadcastSender, Receiver as Broadcas use futures::future::ready; use crate::builder_state::{BuilderState, MessageType, ResponseMessage, RequestMessage}; use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage}; - +use tagged_base64::TaggedBase64; use hs_builder_api::{data_source::BuilderDataSource, block_metadata::BlockMetadata, builder::BuildError}; - +use async_trait::async_trait; +use async_std::task::JoinHandle; use sha2::{Digest, Sha256}; #[derive(clap::Args, Default)] pub struct Options { @@ -66,23 +67,28 @@ pub struct Options { // #[derive(Debug)] pub struct GlobalState{ - pub block_hash_to_block: HashMap, - pub vid_to_potential_builder_state: HashMap>, + //pub block_hash_to_block: HashMap, + pub block_hash_to_block: HashMap::BlockPayload as BlockPayload>::Metadata, Arc>)>, + //pub vid_to_potential_builder_state: HashMap>, pub request_sender: BroadcastSender, - pub response_receiver: UnboundedReceiver, + pub response_receiver: UnboundedReceiver>, } impl GlobalState{ pub fn remove_handles(&mut self, vidcommitment: VidCommitment, block_hashes: Vec) { - self.vid_to_potential_builder_state.remove(&vidcommitment); + //self.vid_to_potential_builder_state.remove(&vidcommitment); for block_hash in block_hashes { self.block_hash_to_block.remove(&block_hash); } } } -use hotshot_types::traits::node_implementation::NodeType; +//use hotshot_types::traits::node_implementation::NodeType; -impl BuilderDataSource for GlobalState +#[async_trait] +impl BuilderDataSource for GlobalState +where + for<'a> <::SignatureKey as SignatureKey>::PureAssembledSignatureType: From<&'a tagged_base64::TaggedBase64>, + TaggedBase64: From<<::SignatureKey as SignatureKey>::PureAssembledSignatureType> { async fn get_available_blocks( &self, @@ -93,15 +99,38 @@ impl BuilderDataSource for GlobalState{ + let block_metadata = BlockMetadata::{ + block_hash: response.block_hash, + block_size: response.block_size, + offered_fee: response.offered_fee, + _phantom: Default::default(), + }; + Ok(vec![block_metadata]) + + } + _ => { + Err(BuildError::Error{message: "No blocks available".to_string()}) + } + } } async fn claim_block( &self, block_hash: &BuilderCommitment, signature: &<::SignatureKey as SignatureKey>::PureAssembledSignatureType, ) -> Result { - //unimplemented!() - let block = self.block_hash_to_block.get(&block_hash).unwrap().clone(); - Ok(block) + // TODO: Verify the signature?? + + if let Some(block) = self.block_hash_to_block.get(block_hash){ + Ok(block.0.clone()) + } else { + Err(BuildError::Error{message: "Block not found".to_string()}) + } + // TODO: should we remove the block from the hashmap? + } async fn submit_txn(&self, txn: ::Transaction) -> Result<(), BuildError> { unimplemented!() @@ -120,7 +149,6 @@ pub async fn run_standalone_builder_service>, qc_sender: BroadcastSender>, req_sender: BroadcastSender>, - response_receiver: BroadcastReceiver, ) -> Result<(),()> //where //TODO diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 91242a8d..c204f45f 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -10,7 +10,10 @@ use async_std::task::{self, Builder}; use std::sync::{Arc, Mutex}; use sha2::{Digest, Sha256}; use futures::future::select_all; -pub use hotshot_testing::{block_types::{TestTransaction, TestBlockHeader, TestBlockPayload, genesis_vid_commitment}, state_types::TestState}; +pub use hotshot_testing::{ + block_types::{TestTransaction, TestBlockHeader, TestBlockPayload, genesis_vid_commitment}, + state_types::{TestInstanceState, TestValidatedState}, +}; pub use hotshot_types::{ traits::node_implementation::NodeType as BuilderType, data::{ViewNumber, Leaf, DAProposal, QuorumProposal}, @@ -32,7 +35,7 @@ mod tests { use std::{collections::HashSet, env, hash::Hash, marker::PhantomData}; use hotshot::{rand::seq::index, types::SignatureKey}; - use hotshot_types::{data::QuorumProposal, message::Message, traits::{block_contents::BlockHeader, state::ConsensusTime}, vote::HasViewNumber}; + use hotshot_types::{data::QuorumProposal, message::Message, traits::block_contents::BlockHeader, vote::HasViewNumber}; use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage}; @@ -70,7 +73,8 @@ mod tests { type SignatureKey = BLSPubKey; type Transaction = TestTransaction; type ElectionConfigType = StaticElectionConfig; - type StateType = TestState; + type ValidatedState = TestValidatedState; + type InstanceState = TestInstanceState; type Membership = GeneralStaticCommittee; } @@ -135,7 +139,7 @@ mod tests { let qc_signature = da_signature.clone(); let qc_proposal = QuorumProposal::{ - block_header: TestBlockHeader::genesis().0, + block_header: TestBlockHeader::genesis(&TestInstanceState {}).0, view_number: ViewNumber::new(i as u64), justify_qc: QuorumCertificate::::genesis(), timeout_certificate: None, From 6f6f2fddd2fa681f79584de19f83ba7bd3eb1b93 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Tue, 6 Feb 2024 22:18:39 -0500 Subject: [PATCH 24/47] remove unused imports --- src/builder_state.rs | 63 +++++++++++++++----------------------------- src/service.rs | 54 +++++++++++++------------------------ 2 files changed, 40 insertions(+), 77 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index d1f9ddbc..e571a1b9 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -2,58 +2,42 @@ // This file is part of the HotShot Builder Protocol. // -#![allow(unused_imports)] #![allow(unused_variables)] -use std::collections::hash_map::Entry; -use std::collections::{BTreeMap, HashMap, HashSet}; -use std::hash::BuildHasher; -use std::marker::PhantomData; -use std::sync::{Arc, Mutex}; -use bincode::de; -use futures::{Future, select}; -use async_std::task::{self, Builder}; -use async_trait::async_trait; -use async_compatibility_layer::{channel::{UnboundedStream,UnboundedReceiver, UnboundedSender}, art::async_spawn, }; -use async_lock::RwLock; -use hotshot_task_impls::transactions; -use hotshot_types::traits::block_contents::{vid_commitment, TestableBlock}; -use hotshot_types::vote::Certificate; -use sha2::{Digest, Sha256}; - -use hotshot::rand::seq::index; -use hotshot_testing::block_types::{TestBlockHeader, TestBlockPayload, TestTransaction}; +// use hotshot_testing::block_types::{TestBlockHeader, TestBlockPayload, TestTransaction}; //use hotshot_task::event_stream::{ChannelStream, EventStream, StreamId}; -use tokio_stream::StreamExt; - -use tokio_stream::wrappers::UnboundedReceiverStream; - -use std::{ - pin::Pin, - task::{Context, Poll}, - fmt::{Debug, Formatter}, -}; -use futures::Stream; - -use std::time::{SystemTime, UNIX_EPOCH}; -use async_broadcast::{broadcast, TryRecvError, Sender as BroadcastSender, Receiver as BroadcastReceiver, RecvError}; // including the following from the hotshot use hotshot_types::{ - traits::node_implementation::NodeType as BuilderType, + traits::{node_implementation::NodeType as BuilderType, block_contents::vid_commitment}, data::{DAProposal, Leaf, QuorumProposal, VidCommitment, VidScheme, VidSchemeTrait, test_srs}, simple_certificate::QuorumCertificate, message::Proposal, - traits::{block_contents::{BlockPayload, BlockHeader, Transaction}, signature_key::SignatureKey, election::Membership}, - utils::BuilderCommitment + traits::{block_contents::{BlockPayload, BlockHeader}, election::Membership}, + utils::BuilderCommitment, + vote::Certificate }; +use jf_primitives::signatures::bls_over_bn254::{SignKey, VerKey}; use commit::{Commitment, Committable}; -use jf_primitives::signatures::bls_over_bn254::{BLSOverBN254CurveSignatureScheme, KeyPair, SignKey, VerKey}; use futures::future::select_all; use async_std::task::JoinHandle; +use async_broadcast::{Receiver as BroadcastReceiver, RecvError}; +use async_std::task; +use async_trait::async_trait; +use async_compatibility_layer::channel:: UnboundedSender; +use async_lock::RwLock; + +use std::collections::hash_map::Entry; +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::sync::Arc; +use std::time::SystemTime; +use std::fmt::Debug; +use std::cmp::PartialEq; + +use crate::service::GlobalState; pub type TxTimeStamp = u128; -const NUM_NODES_IN_VID_COMPUTATION: usize = 8; +//const NUM_NODES_IN_VID_COMPUTATION: usize = 8; #[derive(Clone, Debug, PartialEq)] pub enum TransactionSource { @@ -105,11 +89,6 @@ pub enum Status { ShouldContinue, } -use std::cmp::{PartialEq, Ord, PartialOrd}; -use std::hash::Hash; - -use crate::service::GlobalState; - #[derive(Debug, Clone)] pub struct BuilderState{ diff --git a/src/service.rs b/src/service.rs index ee728cf5..4e5004b8 100644 --- a/src/service.rs +++ b/src/service.rs @@ -15,50 +15,34 @@ //! b. Quorum Proposal //! c. Decide Event //! -// TODO no warning for unused imports -#![allow(unused_imports)] #![allow(unused_variables)] -pub use hotshot::{traits::NodeImplementation, types::SystemContextHandle, HotShotConsensusApi}; -use async_compatibility_layer::{channel::{UnboundedStream,UnboundedReceiver, UnboundedSender}, art::async_spawn, }; -use async_lock::RwLock; -use commit::Committable; -use futures::{Stream, stream::StreamExt}; -use hotshot_task::{ - boxed_sync, - event_stream::{ChannelStream, EventStream, StreamId}, - global_registry::GlobalRegistry, - task::FilterEvent, - BoxSyncFuture, -}; -use hotshot_task_impls::events::HotShotEvent; -use hotshot_testing::state_types::TestTypes; -use hotshot_types::{data::VidCommitment, simple_vote::QuorumData}; +use hotshot::{traits::NodeImplementation, types::SystemContextHandle, HotShotConsensusApi}; +use hotshot_task::task::FilterEvent; use hotshot_types::{ - consensus::Consensus, - error::HotShotError, - event::{EventType, Event}, - message::{MessageKind, SequencingMessage}, + event::EventType, traits::{ - election::Membership, node_implementation::NodeType as BuilderType, storage::Storage, + node_implementation::NodeType as BuilderType, signature_key::SignatureKey,block_contents::{BlockHeader,BlockPayload}, consensus_api::ConsensusApi }, - utils::BuilderCommitment + utils::BuilderCommitment, + data::VidCommitment }; -use hotshot_types::{data::Leaf, simple_certificate::QuorumCertificate}; +use hs_builder_api::{data_source::BuilderDataSource, block_metadata::BlockMetadata, builder::BuildError}; + +use futures::stream::StreamExt; +use async_compatibility_layer::channel::UnboundedReceiver; +use async_broadcast::Sender as BroadcastSender; +use async_trait::async_trait; +use async_std::task::JoinHandle; + use std::{collections::HashMap, sync::Arc}; +use tagged_base64::TaggedBase64; use tracing::error; +use sha2::{Digest, Sha256}; -//use crate::builder_state::{MessageType, BuilderType, TransactionMessage, DecideMessage, QuorumProposalMessage, QCMessage}; -use async_broadcast::{broadcast, Sender as BroadcastSender, Receiver as BroadcastReceiver}; -use futures::future::ready; -use crate::builder_state::{BuilderState, MessageType, ResponseMessage, RequestMessage}; use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage}; -use tagged_base64::TaggedBase64; +use crate::builder_state::{ MessageType, ResponseMessage, RequestMessage}; -use hs_builder_api::{data_source::BuilderDataSource, block_metadata::BlockMetadata, builder::BuildError}; -use async_trait::async_trait; -use async_std::task::JoinHandle; -use sha2::{Digest, Sha256}; #[derive(clap::Args, Default)] pub struct Options { #[clap(short, long, env = "ESPRESSO_BUILDER_PORT")] @@ -77,6 +61,7 @@ pub struct GlobalState{ impl GlobalState{ pub fn remove_handles(&mut self, vidcommitment: VidCommitment, block_hashes: Vec) { //self.vid_to_potential_builder_state.remove(&vidcommitment); + println!("Removing handles for vid commitment {:?}", vidcommitment); for block_hash in block_hashes { self.block_hash_to_block.remove(&block_hash); } @@ -148,8 +133,6 @@ pub async fn run_standalone_builder_service>, da_sender: BroadcastSender>, qc_sender: BroadcastSender>, - req_sender: BroadcastSender>, - ) -> Result<(),()> //where //TODO //Payload: availability::QueryablePayload @@ -237,6 +220,7 @@ pub async fn run_standalone_builder_service { + println!("View Finished Event for view number: {:?}", view_number); unimplemented!("View Finished Event"); } _ => { From 6ba41d8946a8957d375f31a5aacbeb5020315b99 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Wed, 7 Feb 2024 10:02:43 -0500 Subject: [PATCH 25/47] change keys type --- src/builder_state.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index e571a1b9..b82b5518 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -8,15 +8,15 @@ // including the following from the hotshot use hotshot_types::{ - traits::{node_implementation::NodeType as BuilderType, block_contents::vid_commitment}, + traits::{node_implementation::NodeType as BuilderType, block_contents::vid_commitment, signature_key::SignatureKey}, data::{DAProposal, Leaf, QuorumProposal, VidCommitment, VidScheme, VidSchemeTrait, test_srs}, simple_certificate::QuorumCertificate, message::Proposal, traits::{block_contents::{BlockPayload, BlockHeader}, election::Membership}, utils::BuilderCommitment, - vote::Certificate + vote::Certificate, }; -use jf_primitives::signatures::bls_over_bn254::{SignKey, VerKey}; +//use jf_primitives::signatures::bls_over_bn254::{SignKey, VerKey}; use commit::{Commitment, Committable}; use futures::future::select_all; @@ -92,7 +92,7 @@ pub enum Status { #[derive(Debug, Clone)] pub struct BuilderState{ - pub builder_id: (VerKey, SignKey), //TODO (pub,priv) key of the builder, may be good to keep a ref + pub builder_keys: (TYPES::SignatureKey, <::SignatureKey as SignatureKey>::PrivateKey), //TODO (pub,priv) key of the builder, may be good to keep a ref // timestamp to tx hash, used for ordering for the transactions pub timestamp_to_tx: BTreeMap>, @@ -496,7 +496,7 @@ impl BuilderProgress for BuilderState{ // request message MessageType::RequestMessage(req) => { - println!("Received request msg in builder {}: {:?} from index {}", self.builder_id.0, req, channel_index); + println!("Received request msg in builder {}: {:?} from index {}", self.builder_keys.0, req, channel_index); self.process_block_request(req).await; @@ -504,7 +504,7 @@ impl BuilderProgress for BuilderState{ // transaction message MessageType::TransactionMessage(rtx_msg) => { - println!("Received tx msg in builder {}: {:?} from index {}", self.builder_id.0, rtx_msg, channel_index); + println!("Received tx msg in builder {}: {:?} from index {}", self.builder_keys.0, rtx_msg, channel_index); // get the content from the rtx_msg's inside vec // Pass the tx msg to the handler @@ -518,7 +518,7 @@ impl BuilderProgress for BuilderState{ // decide message MessageType::DecideMessage(rdecide_msg) => { - println!("Received decide msg in builder {}: {:?} from index {}", self.builder_id.0, rdecide_msg, channel_index); + println!("Received decide msg in builder {}: {:?} from index {}", self.builder_keys.0, rdecide_msg, channel_index); // store in the rdecide_msgs self.process_decide_event(rdecide_msg).await; // TODO @@ -527,13 +527,13 @@ impl BuilderProgress for BuilderState{ // DA proposal message MessageType::DAProposalMessage(rda_msg) => { - println!("Received da proposal msg in builder {}: {:?} from index {}", self.builder_id.0, rda_msg, channel_index); + println!("Received da proposal msg in builder {}: {:?} from index {}", self.builder_keys.0, rda_msg, channel_index); self.process_da_proposal(rda_msg).await; } // QC proposal message MessageType::QCMessage(rqc_msg) => { - println!("Received qc msg in builder {}: {:?} from index {}", self.builder_id.0, rqc_msg, channel_index); + println!("Received qc msg in builder {}: {:?} from index {}", self.builder_keys.0, rqc_msg, channel_index); self.process_quorum_proposal(rqc_msg).await; } } @@ -562,12 +562,12 @@ pub enum MessageType{ } impl BuilderState{ - pub fn new(builder_id: (VerKey, SignKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, + pub fn new(builder_keys: (TYPES::SignatureKey, <::SignatureKey as SignatureKey>::PrivateKey), view_vid_leaf:(TYPES::Time, VidCommitment, Commitment>), tx_receiver: BroadcastReceiver>, decide_receiver: BroadcastReceiver>, da_proposal_receiver: BroadcastReceiver>, qc_receiver: BroadcastReceiver>, req_receiver: BroadcastReceiver>, global_state: Arc>>, response_sender: UnboundedSender>, quorum_membership: Arc)-> Self{ BuilderState{ - builder_id: builder_id, + builder_keys: builder_keys, timestamp_to_tx: BTreeMap::new(), tx_hash_to_available_txns: HashMap::new(), included_txns: HashSet::new(), From b2cc9b7f56e2c644723acf0d825e354d96798917 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Wed, 7 Feb 2024 12:37:34 -0500 Subject: [PATCH 26/47] add signature in api responses --- src/builder_state.rs | 28 ++++++++++++++++++++++++---- src/service.rs | 22 ++++++++++++++++------ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index b82b5518..7a541733 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -26,6 +26,7 @@ use async_std::task; use async_trait::async_trait; use async_compatibility_layer::channel:: UnboundedSender; use async_lock::RwLock; +//use sha2::digest::crypto_common::rand_core::block; use std::collections::hash_map::Entry; use std::collections::{BTreeMap, HashMap, HashSet}; @@ -82,6 +83,8 @@ pub struct ResponseMessage{ pub block_payload: TYPES::BlockPayload, pub metadata: <::BlockPayload as BlockPayload>::Metadata, pub join_handle: Arc::>, + pub signature:<::SignatureKey as SignatureKey>::PureAssembledSignatureType, + pub sender: TYPES::SignatureKey, } pub enum Status { @@ -423,9 +426,9 @@ impl BuilderProgress for BuilderState{ let encoded_txns:Vec = payload.encode().unwrap().into_iter().collect(); - let block_size = encoded_txns.len() as u64; + let block_size: u64 = encoded_txns.len() as u64; - let offered_fee = 0; + let offered_fee: u64 = 0; // get the number of quorum committee members to be used for VID calculation @@ -451,7 +454,20 @@ impl BuilderProgress for BuilderState{ //self.global_state.write().block_hash_to_block.insert(block_hash, (payload, metadata, join_handle)); //let mut global_state = self.global_state.write().unwrap(); //self.global_state.write_arc().await.block_hash_to_block.insert(block_hash.clone(), (payload, metadata, join_handle)); - return Some(ResponseMessage{block_hash: block_hash, block_size: block_size, offered_fee: offered_fee, block_payload: payload, metadata: metadata, join_handle: Arc::new(join_handle)}); + + // to sign combine the block_hash i.e builder commitment, block size and offered fee + let mut combined_bytes: Vec = Vec::new(); + combined_bytes.extend_from_slice(&block_size.to_be_bytes()); + combined_bytes.extend_from_slice(block_hash.as_ref()); + combined_bytes.extend_from_slice(&offered_fee.to_be_bytes()); + + let signature_over_block_info = ::SignatureKey::sign( + &self.builder_keys.1, combined_bytes.as_slice()) + .expect("Failed to sign tx hash"); + //let signature = self.builder_keys.0.sign(&block_hash); + return Some(ResponseMessage{block_hash: block_hash, block_size: block_size, offered_fee: offered_fee, + block_payload: payload, metadata: metadata, join_handle: Arc::new(join_handle), + signature: signature_over_block_info, sender: self.builder_keys.0.clone()}); }; None @@ -467,7 +483,11 @@ impl BuilderProgress for BuilderState{ // send the response back self.response_sender.send(response.clone()).await.unwrap(); //let inner = Arc::unwrap_or_clone(response.join_handle); - self.global_state.write_arc().await.block_hash_to_block.insert(response.block_hash, (response.block_payload, response.metadata, response.join_handle)); + // generate signature over the block payload and metadata and sent it back + + // again sign over the block hash + + self.global_state.write_arc().await.block_hash_to_block.insert(response.block_hash, (response.block_payload, response.metadata, response.join_handle, response.signature, response.sender)); } None => { println!("No response to send"); diff --git a/src/service.rs b/src/service.rs index 4e5004b8..a08a8d12 100644 --- a/src/service.rs +++ b/src/service.rs @@ -27,7 +27,7 @@ use hotshot_types::{ utils::BuilderCommitment, data::VidCommitment }; -use hs_builder_api::{data_source::BuilderDataSource, block_metadata::BlockMetadata, builder::BuildError}; +use hs_builder_api::{data_source::BuilderDataSource, block_info::{AvailableBlockData, AvailableBlockInfo}, builder::BuildError}; use futures::stream::StreamExt; use async_compatibility_layer::channel::UnboundedReceiver; @@ -52,7 +52,8 @@ pub struct Options { #[derive(Debug)] pub struct GlobalState{ //pub block_hash_to_block: HashMap, - pub block_hash_to_block: HashMap::BlockPayload as BlockPayload>::Metadata, Arc>)>, + pub block_hash_to_block: HashMap::BlockPayload as BlockPayload>::Metadata, Arc>, + <::SignatureKey as SignatureKey>::PureAssembledSignatureType,Types::SignatureKey)>, //pub vid_to_potential_builder_state: HashMap>, pub request_sender: BroadcastSender, pub response_receiver: UnboundedReceiver>, @@ -78,7 +79,7 @@ where async fn get_available_blocks( &self, for_parent: &VidCommitment, - ) -> Result>, BuildError> { + ) -> Result>, BuildError> { let req_msg = RequestMessage{ requested_vid_commitment: for_parent.clone(), @@ -88,10 +89,12 @@ where match response_received { Ok(response) =>{ - let block_metadata = BlockMetadata::{ + let block_metadata = AvailableBlockInfo::{ block_hash: response.block_hash, block_size: response.block_size, offered_fee: response.offered_fee, + signature: response.signature, + sender: response.sender, _phantom: Default::default(), }; Ok(vec![block_metadata]) @@ -106,11 +109,18 @@ where &self, block_hash: &BuilderCommitment, signature: &<::SignatureKey as SignatureKey>::PureAssembledSignatureType, - ) -> Result { + ) -> Result, BuildError> { // TODO: Verify the signature?? if let Some(block) = self.block_hash_to_block.get(block_hash){ - Ok(block.0.clone()) + //Ok(block.0.clone()) + let block_data = AvailableBlockData::{ + block_payload: block.0.clone(), + signature: block.3.clone(), + sender: block.4.clone(), + _phantom: Default::default(), + }; + Ok(block_data) } else { Err(BuildError::Error{message: "Block not found".to_string()}) } From ac70cccd99e56588e46e40f237d5f43e9ca87281 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Wed, 7 Feb 2024 13:58:52 -0500 Subject: [PATCH 27/47] add bootstrapping logic --- src/builder_state.rs | 43 +++++++++++++++++++++++++++++++++------ src/testing/basic_test.rs | 2 +- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 7a541733..1593826f 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -6,9 +6,10 @@ // use hotshot_testing::block_types::{TestBlockHeader, TestBlockPayload, TestTransaction}; //use hotshot_task::event_stream::{ChannelStream, EventStream, StreamId}; +//use hotshot_task_impls::da; // including the following from the hotshot use hotshot_types::{ - traits::{node_implementation::NodeType as BuilderType, block_contents::vid_commitment, signature_key::SignatureKey}, + traits::{node_implementation::{NodeType as BuilderType,ConsensusTime}, block_contents::vid_commitment, signature_key::SignatureKey}, data::{DAProposal, Leaf, QuorumProposal, VidCommitment, VidScheme, VidSchemeTrait, test_srs}, simple_certificate::QuorumCertificate, message::Proposal, @@ -234,7 +235,12 @@ impl BuilderProgress for BuilderState{ // check for view number // check for signature validation and correct leader (both of these are done in the service.rs i.e. before putting hotshot events onto the da channel) - if da_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0{ + // bootstrapping part + // if the view number is 0 then keep going, and don't return from it + if self.built_from_view_vid_leaf.0.get_u64() == 0 { + println!("In bootstrapping phase"); + } + else if da_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0{ println!("View number does not match the built_from_view, so ignoring it"); return; } @@ -285,8 +291,13 @@ impl BuilderProgress for BuilderState{ // check for the leaf commitment // check for signature validation and correct leader (both of these are done in the service.rs i.e. before putting hotshot events onto the da channel) // can use this commitment to match the da proposal or vice-versa - // TODO: if this special value - if qc_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0 || + + // bootstrapping part + // if the view number is 0 then keep going, and don't return from it + if self.built_from_view_vid_leaf.0.get_u64() == 0{ + println!("In bootstrapping phase"); + } + else if qc_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0 || qc_msg.proposal.data.justify_qc.get_data().leaf_commit != self.built_from_view_vid_leaf.2 { println!("Either View number or leaf commit does not match the built-in info, so ignoring it"); return; @@ -332,13 +343,22 @@ impl BuilderProgress for BuilderState{ let leaf_view_number = leaf_chain[0].view_number; - if self.built_from_view_vid_leaf.0 <= leaf_view_number{ + // bootstrapping case + // handle the case when we hear a decide event before we have atleast one clone, in that case, we might exit the builder + // and not make any progress; so we need to handle that case + // Adhoc logic: if the number of subscrived receivers are more than 1, it means that there exists a clone and we can safely exit + if self.built_from_view_vid_leaf.0.get_u64() == 0 && self.tx_receiver.receiver_count() <=1 { + println!("In bootstrapping phase"); + //return Some(Status::ShouldContinue); + } + else if self.built_from_view_vid_leaf.0 <= leaf_view_number{ println!("The decide event is not for the next view, so ignoring it"); // convert leaf commitments into buildercommiments //let leaf_commitments:Vec = leaf_chain.iter().map(|leaf| leaf.get_block_payload().unwrap().builder_commitment(&leaf.get_block_header().metadata())).collect(); // remove the handles from the global state self.global_state.write_arc().await.remove_handles(self.built_from_view_vid_leaf.1, self.builder_commitments.clone()); + return Some(Status::ShouldExit); } @@ -540,9 +560,20 @@ impl BuilderProgress for BuilderState{ MessageType::DecideMessage(rdecide_msg) => { println!("Received decide msg in builder {}: {:?} from index {}", self.builder_keys.0, rdecide_msg, channel_index); // store in the rdecide_msgs - self.process_decide_event(rdecide_msg).await; + let decide_status = self.process_decide_event(rdecide_msg).await; // TODO // if should exit, then break out of the loop + match decide_status{ + Some(Status::ShouldExit) => { + break; + } + Some(Status::ShouldContinue) => { + continue; + } + None => { + continue; + } + } } // DA proposal message diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index c204f45f..75eaa4d4 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -15,7 +15,7 @@ pub use hotshot_testing::{ state_types::{TestInstanceState, TestValidatedState}, }; pub use hotshot_types::{ - traits::node_implementation::NodeType as BuilderType, + traits::node_implementation::{NodeType as BuilderType, ConsensusTime}, data::{ViewNumber, Leaf, DAProposal, QuorumProposal}, simple_certificate::QuorumCertificate, signature_key::{BLSPubKey,BLSPrivKey}, From 6dc46f769f36d2d0688b3b0e73c293a7bfb1d22e Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Wed, 7 Feb 2024 18:45:44 -0500 Subject: [PATCH 28/47] modify test - wip --- src/builder_state.rs | 2 +- src/service.rs | 11 ++++- src/testing/basic_test.rs | 96 +++++++++++++++++++++++++++++++++------ 3 files changed, 91 insertions(+), 18 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 1593826f..f9566d3a 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -257,7 +257,7 @@ impl BuilderProgress for BuilderState{ // generate the vid commitment; num nodes are received through hotshot api in service.rs and passed along with message onto channel let total_nodes = da_msg.total_nodes; - let payload_vid_commitment = vid_commitment(&encoded_txns, total_nodes); + let payload_vid_commitment = vid_commitment(&encoded_txns, total_nodes); if !self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment) { let da_proposal_data = DAProposal { diff --git a/src/service.rs b/src/service.rs index a08a8d12..3dbc7e41 100644 --- a/src/service.rs +++ b/src/service.rs @@ -55,7 +55,7 @@ pub struct GlobalState{ pub block_hash_to_block: HashMap::BlockPayload as BlockPayload>::Metadata, Arc>, <::SignatureKey as SignatureKey>::PureAssembledSignatureType,Types::SignatureKey)>, //pub vid_to_potential_builder_state: HashMap>, - pub request_sender: BroadcastSender, + pub request_sender: BroadcastSender>, pub response_receiver: UnboundedReceiver>, } @@ -67,6 +67,13 @@ impl GlobalState{ self.block_hash_to_block.remove(&block_hash); } } + pub fn new(request_sender: BroadcastSender>, response_receiver: UnboundedReceiver>) -> Self { + GlobalState{ + block_hash_to_block: Default::default(), + request_sender: request_sender, + response_receiver: response_receiver, + } + } } //use hotshot_types::traits::node_implementation::NodeType; @@ -84,7 +91,7 @@ where let req_msg = RequestMessage{ requested_vid_commitment: for_parent.clone(), }; - self.request_sender.broadcast(req_msg).await.unwrap(); + self.request_sender.broadcast(MessageType::RequestMessage(req_msg)).await.unwrap(); let response_received = self.response_receiver.recv().await; match response_received { diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 75eaa4d4..596a0bd4 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -23,7 +23,7 @@ pub use hotshot_types::{ }; pub use hotshot::traits::election::static_committee::{GeneralStaticCommittee, StaticElectionConfig}; -pub use crate::builder_state::{BuilderState,MessageType, BuilderProgress}; +pub use crate::builder_state::{BuilderState,MessageType, BuilderProgress, ResponseMessage}; pub use async_broadcast::{broadcast, TryRecvError, Sender as BroadcastSender, Receiver as BroadcastReceiver, RecvError}; // tests use commit::{Commitment, Committable, CommitmentBoundsArkless}; @@ -34,11 +34,14 @@ mod tests { use core::num; use std::{collections::HashSet, env, hash::Hash, marker::PhantomData}; + use async_compatibility_layer::channel::{unbounded, UnboundedReceiver}; use hotshot::{rand::seq::index, types::SignatureKey}; - use hotshot_types::{data::QuorumProposal, message::Message, traits::block_contents::BlockHeader, vote::HasViewNumber}; - - use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage}; + use hotshot_testing::state_types::TestTypes; + use hotshot_types::{data::QuorumProposal, message::Message, traits::{block_contents::{vid_commitment, BlockHeader}, election::Membership}, vote::HasViewNumber}; + use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage, RequestMessage}; + use crate::service::GlobalState; + use async_lock::RwLock; #[derive(Debug, Clone)] pub struct CustomError{ @@ -47,6 +50,7 @@ mod tests { } use super::*; + const TEST_NUM_NODES_IN_VID_COMPUTATION: usize = 4; /// This test simulates multiple builders receiving messages from the channels and processing them #[async_std::test] async fn test_channel(){ @@ -77,20 +81,27 @@ mod tests { type InstanceState = TestInstanceState; type Membership = GeneralStaticCommittee; } - + // no of test messages to send let num_test_messages = 3; + + // settingup the broadcast channels i.e [From hostshot: (tx, decide, da, qc, )], [From api:(req - broadcast, res - mpsc channel) ] let (tx_sender, tx_receiver) = broadcast::>(num_test_messages*2); let (decide_sender, decide_receiver) = broadcast::>(num_test_messages*2); let (da_sender, da_receiver) = broadcast::>(num_test_messages*2); let (qc_sender, qc_receiver) = broadcast::>(num_test_messages*2); let (req_sender, req_receiver) = broadcast::>(num_test_messages*2); - - + let (res_sender, res_receiver) = unbounded(); + + // to store all the sent messages let mut stx_msgs = Vec::new(); let mut sdecide_msgs = Vec::new(); let mut sda_msgs = Vec::new(); let mut sqc_msgs = Vec::new(); - // generate 5 messages for each type and send it to the respective channels + let mut sreq_msgs = Vec::new(); + let mut sres_msgs: Vec> = Vec::new(); + + + // generate num_test messages for each type and send it to the respective channels; for i in 0..num_test_messages as u32{ // pass a msg to the tx channel let tx = TestTransaction(vec![i as u8]); @@ -124,7 +135,7 @@ mod tests { &private_key, &encoded_transactions_hash, ) - .expect("Failed to sign tx hash"); + .expect("Failed to sign encoded tx hash while preparing da proposal"); let sda_msg = DAProposalMessage::{ proposal: Proposal{ data: da_proposal, @@ -135,37 +146,92 @@ mod tests { total_nodes: 8, }; + // calculate the vid commitment over the encoded_transactions + let encoded_txns_vid_commitment = vid_commitment(&encoded_transactions, TEST_NUM_NODES_IN_VID_COMPUTATION); + let block_header = TestBlockHeader{ + block_number: i as u64, + payload_commitment: encoded_txns_vid_commitment, + }; // Prepare the QC proposal message - - let qc_signature = da_signature.clone(); + //let qc_signature = da_signature.clone(); let qc_proposal = QuorumProposal::{ - block_header: TestBlockHeader::genesis(&TestInstanceState {}).0, + //block_header: TestBlockHeader::genesis(&TestInstanceState {}).0, + block_header: block_header, view_number: ViewNumber::new(i as u64), justify_qc: QuorumCertificate::::genesis(), timeout_certificate: None, proposer_id: pub_key }; + let payload_commitment = qc_proposal.block_header.payload_commitment(); + + // let leaf_commit = qc_proposal.justify_qc.data.commit(); + let qc_signature = ::SignatureKey::sign( + &private_key, + payload_commitment.as_ref(), + ).expect("Failed to sign payload commitment while preparing QC proposal"); + + let requested_vid_commitment = qc_proposal.block_header.payload_commitment(); + let sqc_msg = QCMessage::{ proposal: Proposal{ data:qc_proposal, signature: qc_signature, _pd: PhantomData - }, + }, sender: pub_key, }; + // validate the signature before pushing the message to the builder_state channels + // currently this step happens in the service.rs, wheneve we receiver an hotshot event tx_sender.broadcast(MessageType::TransactionMessage(stx_msg.clone())).await.unwrap(); decide_sender.broadcast(MessageType::DecideMessage(sdecide_msg.clone())).await.unwrap(); da_sender.broadcast(MessageType::DAProposalMessage(sda_msg.clone())).await.unwrap(); qc_sender.broadcast(MessageType::QCMessage(sqc_msg.clone())).await.unwrap(); + //TODO: sending request message onto channel also + // send the request message as well + let request_message = MessageType::::RequestMessage(RequestMessage{ + requested_vid_commitment: requested_vid_commitment, + }); + stx_msgs.push(stx_msg); sdecide_msgs.push(sdecide_msg); sda_msgs.push(sda_msg); sqc_msgs.push(sqc_msg); + sreq_msgs.push(request_message); + } + + // instantiate the global state also + let global_state = Arc::new(RwLock::new(GlobalState::::new(req_sender, res_receiver))); + + let seed = [201 as u8; 32]; + let (builder_pub_key, builder_private_key) = BLSPubKey::generated_from_seed_indexed(seed,2011 as u64); + + let quorum_election_config = <::Membership as Membership>::default_election_config(TEST_NUM_NODES_IN_VID_COMPUTATION as u64); + + let mut commitee_stake_table_entries = vec![]; + for i in 0..TEST_NUM_NODES_IN_VID_COMPUTATION { + let (pub_key, private_key) = BLSPubKey::generated_from_seed_indexed([i as u8; 32],i as u64); + let stake = i as u64; + commitee_stake_table_entries.push(pub_key.get_stake_table_entry(stake)); + } + + let quorum_membershiop = <::Membership as Membership>::create_election( + commitee_stake_table_entries, + quorum_election_config + ); - } + assert!(quorum_membershiop.total_nodes() == TEST_NUM_NODES_IN_VID_COMPUTATION); + + // let mut builder_state = BuilderState::::new((builder_pub__key, builder_private_key), + // (ViewNumber::new(0), genesis_vid_commitment(), Commitment::>::default_commitment_no_preimage()), + // tx_receiver, decide_receiver, da_receiver, qc_receiver, req_receiver, global_state, res_sender, quorum_membershiop); + + + + + /* // spwan 10 builder instances, later try receing on each of the instance let mut handles = Vec::new(); for i in 0..2 { @@ -336,6 +402,6 @@ mod tests { for handle in handles { handle.await; } - + */ } } From 8ba8f85a9034d8641c10e774835f02e7b7d0d1d6 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Wed, 7 Feb 2024 18:56:14 -0500 Subject: [PATCH 29/47] add builder state initilisation --- src/testing/basic_test.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 596a0bd4..1bb6b0d1 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -224,9 +224,9 @@ mod tests { assert!(quorum_membershiop.total_nodes() == TEST_NUM_NODES_IN_VID_COMPUTATION); - // let mut builder_state = BuilderState::::new((builder_pub__key, builder_private_key), - // (ViewNumber::new(0), genesis_vid_commitment(), Commitment::>::default_commitment_no_preimage()), - // tx_receiver, decide_receiver, da_receiver, qc_receiver, req_receiver, global_state, res_sender, quorum_membershiop); + let mut builder_state = BuilderState::::new((builder_pub_key, builder_private_key), + (ViewNumber::new(0), genesis_vid_commitment(), Commitment::>::default_commitment_no_preimage()), + tx_receiver, decide_receiver, da_receiver, qc_receiver, req_receiver, global_state, res_sender, Arc::new(quorum_membershiop)); From c0f95e7f414f4a7eb9129269f97de7eaba180d28 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Wed, 7 Feb 2024 19:25:06 -0500 Subject: [PATCH 30/47] add wip test --- src/builder_state.rs | 13 +++++++++---- src/testing/basic_test.rs | 6 +++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index f9566d3a..dea551a6 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -397,6 +397,7 @@ impl BuilderProgress for BuilderState{ // spawn a clone of the builder state async fn spawn_clone(mut self, da_proposal: DAProposal, quorum_proposal: QuorumProposal, leader: TYPES::SignatureKey) { + println!("Spawning a clone"); self.built_from_view_vid_leaf.0 = quorum_proposal.view_number; self.built_from_view_vid_leaf.1 = quorum_proposal.block_header.payload_commitment(); @@ -518,10 +519,12 @@ impl BuilderProgress for BuilderState{ } async fn event_loop(mut self) { - task::spawn(async move{ + let builder_handle = task::spawn(async move{ loop{ + println!("In event loop"); //let builder_state = builder_state.lock().unwrap(); - while let Ok(req) = self.req_receiver.recv().await { + while let Ok(req) = self.req_receiver.try_recv() { + println!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); if let MessageType::RequestMessage(req) = req { self.process_block_request(req).await; } @@ -598,8 +601,10 @@ impl BuilderProgress for BuilderState{ } } - } - }); + }; + }); + + builder_handle.await; } } /// Unifies the possible messages that can be received by the builder diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 1bb6b0d1..e6b58293 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -116,7 +116,7 @@ mod tests { // Prepare the decide message let qc = QuorumCertificate::::genesis(); let sdecide_msg = DecideMessage::{ - leaf_chain: Arc::new(vec![]), + leaf_chain: Arc::new(vec![Leaf::genesis(&TestInstanceState {})]), qc: Arc::new(qc), block_size: Some(i as u64), }; @@ -222,14 +222,14 @@ mod tests { quorum_election_config ); - assert!(quorum_membershiop.total_nodes() == TEST_NUM_NODES_IN_VID_COMPUTATION); + assert_eq!(quorum_membershiop.total_nodes(), TEST_NUM_NODES_IN_VID_COMPUTATION); let mut builder_state = BuilderState::::new((builder_pub_key, builder_private_key), (ViewNumber::new(0), genesis_vid_commitment(), Commitment::>::default_commitment_no_preimage()), tx_receiver, decide_receiver, da_receiver, qc_receiver, req_receiver, global_state, res_sender, Arc::new(quorum_membershiop)); - + builder_state.event_loop().await; /* // spwan 10 builder instances, later try receing on each of the instance From 39e9803f251a34dadac0c98d0cbc1307354bddc1 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Thu, 8 Feb 2024 23:37:37 -0500 Subject: [PATCH 31/47] wip testing --- Cargo.toml | 3 +- src/builder_state.rs | 232 +++++++++++++++++++++++++++++++++++--- src/testing/basic_test.rs | 209 ++++------------------------------ 3 files changed, 238 insertions(+), 206 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0ae63130..d4b243ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,4 +48,5 @@ jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish" } #hs-builder-api = {git = "https://github.com/EspressoSystems/hs-builder-api", branch="main"} hs-builder-api = {path="../hs-builder-api"} -tagged-base64 = { git = "https://github.com/EspressoSystems/tagged-base64", tag = "0.3.4" } \ No newline at end of file +tagged-base64 = { git = "https://github.com/EspressoSystems/tagged-base64", tag = "0.3.4" } +futures-lite = "2.2.0" \ No newline at end of file diff --git a/src/builder_state.rs b/src/builder_state.rs index dea551a6..350c05d7 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -10,7 +10,7 @@ // including the following from the hotshot use hotshot_types::{ traits::{node_implementation::{NodeType as BuilderType,ConsensusTime}, block_contents::vid_commitment, signature_key::SignatureKey}, - data::{DAProposal, Leaf, QuorumProposal, VidCommitment, VidScheme, VidSchemeTrait, test_srs}, + data::{DAProposal, Leaf, QuorumProposal, VidCommitment, VidScheme, VidSchemeTrait, test_srs, ViewNumber}, simple_certificate::QuorumCertificate, message::Proposal, traits::{block_contents::{BlockPayload, BlockHeader}, election::Membership}, @@ -20,13 +20,15 @@ use hotshot_types::{ //use jf_primitives::signatures::bls_over_bn254::{SignKey, VerKey}; use commit::{Commitment, Committable}; -use futures::future::select_all; +use futures::{future, StreamExt};//::select_all; use async_std::task::JoinHandle; use async_broadcast::{Receiver as BroadcastReceiver, RecvError}; use async_std::task; use async_trait::async_trait; use async_compatibility_layer::channel:: UnboundedSender; use async_lock::RwLock; +//use futures_lite::{future::block_on, stream::StreamExt}; +use futures::stream;//::{select, select_all}; //use sha2::digest::crypto_common::rand_core::block; use std::collections::hash_map::Entry; @@ -178,6 +180,7 @@ pub trait BuilderProgress { /// process the block request async fn process_block_request(&mut self, req: RequestMessage); + } @@ -256,9 +259,9 @@ impl BuilderProgress for BuilderState{ // generate the vid commitment; num nodes are received through hotshot api in service.rs and passed along with message onto channel let total_nodes = da_msg.total_nodes; - + println!("Encoded txns in da proposal: {:?} and total nodes: {:?}", encoded_txns, total_nodes); let payload_vid_commitment = vid_commitment(&encoded_txns, total_nodes); - + println!("Generated payload commitment from the da proposal: {:?}", payload_vid_commitment); if !self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment) { let da_proposal_data = DAProposal { encoded_transactions: encoded_txns.clone(), @@ -306,7 +309,7 @@ impl BuilderProgress for BuilderState{ let sender = qc_msg.sender; let payload_vid_commitment = qc_proposal_data.block_header.payload_commitment(); - + println!("Extracted payload commitment from the quorum proposal: {:?}", payload_vid_commitment); // first check whether vid_commitment exists in the qc_payload_commit_to_qc hashmap, if yer, ignore it, otherwise validate it and later insert in if !self.quorum_proposal_payload_commit_to_quorum_proposal.contains_key(&payload_vid_commitment){ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. @@ -518,23 +521,188 @@ impl BuilderProgress for BuilderState{ } } - async fn event_loop(mut self) { + async fn event_loop(mut self){ + let builder_handle = task::spawn(async move{ - loop{ - println!("In event loop"); - //let builder_state = builder_state.lock().unwrap(); - while let Ok(req) = self.req_receiver.try_recv() { - println!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); - if let MessageType::RequestMessage(req) = req { - self.process_block_request(req).await; + + //let mut x = futures::stream::select(self.tx_receiver, self.da_proposal_receiver); + + loop{ + + // print 10 times the builderstate.built_from_view_vid_leaf and then sleep for some time + // for i in 0..10{ + // println!("In event loop for {:?}", self.built_from_view_vid_leaf); + // } + //task::sleep(std::time::Duration::from_secs(1)).await; + + + /* + if let Ok(tx) = self.tx_receiver.try_recv(){ + println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, tx); + if let MessageType::TransactionMessage(rtx_msg) = tx{ + if rtx_msg.tx_type == TransactionSource::HotShot { + self.process_hotshot_transaction(rtx_msg.tx).await; + } else { + self.process_external_transaction(rtx_msg.tx).await; + } + } + } + + if let Ok(da) = self.da_proposal_receiver.try_recv(){ + println!("Received da proposal msg in builder {}: {:?} from index", self.builder_keys.0, da); + if let MessageType::DAProposalMessage(rda_msg) = da{ + self.process_da_proposal(rda_msg).await; + } + } + + if let Ok(qc) = self.qc_receiver.try_recv(){ + println!("Received qc msg in builder {}: {:?} from index", self.builder_keys.0, qc); + if let MessageType::QCMessage(rqc_msg) = qc{ + self.process_quorum_proposal(rqc_msg).await; + } + } + + if let Ok(decide) = self.decide_receiver.try_recv(){ + println!("Received decide msg in builder {}: {:?} from index", self.builder_keys.0, decide); + if let MessageType::DecideMessage(rdecide_msg) = decide{ + let decide_status = self.process_decide_event(rdecide_msg).await; + match decide_status{ + Some(Status::ShouldExit) => { + break; + } + Some(Status::ShouldContinue) => { + continue; + } + None => { + continue; + } + } + } + } + + */ + + // println!("In event loop for {:?}", self.built_from_view_vid_leaf); + // println!("Receiver count: {:?}", self.tx_receiver.receiver_count()); + // //let builder_state = builder_state.lock().unwrap(); + // while let Ok(req) = self.req_receiver.try_recv() { + // println!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); + // if let MessageType::RequestMessage(req) = req { + // self.process_block_request(req).await; + // } + // }; + + // let (received_msg, channel_index, _)= future::select_all([self.tx_receiver.recv(), self.da_proposal_receiver.recv(), + // self.qc_receiver.recv(), self.decide_receiver.recv(),self.req_receiver.recv()]).await; + //let y = x.next().await; + //println!("Received message: {:?}", y); + println!("In event loop for {:?}", self.built_from_view_vid_leaf); + + + + futures::select!{ + tx = self.tx_receiver.next() => { + //println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, tx); + match tx { + Some(tx) => { + if let MessageType::TransactionMessage(rtx_msg) = tx { + println!("Received tx msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rtx_msg); + if rtx_msg.tx_type == TransactionSource::HotShot { + self.process_hotshot_transaction(rtx_msg.tx).await; + } else { + self.process_external_transaction(rtx_msg.tx).await; + } + } + } + None => { + println!("No more tx messages to consume"); + } + } + } + da = self.da_proposal_receiver.next() => { + //println!("Received da proposal msg in builder {}: {:?} from index", self.builder_keys.0, da); + match da { + Some(da) => { + if let MessageType::DAProposalMessage(rda_msg) = da { + println!("Received da proposal msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rda_msg.proposal.data.view_number); + self.process_da_proposal(rda_msg).await; + } + } + None => { + println!("No more da proposal messages to consume"); + } + } + } + qc = self.qc_receiver.next() => { + //println!("Received qc msg in builder {}: {:?} from index", self.builder_keys.0, qc); + match qc { + Some(qc) => { + if let MessageType::QCMessage(rqc_msg) = qc { + println!("Received qc msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rqc_msg.proposal.data.view_number); + self.process_quorum_proposal(rqc_msg).await; + } + } + None => { + println!("No more qc messages to consume"); + } + } + } + decide = self.decide_receiver.next() => { + println!("Received decide msg in builder {}: {:?} from index", self.builder_keys.0, decide); + match decide { + Some(decide) => { + if let MessageType::DecideMessage(rdecide_msg) = decide { + println!("Received decide msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rdecide_msg); + let decide_status = self.process_decide_event(rdecide_msg).await; + match decide_status{ + Some(Status::ShouldExit) => { + break; + } + Some(Status::ShouldContinue) => { + continue; + } + None => { + continue; + } + } + } + } + None => { + println!("No more decide messages to consume"); + } + } } }; + + + // let (received_msg, channel_index, _)= select_all([self.tx_receiver.next().await, self.da_proposal_receiver.next().await, + // self.qc_receiver.next().await, self.decide_receiver.next().await,self.req_receiver.next().await]); - let (received_msg, channel_index, _)= select_all([self.tx_receiver.recv(), self.decide_receiver.recv(), self.da_proposal_receiver.recv(), - self.qc_receiver.recv(), self.req_receiver.recv()]).await; + // let mut x = select_all([self.tx_receiver.into_stream(), self.da_proposal_receiver, + // self.qc_receiver, self.decide_receiver,self.req_receiver]); + // select! { + // received_tx_msg = self.tx_receiver.next().await.unwrap()=> { + // println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, received_tx_msg); + // if let Some(received_tx_msg) = received_tx_msg { + // if let MessageType::TransactionMessage(rtx_msg) = received_tx_msg { + // println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, rtx_msg); + // if rtx_msg.tx_type == TransactionSource::HotShot { + // self.process_hotshot_transaction(rtx_msg.tx).await; + // } else { + // self.process_external_transaction(rtx_msg.tx).await; + // } + // } + // } + // } + // } + + /* + let (received_msg, channel_index, _)= future::select_all([self.tx_receiver.recv(), self.da_proposal_receiver.recv(), + self.qc_receiver.recv(), self.decide_receiver.recv(),self.req_receiver.recv()]).await; match received_msg { Ok(received_msg) => { + match received_msg { // request message @@ -549,13 +717,20 @@ impl BuilderProgress for BuilderState{ MessageType::TransactionMessage(rtx_msg) => { println!("Received tx msg in builder {}: {:?} from index {}", self.builder_keys.0, rtx_msg, channel_index); + //self.print_builder_state().await; // get the content from the rtx_msg's inside vec // Pass the tx msg to the handler + println!("Local tx_maps before processing the transaction:\n Tx_hash_to_available_txns: {:?} \nTimestamp to tx {:?}\n Included txns{:?}", + self.tx_hash_to_available_txns, self.timestamp_to_tx, self.included_txns); + if rtx_msg.tx_type == TransactionSource::HotShot { self.process_hotshot_transaction(rtx_msg.tx).await; } else { self.process_external_transaction(rtx_msg.tx).await; } + //self.print_builder_state().await; + println!("Local tx_maps after processing the transaction:\n Tx_hash_to_available_txns: {:?} \nTimestamp to tx {:?}\n Included txns{:?}", + self.tx_hash_to_available_txns, self.timestamp_to_tx, self.included_txns); } @@ -563,7 +738,9 @@ impl BuilderProgress for BuilderState{ MessageType::DecideMessage(rdecide_msg) => { println!("Received decide msg in builder {}: {:?} from index {}", self.builder_keys.0, rdecide_msg, channel_index); // store in the rdecide_msgs + //self.print_builder_state().await; let decide_status = self.process_decide_event(rdecide_msg).await; + //self.print_builder_state().await; // TODO // if should exit, then break out of the loop match decide_status{ @@ -582,29 +759,48 @@ impl BuilderProgress for BuilderState{ // DA proposal message MessageType::DAProposalMessage(rda_msg) => { println!("Received da proposal msg in builder {}: {:?} from index {}", self.builder_keys.0, rda_msg, channel_index); - + //self.print_builder_state().await; + // print only the keys in self.da_proposal_payload_commit_to_da_proposal map + println!("DA proposal payload commit to da proposal map keys before processing: {:?}", self.da_proposal_payload_commit_to_da_proposal.keys()); self.process_da_proposal(rda_msg).await; + println!("DA proposal payload commit to da proposal map keys after processing: {:?}", self.da_proposal_payload_commit_to_da_proposal.keys()); + //self.print_builder_state().await; + } // QC proposal message MessageType::QCMessage(rqc_msg) => { println!("Received qc msg in builder {}: {:?} from index {}", self.builder_keys.0, rqc_msg, channel_index); + //self.print_builder_state().await; + println!("QC proposal payload commit to QC proposal map keys before processing: {:?}", self.quorum_proposal_payload_commit_to_quorum_proposal.keys()); self.process_quorum_proposal(rqc_msg).await; + println!("QC proposal payload commit to QC proposal map keys before processing: {:?}", self.quorum_proposal_payload_commit_to_quorum_proposal.keys()); + + //self.print_builder_state().await; } } + } Err(err) => { + println!("Error in builder event loop: {:?}", err); if err == RecvError::Closed { println!("The channel {} is closed", channel_index); //break; //channel_close_index.insert(channel_index); } + else{ + println!("No more messages to consume {}", channel_index); + break; + } } } - + + */ }; + }); - + builder_handle.await; + } } /// Unifies the possible messages that can be received by the builder diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index e6b58293..2f0902fa 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -83,14 +83,15 @@ mod tests { } // no of test messages to send let num_test_messages = 3; + let multiplication_factor = 5; // settingup the broadcast channels i.e [From hostshot: (tx, decide, da, qc, )], [From api:(req - broadcast, res - mpsc channel) ] - let (tx_sender, tx_receiver) = broadcast::>(num_test_messages*2); - let (decide_sender, decide_receiver) = broadcast::>(num_test_messages*2); - let (da_sender, da_receiver) = broadcast::>(num_test_messages*2); - let (qc_sender, qc_receiver) = broadcast::>(num_test_messages*2); - let (req_sender, req_receiver) = broadcast::>(num_test_messages*2); - let (res_sender, res_receiver) = unbounded(); + let (tx_sender, mut tx_receiver) = broadcast::>(num_test_messages*multiplication_factor); + let (decide_sender, mut decide_receiver) = broadcast::>(num_test_messages*multiplication_factor); + let (da_sender, mut da_receiver) = broadcast::>(num_test_messages*multiplication_factor); + let (qc_sender, mut qc_receiver) = broadcast::>(num_test_messages*multiplication_factor); + let (req_sender, mut req_receiver) = broadcast::>(num_test_messages*multiplication_factor); + let (res_sender, mut res_receiver) = unbounded(); // to store all the sent messages let mut stx_msgs = Vec::new(); @@ -125,7 +126,7 @@ mod tests { let da_proposal = DAProposal { encoded_transactions: encoded_transactions.clone(), metadata: (), - view_number: ViewNumber::new(i as u64), + view_number: ViewNumber::new((i+1) as u64), }; let encoded_transactions_hash = Sha256::digest(&encoded_transactions); let seed = [i as u8; 32]; @@ -143,11 +144,13 @@ mod tests { _pd: PhantomData }, sender: pub_key, - total_nodes: 8, + total_nodes: TEST_NUM_NODES_IN_VID_COMPUTATION, }; // calculate the vid commitment over the encoded_transactions + println!("Encoded transactions: {:?}\n Num nodes:{}", encoded_transactions, TEST_NUM_NODES_IN_VID_COMPUTATION); let encoded_txns_vid_commitment = vid_commitment(&encoded_transactions, TEST_NUM_NODES_IN_VID_COMPUTATION); + println!("Encoded transactions vid commitment: {:?}", encoded_txns_vid_commitment); let block_header = TestBlockHeader{ block_number: i as u64, payload_commitment: encoded_txns_vid_commitment, @@ -157,7 +160,7 @@ mod tests { let qc_proposal = QuorumProposal::{ //block_header: TestBlockHeader::genesis(&TestInstanceState {}).0, block_header: block_header, - view_number: ViewNumber::new(i as u64), + view_number: ViewNumber::new((i+1) as u64), justify_qc: QuorumCertificate::::genesis(), timeout_certificate: None, proposer_id: pub_key @@ -185,9 +188,9 @@ mod tests { // validate the signature before pushing the message to the builder_state channels // currently this step happens in the service.rs, wheneve we receiver an hotshot event tx_sender.broadcast(MessageType::TransactionMessage(stx_msg.clone())).await.unwrap(); - decide_sender.broadcast(MessageType::DecideMessage(sdecide_msg.clone())).await.unwrap(); da_sender.broadcast(MessageType::DAProposalMessage(sda_msg.clone())).await.unwrap(); qc_sender.broadcast(MessageType::QCMessage(sqc_msg.clone())).await.unwrap(); + //decide_sender.broadcast(MessageType::DecideMessage(sdecide_msg.clone())).await.unwrap(); //TODO: sending request message onto channel also // send the request message as well @@ -224,184 +227,16 @@ mod tests { assert_eq!(quorum_membershiop.total_nodes(), TEST_NUM_NODES_IN_VID_COMPUTATION); - let mut builder_state = BuilderState::::new((builder_pub_key, builder_private_key), - (ViewNumber::new(0), genesis_vid_commitment(), Commitment::>::default_commitment_no_preimage()), - tx_receiver, decide_receiver, da_receiver, qc_receiver, req_receiver, global_state, res_sender, Arc::new(quorum_membershiop)); - - - builder_state.event_loop().await; - - /* - // spwan 10 builder instances, later try receing on each of the instance - let mut handles = Vec::new(); - for i in 0..2 { - - let tx_receiver_clone = tx_receiver.clone(); - let decide_receiver_clone = decide_receiver.clone(); - let da_receiver_clone = da_receiver.clone(); - let qc_receiver_clone = qc_receiver.clone(); - let req_receiver_clone = req_receiver.clone(); - - let stx_msgs: Vec> = stx_msgs.clone(); - let sdecide_msgs: Vec> = sdecide_msgs.clone(); - let sda_msgs: Vec> = sda_msgs.clone(); - let sqc_msgs: Vec> = sqc_msgs.clone(); - - let mut builder_state = Arc::new(Mutex::new(BuilderState::::new((pub_key, private_key), built_from_view_vid_leaf, tx_receiver_clone, decide_receiver_clone, da_receiver_clone, qc_receiver_clone, req_receiver_clone))); - - // TODO clone a handle and check it contains the remaining messages and don't contain the messages before cloning it - let handle = task::spawn(async move { - - let built_from_view_vid_leaf = (ViewNumber::new(i as u64), genesis_vid_commitment(), Commitment::>::default_commitment_no_preimage()); - - let (pub_key, private_key) = BLSPubKey::generated_from_seed_indexed([i as u8; 32],i as u64); - - let mut builder_state = BuilderState::::new((pub_key, private_key), built_from_view_vid_leaf, - tx_receiver_clone, decide_receiver_clone, da_receiver_clone, - qc_receiver_clone, req_receiver_clone); - - // to keep track of the messages received by the builder - let mut rtx_msgs: Vec> = Vec::new(); - let mut rdecide_msgs:Vec> = Vec::new(); - let mut rda_msgs:Vec> = Vec::new(); - let mut rqc_msgs:Vec> = Vec::new(); - let mut channel_close_index = HashSet::::new(); - //let shared_builder_state = Arc::clone(&builder_state); + let handle = task::spawn(async move{ + let mut builder_state = BuilderState::::new((builder_pub_key, builder_private_key), + (ViewNumber::new(0), genesis_vid_commitment(), Commitment::>::default_commitment_no_preimage()), + tx_receiver, decide_receiver, da_receiver, qc_receiver, req_receiver, global_state, res_sender, Arc::new(quorum_membershiop)); - loop{ - - //let builder_state = builder_state.lock().unwrap(); - while let Ok(req) = builder_state.req_receiver.recv().await { - println!("Received request in builder {}: {:?}", i, req); - if let MessageType::RequestMessage(req) = req { - - let requested_vid_commitment = req.requested_vid_commitment; - - } - // //... handle requests - // // it says do I have a block for this set of txns? if so, return that header?? MPSC [async_compatility] - // // else iterate through and call build block, and add block to blockmap in globalstate - // // do validity check for the requester as well i.e are they leader for one of the next k views - - } - - - // unlock the builder state - //let mut builder_state = builder_state.lock().unwrap(); - - let (received_msg, channel_index, _)= select_all([builder_state.tx_receiver.recv(), - builder_state.decide_receiver.recv(), builder_state.da_proposal_receiver.recv(), - builder_state.qc_receiver.recv(), builder_state.req_receiver.recv()]).await; - - match received_msg { - Ok(received_msg) => { - match received_msg { - - // request message - MessageType::RequestMessage(req) => { - println!("Received request msg in builder {}: {:?} from index {}", i, req, channel_index); - // store in the rtx_msgs - //rreq_msgs.push(req.clone()); - //builder_state.process_request(req).await; - } - - // transaction message - MessageType::TransactionMessage(rtx_msg) => { - println!("Received tx msg in builder {}: {:?} from index {}", i, rtx_msg, channel_index); - // store in the rtx_msgs - rtx_msgs.push(rtx_msg.clone()); - - // get the content from the rtx_msg's inside vec - let index = rtx_msg.tx.0[0] as usize; - //println!("Received tx msg from builder {}: {:?} from index {}", i, rtx_msg, index); - assert_eq!(stx_msgs.get(index).unwrap().tx.commit(), rtx_msg.tx.commit()); - // Pass the tx msg to the handler - if rtx_msg.tx_type == TransactionSource::HotShot { - builder_state.process_hotshot_transaction(rtx_msg.tx).await; - } else { - builder_state.process_external_transaction(rtx_msg.tx).await; - } - - } - - // decide message - MessageType::DecideMessage(rdecide_msg) => { - println!("Received decide msg in builder {}: {:?} from index {}", i, rdecide_msg, channel_index); - // store in the rdecide_msgs - rdecide_msgs.push(rdecide_msg.clone()); - - //println!("Received decide msg from builder {}: {:?} from index {}", i, rdecide_msg, index); - assert_eq!(sdecide_msgs.get(rdecide_msg.block_size.unwrap() as usize).unwrap().block_size, rdecide_msg.block_size); - builder_state.process_decide_event(rdecide_msg).await; - } - - // DA proposal message - MessageType::DAProposalMessage(rda_msg) => { - println!("Received da msg in builder {}: {:?} from index {}", i, rda_msg, channel_index); - // store in the rda_msgs - rda_msgs.push(rda_msg.clone()); - - //println!("Received da msg from builder {}: {:?} from index {}", i, rda_msg, index); - let view_number = rda_msg.proposal.data.get_view_number().get_u64(); - assert_eq!(sda_msgs.get(view_number as usize).unwrap().proposal.data.view_number.get_u64(), rda_msg.proposal.data.view_number.get_u64()); - builder_state.process_da_proposal(rda_msg).await; - } - - // QC proposal message - MessageType::QCMessage(rqc_msg) => { - println!("Received qc msg in builder {}: {:?} from index {}", i, rqc_msg, channel_index); - // store in the rqc_msgs - rqc_msgs.push(rqc_msg.clone()); - - //println!("Received qc msg from builder {}: {:?} from index {}", i, rqc_msg, index); - let view_number = rqc_msg.proposal.data.get_view_number().get_u64(); - assert_eq!(sqc_msgs.get(view_number as usize).unwrap().proposal.data.view_number.get_u64(), rqc_msg.proposal.data.view_number.get_u64()); - builder_state.process_quorum_proposal(rqc_msg).await; - } - } - } - Err(err) => { - if err == RecvError::Closed { - println!("The channel {} is closed", channel_index); - //break; - channel_close_index.insert(channel_index); - } - } - } - // all the messages are received in rx_msga - if rtx_msgs.len() == num_test_messages && rdecide_msgs.len() == num_test_messages && rda_msgs.len() == num_test_messages && rqc_msgs.len() == num_test_messages { - break; - } - } - - // now go through the content of stx_msgs and rtx_msgs and check if they are same - for i in 0..stx_msgs.len() { - assert_eq!(stx_msgs.get(i).unwrap().tx.commit(), rtx_msgs.get(i).unwrap().tx.commit()); - } - - // now go through the content of sdecide_msgs and rdecide_msgs and check if they are same - for i in 0..sdecide_msgs.len() { - assert_eq!(sdecide_msgs.get(i).unwrap().block_size, rdecide_msgs.get(i).unwrap().block_size); - } - - // now go through the content of sda_msgs and rda_msgs and check if they are same - for i in 0..sda_msgs.len() { - assert_eq!(sda_msgs.get(i).unwrap().proposal.data.view_number.get_u64(), rda_msgs.get(i).unwrap().proposal.data.view_number.get_u64()); - } - - // now go through the content of sqc_msgs and rqc_msgs and check if they are same - for i in 0..sqc_msgs.len() { - assert_eq!(sqc_msgs.get(i).unwrap().proposal.data.view_number.get_u64(), rqc_msgs.get(i).unwrap().proposal.data.view_number.get_u64()); - } - - }); - handles.push(handle); - } - - for handle in handles { - handle.await; - } - */ + //builder_state.event_loop().await; + builder_state.event_loop().await; + }); + handle.await; + } } From 77c1e6413357d578c556f231ed817afc734601a8 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 9 Feb 2024 11:10:19 -0500 Subject: [PATCH 32/47] wip test --- src/builder_state.rs | 516 +++++++++++++++++++++++-------------------- 1 file changed, 272 insertions(+), 244 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 350c05d7..394b88b2 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -181,6 +181,9 @@ pub trait BuilderProgress { /// process the block request async fn process_block_request(&mut self, req: RequestMessage); + /// loop function + async fn loop_function(&mut self); + } @@ -275,8 +278,12 @@ impl BuilderProgress for BuilderState{ //let self_clone = self.clone(); - self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; - + //self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; + let self_clone = self.clone(); + + task::spawn(async move { + self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await + }).await; // register the clone to the global state //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); } else { @@ -316,7 +323,11 @@ impl BuilderProgress for BuilderState{ if let Entry::Occupied(da_proposal_data) = self.da_proposal_payload_commit_to_da_proposal.entry(payload_vid_commitment.clone()) { let da_proposal_data = da_proposal_data.remove(); //let self_clone = self.clone(); - self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; + let self_clone = self.clone(); + + task::spawn(async move { + self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await + }).await; // registed the clone to the global state //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); @@ -521,285 +532,302 @@ impl BuilderProgress for BuilderState{ } } - async fn event_loop(mut self){ - - let builder_handle = task::spawn(async move{ - - //let mut x = futures::stream::select(self.tx_receiver, self.da_proposal_receiver); - - loop{ + async fn loop_function(&mut self){ + loop{ - // print 10 times the builderstate.built_from_view_vid_leaf and then sleep for some time - // for i in 0..10{ - // println!("In event loop for {:?}", self.built_from_view_vid_leaf); - // } - //task::sleep(std::time::Duration::from_secs(1)).await; + // print 10 times the builderstate.built_from_view_vid_leaf and then sleep for some time + // for i in 0..10{ + // println!("In event loop for {:?}", self.built_from_view_vid_leaf); + // } + //task::sleep(std::time::Duration::from_secs(1)).await; - /* - if let Ok(tx) = self.tx_receiver.try_recv(){ - println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, tx); - if let MessageType::TransactionMessage(rtx_msg) = tx{ - if rtx_msg.tx_type == TransactionSource::HotShot { - self.process_hotshot_transaction(rtx_msg.tx).await; - } else { - self.process_external_transaction(rtx_msg.tx).await; - } - } + /* + if let Ok(tx) = self.tx_receiver.try_recv(){ + println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, tx); + if let MessageType::TransactionMessage(rtx_msg) = tx{ + if rtx_msg.tx_type == TransactionSource::HotShot { + self.process_hotshot_transaction(rtx_msg.tx).await; + } else { + self.process_external_transaction(rtx_msg.tx).await; } + } + } - if let Ok(da) = self.da_proposal_receiver.try_recv(){ - println!("Received da proposal msg in builder {}: {:?} from index", self.builder_keys.0, da); - if let MessageType::DAProposalMessage(rda_msg) = da{ - self.process_da_proposal(rda_msg).await; - } - } + if let Ok(da) = self.da_proposal_receiver.try_recv(){ + println!("Received da proposal msg in builder {}: {:?} from index", self.builder_keys.0, da); + if let MessageType::DAProposalMessage(rda_msg) = da{ + self.process_da_proposal(rda_msg).await; + } + } - if let Ok(qc) = self.qc_receiver.try_recv(){ - println!("Received qc msg in builder {}: {:?} from index", self.builder_keys.0, qc); - if let MessageType::QCMessage(rqc_msg) = qc{ - self.process_quorum_proposal(rqc_msg).await; + if let Ok(qc) = self.qc_receiver.try_recv(){ + println!("Received qc msg in builder {}: {:?} from index", self.builder_keys.0, qc); + if let MessageType::QCMessage(rqc_msg) = qc{ + self.process_quorum_proposal(rqc_msg).await; + } + } + + if let Ok(decide) = self.decide_receiver.try_recv(){ + println!("Received decide msg in builder {}: {:?} from index", self.builder_keys.0, decide); + if let MessageType::DecideMessage(rdecide_msg) = decide{ + let decide_status = self.process_decide_event(rdecide_msg).await; + match decide_status{ + Some(Status::ShouldExit) => { + break; + } + Some(Status::ShouldContinue) => { + continue; + } + None => { + continue; } } - - if let Ok(decide) = self.decide_receiver.try_recv(){ - println!("Received decide msg in builder {}: {:?} from index", self.builder_keys.0, decide); - if let MessageType::DecideMessage(rdecide_msg) = decide{ - let decide_status = self.process_decide_event(rdecide_msg).await; - match decide_status{ - Some(Status::ShouldExit) => { - break; - } - Some(Status::ShouldContinue) => { - continue; - } - None => { - continue; + } + } + + */ + + // println!("In event loop for {:?}", self.built_from_view_vid_leaf); + // println!("Receiver count: {:?}", self.tx_receiver.receiver_count()); + // //let builder_state = builder_state.lock().unwrap(); + // while let Ok(req) = self.req_receiver.try_recv() { + // println!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); + // if let MessageType::RequestMessage(req) = req { + // self.process_block_request(req).await; + // } + // }; + + // let (received_msg, channel_index, _)= future::select_all([self.tx_receiver.recv(), self.da_proposal_receiver.recv(), + // self.qc_receiver.recv(), self.decide_receiver.recv(),self.req_receiver.recv()]).await; + //let y = x.next().await; + //println!("Received message: {:?}", y); + println!("In event loop for {:?}", self.built_from_view_vid_leaf); + + // get all the tx_messages from the tx_hash_to_available_txns + // for (tx_hash, (timestamp, tx, source)) in self.tx_hash_to_available_txns.iter(){ + // println!("Tx hash: {:?}, timestamp: {:?}, tx: {:?}, source: {:?}", tx_hash, timestamp, tx, source); + // if tx. + // } + // get the length of the tx_hash_to_available_txns + //println!("Length of tx_hash_to_available_txns: {:?}", self.tx_hash_to_available_txns.len()); + // if self.tx_hash_to_available_txns.len() == 3 { + // // get the first transaction from the tx_hash_to_available_txns + // break; + // } + futures::select!{ + tx = self.tx_receiver.next() => { + //println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, tx); + match tx { + Some(tx) => { + if let MessageType::TransactionMessage(rtx_msg) = tx { + println!("Received tx msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rtx_msg); + if rtx_msg.tx_type == TransactionSource::HotShot { + self.process_hotshot_transaction(rtx_msg.tx).await; + } else { + self.process_external_transaction(rtx_msg.tx).await; } + println!("tx map size: {}", self.tx_hash_to_available_txns.len()); + // if self.built_from_view_vid_leaf.0.get_u64() == 1 && self.tx_hash_to_available_txns.len() == 2 { + // // get the first transaction from the tx_hash_to_available_txns + // break; + // } } } + None => { + println!("No more tx messages to consume"); + } } - - */ - - // println!("In event loop for {:?}", self.built_from_view_vid_leaf); - // println!("Receiver count: {:?}", self.tx_receiver.receiver_count()); - // //let builder_state = builder_state.lock().unwrap(); - // while let Ok(req) = self.req_receiver.try_recv() { - // println!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); - // if let MessageType::RequestMessage(req) = req { - // self.process_block_request(req).await; - // } - // }; - - // let (received_msg, channel_index, _)= future::select_all([self.tx_receiver.recv(), self.da_proposal_receiver.recv(), - // self.qc_receiver.recv(), self.decide_receiver.recv(),self.req_receiver.recv()]).await; - //let y = x.next().await; - //println!("Received message: {:?}", y); - println!("In event loop for {:?}", self.built_from_view_vid_leaf); - - - - futures::select!{ - tx = self.tx_receiver.next() => { - //println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, tx); - match tx { - Some(tx) => { - if let MessageType::TransactionMessage(rtx_msg) = tx { - println!("Received tx msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rtx_msg); - if rtx_msg.tx_type == TransactionSource::HotShot { - self.process_hotshot_transaction(rtx_msg.tx).await; - } else { - self.process_external_transaction(rtx_msg.tx).await; - } - } - } - None => { - println!("No more tx messages to consume"); - } + } + da = self.da_proposal_receiver.next() => { + //println!("Received da proposal msg in builder {}: {:?} from index", self.builder_keys.0, da); + match da { + Some(da) => { + if let MessageType::DAProposalMessage(rda_msg) = da { + println!("Received da proposal msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rda_msg.proposal.data.view_number); + self.process_da_proposal(rda_msg).await; } } - da = self.da_proposal_receiver.next() => { - //println!("Received da proposal msg in builder {}: {:?} from index", self.builder_keys.0, da); - match da { - Some(da) => { - if let MessageType::DAProposalMessage(rda_msg) = da { - println!("Received da proposal msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rda_msg.proposal.data.view_number); - self.process_da_proposal(rda_msg).await; - } - } - None => { - println!("No more da proposal messages to consume"); - } - } + None => { + println!("No more da proposal messages to consume"); } - qc = self.qc_receiver.next() => { - //println!("Received qc msg in builder {}: {:?} from index", self.builder_keys.0, qc); - match qc { - Some(qc) => { - if let MessageType::QCMessage(rqc_msg) = qc { - println!("Received qc msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rqc_msg.proposal.data.view_number); - self.process_quorum_proposal(rqc_msg).await; - } - } - None => { - println!("No more qc messages to consume"); - } + } + } + qc = self.qc_receiver.next() => { + //println!("Received qc msg in builder {}: {:?} from index", self.builder_keys.0, qc); + match qc { + Some(qc) => { + if let MessageType::QCMessage(rqc_msg) = qc { + println!("Received qc msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rqc_msg.proposal.data.view_number); + self.process_quorum_proposal(rqc_msg).await; } } - decide = self.decide_receiver.next() => { - println!("Received decide msg in builder {}: {:?} from index", self.builder_keys.0, decide); - match decide { - Some(decide) => { - if let MessageType::DecideMessage(rdecide_msg) = decide { - println!("Received decide msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rdecide_msg); - let decide_status = self.process_decide_event(rdecide_msg).await; - match decide_status{ - Some(Status::ShouldExit) => { - break; - } - Some(Status::ShouldContinue) => { - continue; - } - None => { - continue; - } - } + None => { + println!("No more qc messages to consume"); + } + } + } + decide = self.decide_receiver.next() => { + println!("Received decide msg in builder {}: {:?} from index", self.builder_keys.0, decide); + match decide { + Some(decide) => { + if let MessageType::DecideMessage(rdecide_msg) = decide { + println!("Received decide msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rdecide_msg); + let decide_status = self.process_decide_event(rdecide_msg).await; + match decide_status{ + Some(Status::ShouldExit) => { + break; + } + Some(Status::ShouldContinue) => { + continue; + } + None => { + continue; } - } - None => { - println!("No more decide messages to consume"); } } } - }; - - - // let (received_msg, channel_index, _)= select_all([self.tx_receiver.next().await, self.da_proposal_receiver.next().await, - // self.qc_receiver.next().await, self.decide_receiver.next().await,self.req_receiver.next().await]); + None => { + println!("No more decide messages to consume"); + } + } + } + }; + + + // let (received_msg, channel_index, _)= select_all([self.tx_receiver.next().await, self.da_proposal_receiver.next().await, + // self.qc_receiver.next().await, self.decide_receiver.next().await,self.req_receiver.next().await]); - // let mut x = select_all([self.tx_receiver.into_stream(), self.da_proposal_receiver, - // self.qc_receiver, self.decide_receiver,self.req_receiver]); - - // select! { - // received_tx_msg = self.tx_receiver.next().await.unwrap()=> { - // println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, received_tx_msg); - // if let Some(received_tx_msg) = received_tx_msg { - // if let MessageType::TransactionMessage(rtx_msg) = received_tx_msg { - // println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, rtx_msg); - // if rtx_msg.tx_type == TransactionSource::HotShot { - // self.process_hotshot_transaction(rtx_msg.tx).await; - // } else { - // self.process_external_transaction(rtx_msg.tx).await; - // } - // } - // } - // } - // } + // let mut x = select_all([self.tx_receiver.into_stream(), self.da_proposal_receiver, + // self.qc_receiver, self.decide_receiver,self.req_receiver]); + + // select! { + // received_tx_msg = self.tx_receiver.next().await.unwrap()=> { + // println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, received_tx_msg); + // if let Some(received_tx_msg) = received_tx_msg { + // if let MessageType::TransactionMessage(rtx_msg) = received_tx_msg { + // println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, rtx_msg); + // if rtx_msg.tx_type == TransactionSource::HotShot { + // self.process_hotshot_transaction(rtx_msg.tx).await; + // } else { + // self.process_external_transaction(rtx_msg.tx).await; + // } + // } + // } + // } + // } + + /* + let (received_msg, channel_index, _)= future::select_all([self.tx_receiver.recv(), self.da_proposal_receiver.recv(), + self.qc_receiver.recv(), self.decide_receiver.recv(),self.req_receiver.recv()]).await; + match received_msg { + Ok(received_msg) => { - /* - let (received_msg, channel_index, _)= future::select_all([self.tx_receiver.recv(), self.da_proposal_receiver.recv(), - self.qc_receiver.recv(), self.decide_receiver.recv(),self.req_receiver.recv()]).await; match received_msg { - Ok(received_msg) => { + + // request message + MessageType::RequestMessage(req) => { + println!("Received request msg in builder {}: {:?} from index {}", self.builder_keys.0, req, channel_index); - match received_msg { - - // request message - MessageType::RequestMessage(req) => { - println!("Received request msg in builder {}: {:?} from index {}", self.builder_keys.0, req, channel_index); - - self.process_block_request(req).await; - - } + self.process_block_request(req).await; + + } - // transaction message - MessageType::TransactionMessage(rtx_msg) => { - println!("Received tx msg in builder {}: {:?} from index {}", self.builder_keys.0, rtx_msg, channel_index); - - //self.print_builder_state().await; - // get the content from the rtx_msg's inside vec - // Pass the tx msg to the handler - println!("Local tx_maps before processing the transaction:\n Tx_hash_to_available_txns: {:?} \nTimestamp to tx {:?}\n Included txns{:?}", - self.tx_hash_to_available_txns, self.timestamp_to_tx, self.included_txns); - - if rtx_msg.tx_type == TransactionSource::HotShot { - self.process_hotshot_transaction(rtx_msg.tx).await; - } else { - self.process_external_transaction(rtx_msg.tx).await; - } - //self.print_builder_state().await; - println!("Local tx_maps after processing the transaction:\n Tx_hash_to_available_txns: {:?} \nTimestamp to tx {:?}\n Included txns{:?}", - self.tx_hash_to_available_txns, self.timestamp_to_tx, self.included_txns); - - } + // transaction message + MessageType::TransactionMessage(rtx_msg) => { + println!("Received tx msg in builder {}: {:?} from index {}", self.builder_keys.0, rtx_msg, channel_index); + + //self.print_builder_state().await; + // get the content from the rtx_msg's inside vec + // Pass the tx msg to the handler + println!("Local tx_maps before processing the transaction:\n Tx_hash_to_available_txns: {:?} \nTimestamp to tx {:?}\n Included txns{:?}", + self.tx_hash_to_available_txns, self.timestamp_to_tx, self.included_txns); + + if rtx_msg.tx_type == TransactionSource::HotShot { + self.process_hotshot_transaction(rtx_msg.tx).await; + } else { + self.process_external_transaction(rtx_msg.tx).await; + } + //self.print_builder_state().await; + println!("Local tx_maps after processing the transaction:\n Tx_hash_to_available_txns: {:?} \nTimestamp to tx {:?}\n Included txns{:?}", + self.tx_hash_to_available_txns, self.timestamp_to_tx, self.included_txns); + + } - // decide message - MessageType::DecideMessage(rdecide_msg) => { - println!("Received decide msg in builder {}: {:?} from index {}", self.builder_keys.0, rdecide_msg, channel_index); - // store in the rdecide_msgs - //self.print_builder_state().await; - let decide_status = self.process_decide_event(rdecide_msg).await; - //self.print_builder_state().await; - // TODO - // if should exit, then break out of the loop - match decide_status{ - Some(Status::ShouldExit) => { - break; - } - Some(Status::ShouldContinue) => { - continue; - } - None => { - continue; - } - } + // decide message + MessageType::DecideMessage(rdecide_msg) => { + println!("Received decide msg in builder {}: {:?} from index {}", self.builder_keys.0, rdecide_msg, channel_index); + // store in the rdecide_msgs + //self.print_builder_state().await; + let decide_status = self.process_decide_event(rdecide_msg).await; + //self.print_builder_state().await; + // TODO + // if should exit, then break out of the loop + match decide_status{ + Some(Status::ShouldExit) => { + break; } - - // DA proposal message - MessageType::DAProposalMessage(rda_msg) => { - println!("Received da proposal msg in builder {}: {:?} from index {}", self.builder_keys.0, rda_msg, channel_index); - //self.print_builder_state().await; - // print only the keys in self.da_proposal_payload_commit_to_da_proposal map - println!("DA proposal payload commit to da proposal map keys before processing: {:?}", self.da_proposal_payload_commit_to_da_proposal.keys()); - self.process_da_proposal(rda_msg).await; - println!("DA proposal payload commit to da proposal map keys after processing: {:?}", self.da_proposal_payload_commit_to_da_proposal.keys()); - //self.print_builder_state().await; - + Some(Status::ShouldContinue) => { + continue; } - // QC proposal message - MessageType::QCMessage(rqc_msg) => { - println!("Received qc msg in builder {}: {:?} from index {}", self.builder_keys.0, rqc_msg, channel_index); - //self.print_builder_state().await; - println!("QC proposal payload commit to QC proposal map keys before processing: {:?}", self.quorum_proposal_payload_commit_to_quorum_proposal.keys()); - self.process_quorum_proposal(rqc_msg).await; - println!("QC proposal payload commit to QC proposal map keys before processing: {:?}", self.quorum_proposal_payload_commit_to_quorum_proposal.keys()); - - //self.print_builder_state().await; + None => { + continue; } } - } - Err(err) => { - println!("Error in builder event loop: {:?}", err); - if err == RecvError::Closed { - println!("The channel {} is closed", channel_index); - //break; - //channel_close_index.insert(channel_index); - } - else{ - println!("No more messages to consume {}", channel_index); - break; - } + + // DA proposal message + MessageType::DAProposalMessage(rda_msg) => { + println!("Received da proposal msg in builder {}: {:?} from index {}", self.builder_keys.0, rda_msg, channel_index); + //self.print_builder_state().await; + // print only the keys in self.da_proposal_payload_commit_to_da_proposal map + println!("DA proposal payload commit to da proposal map keys before processing: {:?}", self.da_proposal_payload_commit_to_da_proposal.keys()); + self.process_da_proposal(rda_msg).await; + println!("DA proposal payload commit to da proposal map keys after processing: {:?}", self.da_proposal_payload_commit_to_da_proposal.keys()); + //self.print_builder_state().await; + + } + // QC proposal message + MessageType::QCMessage(rqc_msg) => { + println!("Received qc msg in builder {}: {:?} from index {}", self.builder_keys.0, rqc_msg, channel_index); + //self.print_builder_state().await; + println!("QC proposal payload commit to QC proposal map keys before processing: {:?}", self.quorum_proposal_payload_commit_to_quorum_proposal.keys()); + self.process_quorum_proposal(rqc_msg).await; + println!("QC proposal payload commit to QC proposal map keys before processing: {:?}", self.quorum_proposal_payload_commit_to_quorum_proposal.keys()); + + //self.print_builder_state().await; } } - */ - }; + } + Err(err) => { + println!("Error in builder event loop: {:?}", err); + if err == RecvError::Closed { + println!("The channel {} is closed", channel_index); + //break; + //channel_close_index.insert(channel_index); + } + else{ + println!("No more messages to consume {}", channel_index); + break; + } + } + } + + */ + }; + } + async fn event_loop(mut self){ + + let builder_handle = task::spawn(async move{ + + //let mut x = futures::stream::select(self.tx_receiver, self.da_proposal_receiver); + + self.loop_function().await; }); - builder_handle.await; + //builder_handle.await; } } From 9709cc66a233c127bffa30bec8b72f48b108cedd Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 9 Feb 2024 11:22:14 -0500 Subject: [PATCH 33/47] wip test --- src/builder_state.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 394b88b2..4408e08b 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -279,11 +279,12 @@ impl BuilderProgress for BuilderState{ //let self_clone = self.clone(); //self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; - let self_clone = self.clone(); + // let self_clone = self.clone(); - task::spawn(async move { - self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await - }).await; + // task::spawn(async move { + // self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await + // }).await; + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; // register the clone to the global state //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); } else { @@ -323,11 +324,13 @@ impl BuilderProgress for BuilderState{ if let Entry::Occupied(da_proposal_data) = self.da_proposal_payload_commit_to_da_proposal.entry(payload_vid_commitment.clone()) { let da_proposal_data = da_proposal_data.remove(); //let self_clone = self.clone(); - let self_clone = self.clone(); + // let self_clone = self.clone(); - task::spawn(async move { - self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await - }).await; + // task::spawn(async move { + // self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await + // }).await; + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; + // registed the clone to the global state //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); @@ -827,6 +830,7 @@ impl BuilderProgress for BuilderState{ }); + //builder_handle //builder_handle.await; } From dece120a9fec78a0fb2b2a26a8f38ec5c7882c4e Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 9 Feb 2024 11:55:41 -0500 Subject: [PATCH 34/47] swap task::spawn with art::async_spawn --- src/builder_state.rs | 5 ++++- src/testing/basic_test.rs | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 4408e08b..9c3eb8bc 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -27,6 +27,8 @@ use async_std::task; use async_trait::async_trait; use async_compatibility_layer::channel:: UnboundedSender; use async_lock::RwLock; +use async_compatibility_layer::art::{async_sleep, async_spawn}; + //use futures_lite::{future::block_on, stream::StreamExt}; use futures::stream;//::{select, select_all}; //use sha2::digest::crypto_common::rand_core::block; @@ -822,7 +824,8 @@ impl BuilderProgress for BuilderState{ } async fn event_loop(mut self){ - let builder_handle = task::spawn(async move{ + //let builder_handle = task::spawn(async move{ + let builder_handle = async_spawn(async move{ //let mut x = futures::stream::select(self.tx_receiver, self.da_proposal_receiver); diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 2f0902fa..2b0b614f 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -27,6 +27,7 @@ pub use crate::builder_state::{BuilderState,MessageType, BuilderProgress, Respon pub use async_broadcast::{broadcast, TryRecvError, Sender as BroadcastSender, Receiver as BroadcastReceiver, RecvError}; // tests use commit::{Commitment, Committable, CommitmentBoundsArkless}; +use async_compatibility_layer::art::{async_sleep, async_spawn}; /// The following tests are performed: #[cfg(test)] mod tests { @@ -228,7 +229,7 @@ mod tests { assert_eq!(quorum_membershiop.total_nodes(), TEST_NUM_NODES_IN_VID_COMPUTATION); - let handle = task::spawn(async move{ + let handle = async_spawn(async move{ let mut builder_state = BuilderState::::new((builder_pub_key, builder_private_key), (ViewNumber::new(0), genesis_vid_commitment(), Commitment::>::default_commitment_no_preimage()), tx_receiver, decide_receiver, da_receiver, qc_receiver, req_receiver, global_state, res_sender, Arc::new(quorum_membershiop)); From a9ccfd349438d6d5557f68f7b430c43bb5bfe659 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 9 Feb 2024 12:20:33 -0500 Subject: [PATCH 35/47] await on handle --- src/builder_state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 9c3eb8bc..6241f522 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -834,7 +834,7 @@ impl BuilderProgress for BuilderState{ }); //builder_handle - //builder_handle.await; + builder_handle.await; } } From 5fa02937e038070d7d1cfc9b086f64fb30ccdbbc Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 9 Feb 2024 13:40:23 -0500 Subject: [PATCH 36/47] point to recent branch in builder-api --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d4b243ff..a1e90c4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,9 +44,9 @@ atomic_store = { git = "https://github.com/EspressoSystems/atomicstore.git", tag unix-time = "0.1.5" async-broadcast = "0.6.0" sha2 = "0.10" -jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish" } +#jf-primitives = { git = "https://github.com/EspressoSystems/jellyfish" } -#hs-builder-api = {git = "https://github.com/EspressoSystems/hs-builder-api", branch="main"} -hs-builder-api = {path="../hs-builder-api"} +hs-builder-api = {git = "https://github.com/EspressoSystems/hs-builder-api", branch="builder_specific_information"} +#hs-builder-api = {path="../hs-builder-api"} tagged-base64 = { git = "https://github.com/EspressoSystems/tagged-base64", tag = "0.3.4" } futures-lite = "2.2.0" \ No newline at end of file From ff4ca24b6bf9f2df876ec950dbbf33ef0ed5e4c1 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 9 Feb 2024 18:16:36 -0500 Subject: [PATCH 37/47] add tracing and some cleanup --- src/builder_state.rs | 500 ++++++++++---------------------------- src/testing/basic_test.rs | 44 ++-- 2 files changed, 155 insertions(+), 389 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 6241f522..706c854f 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -2,37 +2,28 @@ // This file is part of the HotShot Builder Protocol. // -#![allow(unused_variables)] -// use hotshot_testing::block_types::{TestBlockHeader, TestBlockPayload, TestTransaction}; -//use hotshot_task::event_stream::{ChannelStream, EventStream, StreamId}; - -//use hotshot_task_impls::da; -// including the following from the hotshot use hotshot_types::{ traits::{node_implementation::{NodeType as BuilderType,ConsensusTime}, block_contents::vid_commitment, signature_key::SignatureKey}, - data::{DAProposal, Leaf, QuorumProposal, VidCommitment, VidScheme, VidSchemeTrait, test_srs, ViewNumber}, + data::{DAProposal, Leaf, QuorumProposal, VidCommitment, VidScheme, VidSchemeTrait, test_srs}, simple_certificate::QuorumCertificate, message::Proposal, traits::{block_contents::{BlockPayload, BlockHeader}, election::Membership}, utils::BuilderCommitment, vote::Certificate, }; -//use jf_primitives::signatures::bls_over_bn254::{SignKey, VerKey}; + use commit::{Commitment, Committable}; -use futures::{future, StreamExt};//::select_all; +use futures::StreamExt;//::select_all; use async_std::task::JoinHandle; -use async_broadcast::{Receiver as BroadcastReceiver, RecvError}; +use async_broadcast::Receiver as BroadcastReceiver; use async_std::task; use async_trait::async_trait; use async_compatibility_layer::channel:: UnboundedSender; use async_lock::RwLock; -use async_compatibility_layer::art::{async_sleep, async_spawn}; - -//use futures_lite::{future::block_on, stream::StreamExt}; -use futures::stream;//::{select, select_all}; -//use sha2::digest::crypto_common::rand_core::block; +use async_compatibility_layer::art::async_spawn; +use core::panic; use std::collections::hash_map::Entry; use std::collections::{BTreeMap, HashMap, HashSet}; use std::sync::Arc; @@ -43,43 +34,47 @@ use std::cmp::PartialEq; use crate::service::GlobalState; pub type TxTimeStamp = u128; -//const NUM_NODES_IN_VID_COMPUTATION: usize = 8; +/// Enum to hold the different sources of the transaction #[derive(Clone, Debug, PartialEq)] pub enum TransactionSource { External, // txn from the external source i.e private mempool HotShot, // txn from the HotShot network i.e public mempool } +/// Transaction Message to be put on the tx channel #[derive(Clone, Debug, PartialEq)] pub struct TransactionMessage{ pub tx: TYPES::Transaction, pub tx_type: TransactionSource, } +/// Decide Message to be put on the decide channel #[derive(Clone, Debug, PartialEq)] pub struct DecideMessage{ pub leaf_chain: Arc>>, pub qc: Arc>, pub block_size: Option } +/// DA Proposal Message to be put on the da proposal channel #[derive(Clone, Debug, PartialEq)] pub struct DAProposalMessage{ pub proposal: Proposal>, pub sender: TYPES::SignatureKey, pub total_nodes: usize, } +/// QC Message to be put on the quorum proposal channel #[derive(Clone, Debug, PartialEq)] pub struct QCMessage{ pub proposal: Proposal>, pub sender: TYPES::SignatureKey, } - +/// Request Message to be put on the request channel #[derive(Clone, Debug, PartialEq)] pub struct RequestMessage{ pub requested_vid_commitment: VidCommitment, //pub total_nodes: usize } - +/// Response Message to be put on the response channel #[derive(Debug, Clone)] pub struct ResponseMessage{ pub block_hash: BuilderCommitment, //TODO: Need to pull out from hotshot @@ -91,7 +86,7 @@ pub struct ResponseMessage{ pub signature:<::SignatureKey as SignatureKey>::PureAssembledSignatureType, pub sender: TYPES::SignatureKey, } - +/// Enum to hold the status out of the decide event pub enum Status { ShouldExit, ShouldContinue, @@ -100,18 +95,19 @@ pub enum Status { #[derive(Debug, Clone)] pub struct BuilderState{ + // identity keys for the builder pub builder_keys: (TYPES::SignatureKey, <::SignatureKey as SignatureKey>::PrivateKey), //TODO (pub,priv) key of the builder, may be good to keep a ref // timestamp to tx hash, used for ordering for the transactions pub timestamp_to_tx: BTreeMap>, - // transaction hash to transaction data for efficient lookup + // transaction hash to available transaction data pub tx_hash_to_available_txns: HashMap,(TxTimeStamp, TYPES::Transaction, TransactionSource)>, /// Included txs set while building blocks pub included_txns: HashSet>, - /// block hash to the full block + /// block hash to the block payload pub block_hash_to_block: HashMap, /// da_proposal_payload_commit to da_proposal @@ -132,16 +128,16 @@ pub struct BuilderState{ /// decide receiver pub decide_receiver: BroadcastReceiver>, - /// da proposal event channel + /// da proposal receiver pub da_proposal_receiver: BroadcastReceiver>, - /// quorum proposal event channel + /// quorum proposal receiver pub qc_receiver: BroadcastReceiver>, - // channel receiver for the requests + // channel receiver for the block requests pub req_receiver: BroadcastReceiver>, - // global state handle + // global state handle, defined in the service.rs pub global_state: Arc::>>, // response sender @@ -157,46 +153,44 @@ pub struct BuilderState{ #[async_trait] pub trait BuilderProgress { /// process the external transaction - async fn process_external_transaction(&mut self, tx: TYPES::Transaction); + fn process_external_transaction(&mut self, tx: TYPES::Transaction); /// process the hotshot transaction - async fn process_hotshot_transaction(&mut self, tx: TYPES::Transaction); + fn process_hotshot_transaction(&mut self, tx: TYPES::Transaction); /// process the DA proposal - async fn process_da_proposal(&mut self, da_msg: DAProposalMessage); + fn process_da_proposal(&mut self, da_msg: DAProposalMessage); /// process the quorum proposal - async fn process_quorum_proposal(&mut self, qc_msg: QCMessage); + fn process_quorum_proposal(&mut self, qc_msg: QCMessage); /// process the decide event async fn process_decide_event(&mut self, decide_msg: DecideMessage) -> Option; /// spawn a clone of builder - async fn spawn_clone(self, da_proposal: DAProposal, quorum_proposal: QuorumProposal, leader: TYPES::SignatureKey); + fn spawn_clone(self, da_proposal: DAProposal, quorum_proposal: QuorumProposal, leader: TYPES::SignatureKey); /// build a block - async fn build_block(&mut self, matching_vid: VidCommitment) -> Option>; + fn build_block(&mut self, matching_vid: VidCommitment) -> Option>; /// Event Loop - async fn event_loop(mut self); - + fn event_loop(self); + /// process the block request async fn process_block_request(&mut self, req: RequestMessage); - /// loop function - async fn loop_function(&mut self); - } #[async_trait] +//#[tracing::instrument(skip_all)] impl BuilderProgress for BuilderState{ /// processing the external i.e private mempool transaction - async fn process_external_transaction(&mut self, tx: TYPES::Transaction) + fn process_external_transaction(&mut self, tx: TYPES::Transaction) { // PRIVATE MEMPOOL TRANSACTION PROCESSING - println!("Processing external transaction"); + tracing::info!("Processing external transaction"); // check if the transaction already exists in either the included set or the local tx pool // if it exits, then we can ignore it and return // else we can insert it into local tx pool @@ -204,7 +198,7 @@ impl BuilderProgress for BuilderState{ let tx_hash = tx.commit(); // If it already exists, then discard it. Decide the existence based on the tx_hash_tx and check in both the local pool and already included txns if self.tx_hash_to_available_txns.contains_key(&tx_hash) || self.included_txns.contains(&tx_hash) { - println!("Transaction already exists in the builderinfo.txid_to_tx hashmap, So we can ignore it"); + tracing::info!("Transaction already exists in the builderinfo.txid_to_tx hashmap, So we can ignore it"); return; } else { @@ -218,13 +212,13 @@ impl BuilderProgress for BuilderState{ } /// processing the hotshot i.e public mempool transaction - async fn process_hotshot_transaction(&mut self, tx: TYPES::Transaction) + fn process_hotshot_transaction(&mut self, tx: TYPES::Transaction) { let tx_hash = tx.commit(); // HOTSHOT MEMPOOL TRANSACTION PROCESSING // If it already exists, then discard it. Decide the existence based on the tx_hash_tx and check in both the local pool and already included txns if self.tx_hash_to_available_txns.contains_key(&tx_hash) || self.included_txns.contains(&tx_hash) { - println!("Transaction already exists in the builderinfo.txid_to_tx hashmap, So we can ignore it"); + tracing::info!("Transaction already exists in the builderinfo.txid_to_tx hashmap, So we can ignore it"); return; } else { // get the current timestamp in nanoseconds @@ -237,7 +231,7 @@ impl BuilderProgress for BuilderState{ } /// processing the DA proposal - async fn process_da_proposal(&mut self, da_msg: DAProposalMessage) + fn process_da_proposal(&mut self, da_msg: DAProposalMessage) { // Validation // check for view number @@ -246,10 +240,10 @@ impl BuilderProgress for BuilderState{ // bootstrapping part // if the view number is 0 then keep going, and don't return from it if self.built_from_view_vid_leaf.0.get_u64() == 0 { - println!("In bootstrapping phase"); + tracing::info!("In bootstrapping phase"); } else if da_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0{ - println!("View number does not match the built_from_view, so ignoring it"); + tracing::info!("View number does not match the built_from_view, so ignoring it"); return; } @@ -264,9 +258,9 @@ impl BuilderProgress for BuilderState{ // generate the vid commitment; num nodes are received through hotshot api in service.rs and passed along with message onto channel let total_nodes = da_msg.total_nodes; - println!("Encoded txns in da proposal: {:?} and total nodes: {:?}", encoded_txns, total_nodes); + tracing::debug!("Encoded txns in da proposal: {:?} and total nodes: {:?}", encoded_txns, total_nodes); let payload_vid_commitment = vid_commitment(&encoded_txns, total_nodes); - println!("Generated payload commitment from the da proposal: {:?}", payload_vid_commitment); + tracing::debug!("Generated payload commitment from the da proposal: {:?}", payload_vid_commitment); if !self.da_proposal_payload_commit_to_da_proposal.contains_key(&payload_vid_commitment) { let da_proposal_data = DAProposal { encoded_transactions: encoded_txns.clone(), @@ -277,16 +271,7 @@ impl BuilderProgress for BuilderState{ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(qc_proposal_data) = self.quorum_proposal_payload_commit_to_quorum_proposal.entry(payload_vid_commitment.clone()) { let qc_proposal_data = qc_proposal_data.remove(); - - //let self_clone = self.clone(); - - //self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; - // let self_clone = self.clone(); - - // task::spawn(async move { - // self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await - // }).await; - self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender); // register the clone to the global state //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); } else { @@ -297,7 +282,7 @@ impl BuilderProgress for BuilderState{ } /// processing the quorum proposal - async fn process_quorum_proposal(&mut self, qc_msg: QCMessage) + fn process_quorum_proposal(&mut self, qc_msg: QCMessage) { // Validation // check for view number @@ -308,32 +293,24 @@ impl BuilderProgress for BuilderState{ // bootstrapping part // if the view number is 0 then keep going, and don't return from it if self.built_from_view_vid_leaf.0.get_u64() == 0{ - println!("In bootstrapping phase"); + tracing::info!("In bootstrapping phase"); } else if qc_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0 || qc_msg.proposal.data.justify_qc.get_data().leaf_commit != self.built_from_view_vid_leaf.2 { - println!("Either View number or leaf commit does not match the built-in info, so ignoring it"); + tracing::info!("Either View number or leaf commit does not match the built-in info, so ignoring it"); return; } let qc_proposal_data = qc_msg.proposal.data; let sender = qc_msg.sender; let payload_vid_commitment = qc_proposal_data.block_header.payload_commitment(); - println!("Extracted payload commitment from the quorum proposal: {:?}", payload_vid_commitment); + tracing::debug!("Extracted payload commitment from the quorum proposal: {:?}", payload_vid_commitment); // first check whether vid_commitment exists in the qc_payload_commit_to_qc hashmap, if yer, ignore it, otherwise validate it and later insert in if !self.quorum_proposal_payload_commit_to_quorum_proposal.contains_key(&payload_vid_commitment){ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(da_proposal_data) = self.da_proposal_payload_commit_to_da_proposal.entry(payload_vid_commitment.clone()) { let da_proposal_data = da_proposal_data.remove(); - //let self_clone = self.clone(); - // let self_clone = self.clone(); - - // task::spawn(async move { - // self_clone.spawn_clone(da_proposal_data, qc_proposal_data, sender).await - // }).await; - self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender).await; - - + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender); // registed the clone to the global state //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); @@ -352,13 +329,13 @@ impl BuilderProgress for BuilderState{ // if you haven't launched the clone, then you don't exit, you need atleast one clone to function properly // the special value can be 0 itself, or a view number 0 is also right answer let leaf_chain = decide_msg.leaf_chain; - let qc = decide_msg.qc; - let block_size = decide_msg.block_size; + let _qc = decide_msg.qc; + let _block_size = decide_msg.block_size; - let latest_decide_parent_commitment = leaf_chain[0].parent_commitment; + let _latest_decide_parent_commitment = leaf_chain[0].parent_commitment; - let latest_decide_commitment = leaf_chain[0].commit(); + let _latest_decide_commitment = leaf_chain[0].commit(); let leaf_view_number = leaf_chain[0].view_number; @@ -367,11 +344,11 @@ impl BuilderProgress for BuilderState{ // and not make any progress; so we need to handle that case // Adhoc logic: if the number of subscrived receivers are more than 1, it means that there exists a clone and we can safely exit if self.built_from_view_vid_leaf.0.get_u64() == 0 && self.tx_receiver.receiver_count() <=1 { - println!("In bootstrapping phase"); + tracing::info!("In bootstrapping phase"); //return Some(Status::ShouldContinue); } else if self.built_from_view_vid_leaf.0 <= leaf_view_number{ - println!("The decide event is not for the next view, so ignoring it"); + tracing::info!("The decide event is not for the next view, so ignoring it"); // convert leaf commitments into buildercommiments //let leaf_commitments:Vec = leaf_chain.iter().map(|leaf| leaf.get_block_payload().unwrap().builder_commitment(&leaf.get_block_header().metadata())).collect(); @@ -386,7 +363,7 @@ impl BuilderProgress for BuilderState{ let block_payload = leaf.get_block_payload(); match block_payload{ Some(block_payload) => { - println!("Block payload in decide event {:?}", block_payload); + tracing::debug!("Block payload in decide event {:?}", block_payload); let metadata = leaf_chain[0].get_block_header().metadata(); let transactions_commitments = block_payload.transaction_commitments(&metadata); // iterate over the transactions and remove them from tx_hash_to_tx and timestamp_to_tx @@ -405,7 +382,7 @@ impl BuilderProgress for BuilderState{ } }, None => { - println!("Block payload is none"); + tracing::warn!("Block payload is none"); } } } @@ -414,9 +391,9 @@ impl BuilderProgress for BuilderState{ } // spawn a clone of the builder state - async fn spawn_clone(mut self, da_proposal: DAProposal, quorum_proposal: QuorumProposal, leader: TYPES::SignatureKey) + fn spawn_clone(mut self, da_proposal: DAProposal, quorum_proposal: QuorumProposal, leader: TYPES::SignatureKey) { - println!("Spawning a clone"); + tracing::debug!("Spawning a clone"); self.built_from_view_vid_leaf.0 = quorum_proposal.view_number; self.built_from_view_vid_leaf.1 = quorum_proposal.block_header.payload_commitment(); @@ -444,15 +421,15 @@ impl BuilderProgress for BuilderState{ txn_info.remove_entry(); }); - self.event_loop().await; + self.event_loop(); } // build a block - async fn build_block(&mut self, matching_vid: VidCommitment) -> Option>{ + fn build_block(&mut self, _matching_vid: VidCommitment) -> Option>{ if let Ok((payload, metadata)) = ::from_transactions( - self.timestamp_to_tx.iter().filter_map(|(ts, tx_hash)| { - self.tx_hash_to_available_txns.get(tx_hash).map(|(ts, tx, source)| { + self.timestamp_to_tx.iter().filter_map(|(_ts, tx_hash)| { + self.tx_hash_to_available_txns.get(tx_hash).map(|(_ts, tx, _source)| { tx.clone() }) })) { @@ -510,6 +487,7 @@ impl BuilderProgress for BuilderState{ signature: signature_over_block_info, sender: self.builder_keys.0.clone()}); }; + tracing::warn!("build the block, returning None"); None } @@ -517,7 +495,7 @@ impl BuilderProgress for BuilderState{ let requested_vid_commitment = req.requested_vid_commitment; //let vid_nodes = req.total_nodes; if requested_vid_commitment == self.built_from_view_vid_leaf.1{ - let response = self.build_block(requested_vid_commitment).await; + let response = self.build_block(requested_vid_commitment); match response{ Some(response)=>{ // send the response back @@ -530,312 +508,100 @@ impl BuilderProgress for BuilderState{ self.global_state.write_arc().await.block_hash_to_block.insert(response.block_hash, (response.block_payload, response.metadata, response.join_handle, response.signature, response.sender)); } None => { - println!("No response to send"); + tracing::warn!("No response to send"); } } } } - - async fn loop_function(&mut self){ - loop{ - - // print 10 times the builderstate.built_from_view_vid_leaf and then sleep for some time - // for i in 0..10{ - // println!("In event loop for {:?}", self.built_from_view_vid_leaf); - // } - //task::sleep(std::time::Duration::from_secs(1)).await; - - - /* - if let Ok(tx) = self.tx_receiver.try_recv(){ - println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, tx); - if let MessageType::TransactionMessage(rtx_msg) = tx{ - if rtx_msg.tx_type == TransactionSource::HotShot { - self.process_hotshot_transaction(rtx_msg.tx).await; - } else { - self.process_external_transaction(rtx_msg.tx).await; - } - } - } - - if let Ok(da) = self.da_proposal_receiver.try_recv(){ - println!("Received da proposal msg in builder {}: {:?} from index", self.builder_keys.0, da); - if let MessageType::DAProposalMessage(rda_msg) = da{ - self.process_da_proposal(rda_msg).await; - } - } - - if let Ok(qc) = self.qc_receiver.try_recv(){ - println!("Received qc msg in builder {}: {:?} from index", self.builder_keys.0, qc); - if let MessageType::QCMessage(rqc_msg) = qc{ - self.process_quorum_proposal(rqc_msg).await; - } - } - - if let Ok(decide) = self.decide_receiver.try_recv(){ - println!("Received decide msg in builder {}: {:?} from index", self.builder_keys.0, decide); - if let MessageType::DecideMessage(rdecide_msg) = decide{ - let decide_status = self.process_decide_event(rdecide_msg).await; - match decide_status{ - Some(Status::ShouldExit) => { - break; - } - Some(Status::ShouldContinue) => { - continue; - } - None => { - continue; - } - } - } - } - - */ - - // println!("In event loop for {:?}", self.built_from_view_vid_leaf); - // println!("Receiver count: {:?}", self.tx_receiver.receiver_count()); - // //let builder_state = builder_state.lock().unwrap(); - // while let Ok(req) = self.req_receiver.try_recv() { - // println!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); - // if let MessageType::RequestMessage(req) = req { - // self.process_block_request(req).await; - // } - // }; - - // let (received_msg, channel_index, _)= future::select_all([self.tx_receiver.recv(), self.da_proposal_receiver.recv(), - // self.qc_receiver.recv(), self.decide_receiver.recv(),self.req_receiver.recv()]).await; - //let y = x.next().await; - //println!("Received message: {:?}", y); - println!("In event loop for {:?}", self.built_from_view_vid_leaf); - - // get all the tx_messages from the tx_hash_to_available_txns - // for (tx_hash, (timestamp, tx, source)) in self.tx_hash_to_available_txns.iter(){ - // println!("Tx hash: {:?}, timestamp: {:?}, tx: {:?}, source: {:?}", tx_hash, timestamp, tx, source); - // if tx. - // } - // get the length of the tx_hash_to_available_txns - //println!("Length of tx_hash_to_available_txns: {:?}", self.tx_hash_to_available_txns.len()); - // if self.tx_hash_to_available_txns.len() == 3 { - // // get the first transaction from the tx_hash_to_available_txns - // break; - // } - futures::select!{ - tx = self.tx_receiver.next() => { - //println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, tx); - match tx { - Some(tx) => { - if let MessageType::TransactionMessage(rtx_msg) = tx { - println!("Received tx msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rtx_msg); - if rtx_msg.tx_type == TransactionSource::HotShot { - self.process_hotshot_transaction(rtx_msg.tx).await; - } else { - self.process_external_transaction(rtx_msg.tx).await; + #[tracing::instrument(skip_all, name = "Builder Event Loop")] + fn event_loop(mut self){ + let _builder_handle = async_spawn(async move{ + + loop{ + + futures::select!{ + tx = self.tx_receiver.next() => { + //println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, tx); + match tx { + Some(tx) => { + if let MessageType::TransactionMessage(rtx_msg) = tx { + //tracing::debug!("Received tx msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rtx_msg); + if rtx_msg.tx_type == TransactionSource::HotShot { + self.process_hotshot_transaction(rtx_msg.tx); + } else { + self.process_external_transaction(rtx_msg.tx); + } + tracing::debug!("tx map size: {}", self.tx_hash_to_available_txns.len()); + // if self.built_from_view_vid_leaf.0.get_u64() == 1 && self.tx_hash_to_available_txns.len() == 2 { + // // get the first transaction from the tx_hash_to_available_txns + // break; + // } + } + } + None => { + tracing::info!("No more tx messages to consume"); } - println!("tx map size: {}", self.tx_hash_to_available_txns.len()); - // if self.built_from_view_vid_leaf.0.get_u64() == 1 && self.tx_hash_to_available_txns.len() == 2 { - // // get the first transaction from the tx_hash_to_available_txns - // break; - // } - } - } - None => { - println!("No more tx messages to consume"); - } - } - } - da = self.da_proposal_receiver.next() => { - //println!("Received da proposal msg in builder {}: {:?} from index", self.builder_keys.0, da); - match da { - Some(da) => { - if let MessageType::DAProposalMessage(rda_msg) = da { - println!("Received da proposal msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rda_msg.proposal.data.view_number); - self.process_da_proposal(rda_msg).await; - } - } - None => { - println!("No more da proposal messages to consume"); - } - } - } - qc = self.qc_receiver.next() => { - //println!("Received qc msg in builder {}: {:?} from index", self.builder_keys.0, qc); - match qc { - Some(qc) => { - if let MessageType::QCMessage(rqc_msg) = qc { - println!("Received qc msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rqc_msg.proposal.data.view_number); - self.process_quorum_proposal(rqc_msg).await; } } - None => { - println!("No more qc messages to consume"); - } - } - } - decide = self.decide_receiver.next() => { - println!("Received decide msg in builder {}: {:?} from index", self.builder_keys.0, decide); - match decide { - Some(decide) => { - if let MessageType::DecideMessage(rdecide_msg) = decide { - println!("Received decide msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rdecide_msg); - let decide_status = self.process_decide_event(rdecide_msg).await; - match decide_status{ - Some(Status::ShouldExit) => { - break; - } - Some(Status::ShouldContinue) => { - continue; - } - None => { - continue; + da = self.da_proposal_receiver.next() => { + //println!("Received da proposal msg in builder {}: {:?} from index", self.builder_keys.0, da); + match da { + Some(da) => { + if let MessageType::DAProposalMessage(rda_msg) = da { + tracing::debug!("Received da proposal msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rda_msg.proposal.data.view_number); + self.process_da_proposal(rda_msg); } } + None => { + tracing::info!("No more da proposal messages to consume"); + } } } - None => { - println!("No more decide messages to consume"); - } - } - } - }; - - - // let (received_msg, channel_index, _)= select_all([self.tx_receiver.next().await, self.da_proposal_receiver.next().await, - // self.qc_receiver.next().await, self.decide_receiver.next().await,self.req_receiver.next().await]); - - // let mut x = select_all([self.tx_receiver.into_stream(), self.da_proposal_receiver, - // self.qc_receiver, self.decide_receiver,self.req_receiver]); - - // select! { - // received_tx_msg = self.tx_receiver.next().await.unwrap()=> { - // println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, received_tx_msg); - // if let Some(received_tx_msg) = received_tx_msg { - // if let MessageType::TransactionMessage(rtx_msg) = received_tx_msg { - // println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, rtx_msg); - // if rtx_msg.tx_type == TransactionSource::HotShot { - // self.process_hotshot_transaction(rtx_msg.tx).await; - // } else { - // self.process_external_transaction(rtx_msg.tx).await; - // } - // } - // } - // } - // } - - /* - let (received_msg, channel_index, _)= future::select_all([self.tx_receiver.recv(), self.da_proposal_receiver.recv(), - self.qc_receiver.recv(), self.decide_receiver.recv(),self.req_receiver.recv()]).await; - match received_msg { - Ok(received_msg) => { - - match received_msg { - - // request message - MessageType::RequestMessage(req) => { - println!("Received request msg in builder {}: {:?} from index {}", self.builder_keys.0, req, channel_index); - - self.process_block_request(req).await; - - } - - // transaction message - MessageType::TransactionMessage(rtx_msg) => { - println!("Received tx msg in builder {}: {:?} from index {}", self.builder_keys.0, rtx_msg, channel_index); - - //self.print_builder_state().await; - // get the content from the rtx_msg's inside vec - // Pass the tx msg to the handler - println!("Local tx_maps before processing the transaction:\n Tx_hash_to_available_txns: {:?} \nTimestamp to tx {:?}\n Included txns{:?}", - self.tx_hash_to_available_txns, self.timestamp_to_tx, self.included_txns); - - if rtx_msg.tx_type == TransactionSource::HotShot { - self.process_hotshot_transaction(rtx_msg.tx).await; - } else { - self.process_external_transaction(rtx_msg.tx).await; + qc = self.qc_receiver.next() => { + //println!("Received qc msg in builder {}: {:?} from index", self.builder_keys.0, qc); + match qc { + Some(qc) => { + if let MessageType::QCMessage(rqc_msg) = qc { + tracing::debug!("Received qc msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rqc_msg.proposal.data.view_number); + self.process_quorum_proposal(rqc_msg); + } + } + None => { + tracing::info!("No more qc messages to consume"); + } } - //self.print_builder_state().await; - println!("Local tx_maps after processing the transaction:\n Tx_hash_to_available_txns: {:?} \nTimestamp to tx {:?}\n Included txns{:?}", - self.tx_hash_to_available_txns, self.timestamp_to_tx, self.included_txns); - } - - // decide message - MessageType::DecideMessage(rdecide_msg) => { - println!("Received decide msg in builder {}: {:?} from index {}", self.builder_keys.0, rdecide_msg, channel_index); - // store in the rdecide_msgs - //self.print_builder_state().await; - let decide_status = self.process_decide_event(rdecide_msg).await; - //self.print_builder_state().await; - // TODO - // if should exit, then break out of the loop - match decide_status{ - Some(Status::ShouldExit) => { - break; - } - Some(Status::ShouldContinue) => { - continue; + decide = self.decide_receiver.next() => { + match decide { + Some(decide) => { + if let MessageType::DecideMessage(rdecide_msg) = decide { + tracing::debug!("Received decide msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rdecide_msg); + let decide_status = self.process_decide_event(rdecide_msg).await; + match decide_status{ + Some(Status::ShouldExit) => { + break; + } + Some(Status::ShouldContinue) => { + continue; + } + None => { + continue; + } + } + } } None => { - continue; + tracing::info!("No more decide messages to consume"); } } } - - // DA proposal message - MessageType::DAProposalMessage(rda_msg) => { - println!("Received da proposal msg in builder {}: {:?} from index {}", self.builder_keys.0, rda_msg, channel_index); - //self.print_builder_state().await; - // print only the keys in self.da_proposal_payload_commit_to_da_proposal map - println!("DA proposal payload commit to da proposal map keys before processing: {:?}", self.da_proposal_payload_commit_to_da_proposal.keys()); - self.process_da_proposal(rda_msg).await; - println!("DA proposal payload commit to da proposal map keys after processing: {:?}", self.da_proposal_payload_commit_to_da_proposal.keys()); - //self.print_builder_state().await; - - } - // QC proposal message - MessageType::QCMessage(rqc_msg) => { - println!("Received qc msg in builder {}: {:?} from index {}", self.builder_keys.0, rqc_msg, channel_index); - //self.print_builder_state().await; - println!("QC proposal payload commit to QC proposal map keys before processing: {:?}", self.quorum_proposal_payload_commit_to_quorum_proposal.keys()); - self.process_quorum_proposal(rqc_msg).await; - println!("QC proposal payload commit to QC proposal map keys before processing: {:?}", self.quorum_proposal_payload_commit_to_quorum_proposal.keys()); - - //self.print_builder_state().await; - } - } - + }; + } - Err(err) => { - println!("Error in builder event loop: {:?}", err); - if err == RecvError::Closed { - println!("The channel {} is closed", channel_index); - //break; - //channel_close_index.insert(channel_index); - } - else{ - println!("No more messages to consume {}", channel_index); - break; - } - } - } - - */ - }; - } - async fn event_loop(mut self){ - - //let builder_handle = task::spawn(async move{ - let builder_handle = async_spawn(async move{ - - //let mut x = futures::stream::select(self.tx_receiver, self.da_proposal_receiver); - - self.loop_function().await; }); - //builder_handle - builder_handle.await; - } } /// Unifies the possible messages that can be received by the builder diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 2b0b614f..c41c7630 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -4,12 +4,10 @@ //! Builder Phase 1 Testing //! - #![allow(unused_imports)] -use async_std::task::{self, Builder}; +use async_std::task; use std::sync::{Arc, Mutex}; use sha2::{Digest, Sha256}; -use futures::future::select_all; pub use hotshot_testing::{ block_types::{TestTransaction, TestBlockHeader, TestBlockPayload, genesis_vid_commitment}, state_types::{TestInstanceState, TestValidatedState}, @@ -26,19 +24,19 @@ pub use hotshot::traits::election::static_committee::{GeneralStaticCommittee, St pub use crate::builder_state::{BuilderState,MessageType, BuilderProgress, ResponseMessage}; pub use async_broadcast::{broadcast, TryRecvError, Sender as BroadcastSender, Receiver as BroadcastReceiver, RecvError}; // tests -use commit::{Commitment, Committable, CommitmentBoundsArkless}; +use commit::{Commitment, CommitmentBoundsArkless}; use async_compatibility_layer::art::{async_sleep, async_spawn}; +use tracing; /// The following tests are performed: #[cfg(test)] mod tests { - use core::num; - use std::{collections::HashSet, env, hash::Hash, marker::PhantomData}; + use std::{hash::Hash, marker::PhantomData}; - use async_compatibility_layer::channel::{unbounded, UnboundedReceiver}; - use hotshot::{rand::seq::index, types::SignatureKey}; - use hotshot_testing::state_types::TestTypes; + use async_compatibility_layer::channel::unbounded; + use hotshot::types::SignatureKey; use hotshot_types::{data::QuorumProposal, message::Message, traits::{block_contents::{vid_commitment, BlockHeader}, election::Membership}, vote::HasViewNumber}; + //use tracing::instrument; use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage, RequestMessage}; use crate::service::GlobalState; @@ -54,9 +52,11 @@ mod tests { const TEST_NUM_NODES_IN_VID_COMPUTATION: usize = 4; /// This test simulates multiple builders receiving messages from the channels and processing them #[async_std::test] + //#[instrument] async fn test_channel(){ - //env::set_var("RUST_ASYNC_STD_THREAD_COUNT", "10"); - println!("Testing the channel"); + async_compatibility_layer::logging::setup_logging(); + async_compatibility_layer::logging::setup_backtrace(); + tracing::info!("Testing the builder core with multiple messages from the channels"); #[derive( Copy, Clone, @@ -87,12 +87,12 @@ mod tests { let multiplication_factor = 5; // settingup the broadcast channels i.e [From hostshot: (tx, decide, da, qc, )], [From api:(req - broadcast, res - mpsc channel) ] - let (tx_sender, mut tx_receiver) = broadcast::>(num_test_messages*multiplication_factor); - let (decide_sender, mut decide_receiver) = broadcast::>(num_test_messages*multiplication_factor); - let (da_sender, mut da_receiver) = broadcast::>(num_test_messages*multiplication_factor); - let (qc_sender, mut qc_receiver) = broadcast::>(num_test_messages*multiplication_factor); - let (req_sender, mut req_receiver) = broadcast::>(num_test_messages*multiplication_factor); - let (res_sender, mut res_receiver) = unbounded(); + let (tx_sender, tx_receiver) = broadcast::>(num_test_messages*multiplication_factor); + let (decide_sender, decide_receiver) = broadcast::>(num_test_messages*multiplication_factor); + let (da_sender, da_receiver) = broadcast::>(num_test_messages*multiplication_factor); + let (qc_sender, qc_receiver) = broadcast::>(num_test_messages*multiplication_factor); + let (req_sender, req_receiver) = broadcast::>(num_test_messages*multiplication_factor); + let (res_sender, res_receiver) = unbounded(); // to store all the sent messages let mut stx_msgs = Vec::new(); @@ -114,7 +114,7 @@ mod tests { tx: tx.clone(), tx_type: TransactionSource::HotShot, }; - + tracing::debug!("Sending transaction message: {:?}", stx_msg); // Prepare the decide message let qc = QuorumCertificate::::genesis(); let sdecide_msg = DecideMessage::{ @@ -149,9 +149,9 @@ mod tests { }; // calculate the vid commitment over the encoded_transactions - println!("Encoded transactions: {:?}\n Num nodes:{}", encoded_transactions, TEST_NUM_NODES_IN_VID_COMPUTATION); + tracing::debug!("Encoded transactions: {:?}\n Num nodes:{}", encoded_transactions, TEST_NUM_NODES_IN_VID_COMPUTATION); let encoded_txns_vid_commitment = vid_commitment(&encoded_transactions, TEST_NUM_NODES_IN_VID_COMPUTATION); - println!("Encoded transactions vid commitment: {:?}", encoded_txns_vid_commitment); + tracing::debug!("Encoded transactions vid commitment: {:?}", encoded_txns_vid_commitment); let block_header = TestBlockHeader{ block_number: i as u64, payload_commitment: encoded_txns_vid_commitment, @@ -235,9 +235,9 @@ mod tests { tx_receiver, decide_receiver, da_receiver, qc_receiver, req_receiver, global_state, res_sender, Arc::new(quorum_membershiop)); //builder_state.event_loop().await; - builder_state.event_loop().await; + builder_state.event_loop(); }); handle.await; - + task::sleep(std::time::Duration::from_secs(240)).await; } } From 4eb00691292a37d5bfdb25cd8ca4b8dfe5b20df4 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Fri, 9 Feb 2024 18:22:59 -0500 Subject: [PATCH 38/47] some more cleanup --- src/service.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/service.rs b/src/service.rs index 3dbc7e41..9b27e3fc 100644 --- a/src/service.rs +++ b/src/service.rs @@ -51,18 +51,15 @@ pub struct Options { // #[derive(Debug)] pub struct GlobalState{ - //pub block_hash_to_block: HashMap, pub block_hash_to_block: HashMap::BlockPayload as BlockPayload>::Metadata, Arc>, <::SignatureKey as SignatureKey>::PureAssembledSignatureType,Types::SignatureKey)>, - //pub vid_to_potential_builder_state: HashMap>, pub request_sender: BroadcastSender>, pub response_receiver: UnboundedReceiver>, } impl GlobalState{ pub fn remove_handles(&mut self, vidcommitment: VidCommitment, block_hashes: Vec) { - //self.vid_to_potential_builder_state.remove(&vidcommitment); - println!("Removing handles for vid commitment {:?}", vidcommitment); + tracing::info!("Removing handles for vid commitment {:?}", vidcommitment); for block_hash in block_hashes { self.block_hash_to_block.remove(&block_hash); } @@ -237,7 +234,7 @@ pub async fn run_standalone_builder_service { - println!("View Finished Event for view number: {:?}", view_number); + tracing::info!("View Finished Event for view number: {:?}", view_number); unimplemented!("View Finished Event"); } _ => { From 96300bddc3b6b58b6ece386698048b327349f81d Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 12 Feb 2024 10:32:54 -0500 Subject: [PATCH 39/47] some cleanup --- src/testing/basic_test.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index c41c7630..b7c3d329 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -206,33 +206,35 @@ mod tests { sreq_msgs.push(request_message); } - // instantiate the global state also - let global_state = Arc::new(RwLock::new(GlobalState::::new(req_sender, res_receiver))); - - let seed = [201 as u8; 32]; - let (builder_pub_key, builder_private_key) = BLSPubKey::generated_from_seed_indexed(seed,2011 as u64); - + + // form the quorum election config, required for the VID computation inside the builder_state let quorum_election_config = <::Membership as Membership>::default_election_config(TEST_NUM_NODES_IN_VID_COMPUTATION as u64); let mut commitee_stake_table_entries = vec![]; for i in 0..TEST_NUM_NODES_IN_VID_COMPUTATION { - let (pub_key, private_key) = BLSPubKey::generated_from_seed_indexed([i as u8; 32],i as u64); + let (pub_key, _private_key) = BLSPubKey::generated_from_seed_indexed([i as u8; 32],i as u64); let stake = i as u64; commitee_stake_table_entries.push(pub_key.get_stake_table_entry(stake)); } - - let quorum_membershiop = <::Membership as Membership>::create_election( + + let quorum_membership = <::Membership as Membership>::create_election( commitee_stake_table_entries, quorum_election_config ); - assert_eq!(quorum_membershiop.total_nodes(), TEST_NUM_NODES_IN_VID_COMPUTATION); + assert_eq!(quorum_membership.total_nodes(), TEST_NUM_NODES_IN_VID_COMPUTATION); + // instantiate the global state also + let global_state = Arc::new(RwLock::new(GlobalState::::new(req_sender, res_receiver))); + + // generate the keys for the buidler + let seed = [201 as u8; 32]; + let (builder_pub_key, builder_private_key) = BLSPubKey::generated_from_seed_indexed(seed,2011 as u64); let handle = async_spawn(async move{ let mut builder_state = BuilderState::::new((builder_pub_key, builder_private_key), (ViewNumber::new(0), genesis_vid_commitment(), Commitment::>::default_commitment_no_preimage()), - tx_receiver, decide_receiver, da_receiver, qc_receiver, req_receiver, global_state, res_sender, Arc::new(quorum_membershiop)); + tx_receiver, decide_receiver, da_receiver, qc_receiver, req_receiver, global_state, res_sender, Arc::new(quorum_membership)); //builder_state.event_loop().await; builder_state.event_loop(); From 5dfc88efa21130b3b68b1c62a393383e6c53bba5 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 12 Feb 2024 13:55:51 -0500 Subject: [PATCH 40/47] add api request handling --- src/builder_state.rs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 706c854f..360dc370 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -520,7 +520,27 @@ impl BuilderProgress for BuilderState{ loop{ + while let Ok(req) = self.req_receiver.try_recv() { + println!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); + if let MessageType::RequestMessage(req) = req { + self.process_block_request(req).await; + } + }; + futures::select!{ + req = self.req_receiver.next() => { + println!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); + match req { + Some(req) => { + if let MessageType::RequestMessage(req) = req { + self.process_block_request(req).await; + } + } + None => { + tracing::info!("No more request messages to consume"); + } + } + }, tx = self.tx_receiver.next() => { //println!("Received tx msg in builder {}: {:?} from index", self.builder_keys.0, tx); match tx { @@ -543,7 +563,7 @@ impl BuilderProgress for BuilderState{ tracing::info!("No more tx messages to consume"); } } - } + }, da = self.da_proposal_receiver.next() => { //println!("Received da proposal msg in builder {}: {:?} from index", self.builder_keys.0, da); match da { @@ -557,7 +577,7 @@ impl BuilderProgress for BuilderState{ tracing::info!("No more da proposal messages to consume"); } } - } + }, qc = self.qc_receiver.next() => { //println!("Received qc msg in builder {}: {:?} from index", self.builder_keys.0, qc); match qc { @@ -571,7 +591,7 @@ impl BuilderProgress for BuilderState{ tracing::info!("No more qc messages to consume"); } } - } + }, decide = self.decide_receiver.next() => { match decide { Some(decide) => { @@ -595,7 +615,7 @@ impl BuilderProgress for BuilderState{ tracing::info!("No more decide messages to consume"); } } - } + }, }; } From 1c0b618e66778ec7c34ca797b033abeaef2fa1ac Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 12 Feb 2024 14:04:35 -0500 Subject: [PATCH 41/47] dynamic qc, da, decide messages --- src/testing/basic_test.rs | 137 +++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 40 deletions(-) diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index b7c3d329..7c63a54f 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -13,9 +13,12 @@ pub use hotshot_testing::{ state_types::{TestInstanceState, TestValidatedState}, }; pub use hotshot_types::{ - traits::node_implementation::{NodeType as BuilderType, ConsensusTime}, + traits::{ + node_implementation::{NodeType as BuilderType, ConsensusTime, NodeType}, + block_contents::BlockPayload, + }, data::{ViewNumber, Leaf, DAProposal, QuorumProposal}, - simple_certificate::QuorumCertificate, + simple_certificate::{QuorumCertificate,SimpleCertificate, SuccessThreshold}, signature_key::{BLSPubKey,BLSPrivKey}, message::Proposal, }; @@ -34,8 +37,9 @@ mod tests { use std::{hash::Hash, marker::PhantomData}; use async_compatibility_layer::channel::unbounded; + use commit::Committable; use hotshot::types::SignatureKey; - use hotshot_types::{data::QuorumProposal, message::Message, traits::{block_contents::{vid_commitment, BlockHeader}, election::Membership}, vote::HasViewNumber}; + use hotshot_types::{data::QuorumProposal, message::Message, simple_certificate::Threshold, simple_vote::QuorumData, traits::{block_contents::{vid_commitment, BlockHeader}, election::Membership}, utils::View, vote::{Certificate, HasViewNumber}}; //use tracing::instrument; use crate::builder_state::{TransactionMessage, TransactionSource, DecideMessage, DAProposalMessage, QCMessage, RequestMessage}; @@ -95,115 +99,168 @@ mod tests { let (res_sender, res_receiver) = unbounded(); // to store all the sent messages - let mut stx_msgs = Vec::new(); - let mut sdecide_msgs = Vec::new(); - let mut sda_msgs = Vec::new(); - let mut sqc_msgs = Vec::new(); - let mut sreq_msgs = Vec::new(); + let mut stx_msgs: Vec> = Vec::new(); + let mut sdecide_msgs: Vec> = Vec::new(); + let mut sda_msgs: Vec> = Vec::new(); + let mut sqc_msgs: Vec> = Vec::new(); + let mut sreq_msgs: Vec> = Vec::new(); let mut sres_msgs: Vec> = Vec::new(); // generate num_test messages for each type and send it to the respective channels; for i in 0..num_test_messages as u32{ - // pass a msg to the tx channel + + // Prepare the transaction message let tx = TestTransaction(vec![i as u8]); let encoded_transactions = TestTransaction::encode(vec![tx.clone()]).unwrap(); - // Prepare the transaction message let stx_msg = TransactionMessage::{ tx: tx.clone(), tx_type: TransactionSource::HotShot, }; - tracing::debug!("Sending transaction message: {:?}", stx_msg); - // Prepare the decide message - let qc = QuorumCertificate::::genesis(); - let sdecide_msg = DecideMessage::{ - leaf_chain: Arc::new(vec![Leaf::genesis(&TestInstanceState {})]), - qc: Arc::new(qc), - block_size: Some(i as u64), - }; - + // Prepare the DA proposal message let da_proposal = DAProposal { encoded_transactions: encoded_transactions.clone(), metadata: (), - view_number: ViewNumber::new((i+1) as u64), + view_number: ViewNumber::new(i as u64), }; let encoded_transactions_hash = Sha256::digest(&encoded_transactions); let seed = [i as u8; 32]; let (pub_key, private_key) = BLSPubKey::generated_from_seed_indexed(seed,i as u64); let da_signature = - ::SignatureKey::sign( - &private_key, - &encoded_transactions_hash, - ) - .expect("Failed to sign encoded tx hash while preparing da proposal"); + ::SignatureKey::sign( + &private_key, + &encoded_transactions_hash, + ) + .expect("Failed to sign encoded tx hash while preparing da proposal"); + let sda_msg = DAProposalMessage::{ proposal: Proposal{ - data: da_proposal, - signature: da_signature.clone(), - _pd: PhantomData - }, + data: da_proposal, + signature: da_signature.clone(), + _pd: PhantomData + }, sender: pub_key, total_nodes: TEST_NUM_NODES_IN_VID_COMPUTATION, }; + // Prepare the QC proposal message // calculate the vid commitment over the encoded_transactions tracing::debug!("Encoded transactions: {:?}\n Num nodes:{}", encoded_transactions, TEST_NUM_NODES_IN_VID_COMPUTATION); let encoded_txns_vid_commitment = vid_commitment(&encoded_transactions, TEST_NUM_NODES_IN_VID_COMPUTATION); tracing::debug!("Encoded transactions vid commitment: {:?}", encoded_txns_vid_commitment); + let block_header = TestBlockHeader{ block_number: i as u64, payload_commitment: encoded_txns_vid_commitment, }; - // Prepare the QC proposal message - //let qc_signature = da_signature.clone(); + + let justify_qc = match i{ + 0 => QuorumCertificate::::genesis(), + _ => { + let previous_qc = sqc_msgs[(i-1) as usize].proposal.data.justify_qc.clone(); + // Construct a leaf + + //let metadata = block_header.metadata(); + let metadata = sqc_msgs[(i-1) as usize].proposal.data.block_header.metadata(); + + let leaf: Leaf<_> = Leaf { + view_number: sqc_msgs[(i-1) as usize].proposal.data.view_number.clone(), + justify_qc: sqc_msgs[(i-1) as usize].proposal.data.justify_qc.clone(), + parent_commitment: sqc_msgs[(i-1) as usize].proposal.data.justify_qc.get_data().leaf_commit, + block_header: sqc_msgs[(i-1) as usize].proposal.data.block_header.clone(), + block_payload: Some(BlockPayload::from_bytes(sda_msgs[(i-1) as usize].proposal.data.encoded_transactions.clone().into_iter(), metadata)), + proposer_id: sqc_msgs[(i-1) as usize].proposal.data.proposer_id, + }; + let q_data = QuorumData::{ + leaf_commit: leaf.commit(), + }; + let justify_qc = SimpleCertificate::, SuccessThreshold>{ + data: q_data.clone(), + vote_commitment: q_data.commit(), + view_number: previous_qc.get_view_number(), + signatures: previous_qc.signatures.clone(), + is_genesis: true, // todo setting true because we don't have signatures of QCType + _pd: PhantomData, + }; + justify_qc + }, + }; + + //::SignatureKey::sign(private_key, encoded_txns_vid_commitment.as_ref()).unwrap(), let qc_proposal = QuorumProposal::{ //block_header: TestBlockHeader::genesis(&TestInstanceState {}).0, block_header: block_header, - view_number: ViewNumber::new((i+1) as u64), - justify_qc: QuorumCertificate::::genesis(), + view_number: ViewNumber::new(i as u64), + justify_qc: justify_qc.clone(), timeout_certificate: None, proposer_id: pub_key }; let payload_commitment = qc_proposal.block_header.payload_commitment(); - + // let leaf_commit = qc_proposal.justify_qc.data.commit(); let qc_signature = ::SignatureKey::sign( &private_key, payload_commitment.as_ref(), ).expect("Failed to sign payload commitment while preparing QC proposal"); - - let requested_vid_commitment = qc_proposal.block_header.payload_commitment(); + let sqc_msg = QCMessage::{ proposal: Proposal{ - data:qc_proposal, + data:qc_proposal.clone(), signature: qc_signature, _pd: PhantomData }, sender: pub_key, }; + // Prepare the decide message + // let qc = QuorumCertificate::::genesis(); + let leaf = match i{ + 0 => Leaf::genesis(&TestInstanceState {}), + _ => { + let current_leaf: Leaf<_> = Leaf { + view_number: ViewNumber::new(i as u64), + justify_qc: justify_qc.clone(), + parent_commitment: sqc_msgs[(i-1) as usize].proposal.data.justify_qc.get_data().leaf_commit, + block_header: qc_proposal.block_header.clone(), + block_payload: Some(BlockPayload::from_bytes(encoded_transactions.clone().into_iter(), qc_proposal.block_header.metadata())), + proposer_id: qc_proposal.proposer_id, + }; + current_leaf + }, + }; + + + + let sdecide_msg = DecideMessage::{ + leaf_chain: Arc::new(vec![leaf.clone()]), + qc: Arc::new(justify_qc), + block_size: Some(encoded_transactions.len() as u64), + }; + // validate the signature before pushing the message to the builder_state channels // currently this step happens in the service.rs, wheneve we receiver an hotshot event + tracing::debug!("Sending transaction message: {:?}", stx_msg); tx_sender.broadcast(MessageType::TransactionMessage(stx_msg.clone())).await.unwrap(); da_sender.broadcast(MessageType::DAProposalMessage(sda_msg.clone())).await.unwrap(); qc_sender.broadcast(MessageType::QCMessage(sqc_msg.clone())).await.unwrap(); //decide_sender.broadcast(MessageType::DecideMessage(sdecide_msg.clone())).await.unwrap(); - + //TODO: sending request message onto channel also // send the request message as well + let requested_vid_commitment = payload_commitment; let request_message = MessageType::::RequestMessage(RequestMessage{ requested_vid_commitment: requested_vid_commitment, }); stx_msgs.push(stx_msg); - sdecide_msgs.push(sdecide_msg); + //sdecide_msgs.push(sdecide_msg); sda_msgs.push(sda_msg); sqc_msgs.push(sqc_msg); - sreq_msgs.push(request_message); + //sreq_msgs.push(request_message); } From 9f6b727bb691ae9868071b047577819803b743c3 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 12 Feb 2024 15:42:45 -0500 Subject: [PATCH 42/47] add more tracing details --- src/builder_state.rs | 77 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 360dc370..3f89c875 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -212,6 +212,10 @@ impl BuilderProgress for BuilderState{ } /// processing the hotshot i.e public mempool transaction + #[tracing::instrument(skip_all, name = "process hotshot transaction", + fields(builder_view=%self.built_from_view_vid_leaf.0.get_u64(), + builder_vid=%self.built_from_view_vid_leaf.1.clone(), + builder_leaf=%self.built_from_view_vid_leaf.2.clone()))] fn process_hotshot_transaction(&mut self, tx: TYPES::Transaction) { let tx_hash = tx.commit(); @@ -231,6 +235,11 @@ impl BuilderProgress for BuilderState{ } /// processing the DA proposal + //#[tracing::instrument(skip_all, name = "Process DA Proposal", fields(builder_id=%self.built_from_view_vid_leaf.0.get_u64(), builder_commitments=%self.built_from_view_vid_leaf.1.clone()))] + #[tracing::instrument(skip_all, name = "process da proposal", + fields(builder_view=%self.built_from_view_vid_leaf.0.get_u64(), + builder_vid=%self.built_from_view_vid_leaf.1.clone(), + builder_leaf=%self.built_from_view_vid_leaf.2.clone()))] fn process_da_proposal(&mut self, da_msg: DAProposalMessage) { // Validation @@ -271,9 +280,17 @@ impl BuilderProgress for BuilderState{ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(qc_proposal_data) = self.quorum_proposal_payload_commit_to_quorum_proposal.entry(payload_vid_commitment.clone()) { let qc_proposal_data = qc_proposal_data.remove(); - self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender); - // register the clone to the global state - //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); + + // make sure we don't clone for the bootstrapping da and qc proposals + if qc_proposal_data.view_number.get_u64() != 0 { + tracing::info!("Spawning a clone"); + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender); + // register the clone to the global state + //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); + } + else { + tracing::info!("Not spawning a clone despite matching DA and QC proposals, as they corresponds to bootstrapping phase"); + } } else { self.da_proposal_payload_commit_to_da_proposal.insert(payload_vid_commitment, da_proposal_data); } @@ -282,6 +299,11 @@ impl BuilderProgress for BuilderState{ } /// processing the quorum proposal + //#[tracing::instrument(skip_all, name = "Process Quorum Proposal")] + #[tracing::instrument(skip_all, name = "process quorum proposal", + fields(builder_view=%self.built_from_view_vid_leaf.0.get_u64(), + builder_vid=%self.built_from_view_vid_leaf.1.clone(), + builder_leaf=%self.built_from_view_vid_leaf.2.clone()))] fn process_quorum_proposal(&mut self, qc_msg: QCMessage) { // Validation @@ -310,10 +332,17 @@ impl BuilderProgress for BuilderState{ // if we have matching da and quorum proposals, we can skip storing the one, and remove the other from storage, and call build_block with both, to save a little space. if let Entry::Occupied(da_proposal_data) = self.da_proposal_payload_commit_to_da_proposal.entry(payload_vid_commitment.clone()) { let da_proposal_data = da_proposal_data.remove(); - self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender); - // registed the clone to the global state - //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); - + + // make sure we don't clone for the bootstrapping da and qc proposals + if da_proposal_data.view_number.get_u64() != 0 { + tracing::info!("Spawning a clone"); + self.clone().spawn_clone(da_proposal_data, qc_proposal_data, sender); + // registed the clone to the global state + //self.global_state.get_mut().vid_to_potential_builder_state.insert(payload_vid_commitment, self_clone); + } + else{ + tracing::info!("Not spawning a clone despite matching DA and QC proposals, as they corresponds to bootstrapping phase"); + } } else { self.quorum_proposal_payload_commit_to_quorum_proposal.insert(payload_vid_commitment, qc_proposal_data.clone()); } @@ -322,6 +351,10 @@ impl BuilderProgress for BuilderState{ } /// processing the decide event + #[tracing::instrument(skip_all, name = "process decide event", + fields(builder_view=%self.built_from_view_vid_leaf.0.get_u64(), + builder_vid=%self.built_from_view_vid_leaf.1.clone(), + builder_leaf=%self.built_from_view_vid_leaf.2.clone()))] async fn process_decide_event(&mut self, decide_msg: DecideMessage) -> Option { @@ -391,9 +424,12 @@ impl BuilderProgress for BuilderState{ } // spawn a clone of the builder state + #[tracing::instrument(skip_all, name = "spwan_clone", + fields(builder_view=%self.built_from_view_vid_leaf.0.get_u64(), + builder_vid=%self.built_from_view_vid_leaf.1.clone(), + builder_leaf=%self.built_from_view_vid_leaf.2.clone()))] fn spawn_clone(mut self, da_proposal: DAProposal, quorum_proposal: QuorumProposal, leader: TYPES::SignatureKey) { - tracing::debug!("Spawning a clone"); self.built_from_view_vid_leaf.0 = quorum_proposal.view_number; self.built_from_view_vid_leaf.1 = quorum_proposal.block_header.payload_commitment(); @@ -424,7 +460,11 @@ impl BuilderProgress for BuilderState{ self.event_loop(); } - // build a block + // build a block + #[tracing::instrument(skip_all, name = "build block", + fields(builder_view=%self.built_from_view_vid_leaf.0.get_u64(), + builder_vid=%self.built_from_view_vid_leaf.1.clone(), + builder_leaf=%self.built_from_view_vid_leaf.2.clone()))] fn build_block(&mut self, _matching_vid: VidCommitment) -> Option>{ if let Ok((payload, metadata)) = ::from_transactions( @@ -514,14 +554,17 @@ impl BuilderProgress for BuilderState{ } } - #[tracing::instrument(skip_all, name = "Builder Event Loop")] + #[tracing::instrument(skip_all, name = "event loop", + fields(builder_view=%self.built_from_view_vid_leaf.0.get_u64(), + builder_vid=%self.built_from_view_vid_leaf.1.clone(), + builder_leaf=%self.built_from_view_vid_leaf.2.clone()))] fn event_loop(mut self){ let _builder_handle = async_spawn(async move{ loop{ while let Ok(req) = self.req_receiver.try_recv() { - println!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); + tracing::info!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); if let MessageType::RequestMessage(req) = req { self.process_block_request(req).await; } @@ -529,7 +572,7 @@ impl BuilderProgress for BuilderState{ futures::select!{ req = self.req_receiver.next() => { - println!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); + tracing::info!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); match req { Some(req) => { if let MessageType::RequestMessage(req) = req { @@ -546,7 +589,7 @@ impl BuilderProgress for BuilderState{ match tx { Some(tx) => { if let MessageType::TransactionMessage(rtx_msg) = tx { - //tracing::debug!("Received tx msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rtx_msg); + tracing::debug!("Received tx msg in builder {:?}:\n {:?}", self.built_from_view_vid_leaf, rtx_msg); if rtx_msg.tx_type == TransactionSource::HotShot { self.process_hotshot_transaction(rtx_msg.tx); } else { @@ -565,11 +608,11 @@ impl BuilderProgress for BuilderState{ } }, da = self.da_proposal_receiver.next() => { - //println!("Received da proposal msg in builder {}: {:?} from index", self.builder_keys.0, da); match da { Some(da) => { if let MessageType::DAProposalMessage(rda_msg) = da { - tracing::debug!("Received da proposal msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rda_msg.proposal.data.view_number); + tracing::debug!("Received da proposal msg in builder {:?}:\n {:?}", self.built_from_view_vid_leaf, rda_msg); + //tracing::debug!("Received da proposal msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rda_msg.proposal.data.view_number); self.process_da_proposal(rda_msg); } } @@ -583,7 +626,7 @@ impl BuilderProgress for BuilderState{ match qc { Some(qc) => { if let MessageType::QCMessage(rqc_msg) = qc { - tracing::debug!("Received qc msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rqc_msg.proposal.data.view_number); + tracing::debug!("Received qc msg in builder {:?}:\n {:?} from index", self.built_from_view_vid_leaf, rqc_msg); self.process_quorum_proposal(rqc_msg); } } @@ -596,7 +639,7 @@ impl BuilderProgress for BuilderState{ match decide { Some(decide) => { if let MessageType::DecideMessage(rdecide_msg) = decide { - tracing::debug!("Received decide msg in builder {:?}: {:?} from index", self.built_from_view_vid_leaf.0, rdecide_msg); + tracing::debug!("Received decide msg in builder {:?}:\n {:?} from index", self.built_from_view_vid_leaf, rdecide_msg); let decide_status = self.process_decide_event(rdecide_msg).await; match decide_status{ Some(Status::ShouldExit) => { From 87c25cb16d6d78c966820839b529ee7b94bfb5ef Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Mon, 12 Feb 2024 18:34:27 -0500 Subject: [PATCH 43/47] working test --- src/builder_state.rs | 50 ++++++++++++++++++++++++++++----------- src/testing/basic_test.rs | 48 +++++++++++++++++++++++++++++-------- 2 files changed, 74 insertions(+), 24 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index 3f89c875..addbd981 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -317,11 +317,15 @@ impl BuilderProgress for BuilderState{ if self.built_from_view_vid_leaf.0.get_u64() == 0{ tracing::info!("In bootstrapping phase"); } - else if qc_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0 || - qc_msg.proposal.data.justify_qc.get_data().leaf_commit != self.built_from_view_vid_leaf.2 { - tracing::info!("Either View number or leaf commit does not match the built-in info, so ignoring it"); - return; + else if qc_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0{ + tracing::info!("Either View number or leaf commit does not match the built-in info, so ignoring it"); + return; } + // else if qc_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0 || + // qc_msg.proposal.data.justify_qc.get_data().leaf_commit != self.built_from_view_vid_leaf.2 { + // tracing::info!("Either View number or leaf commit does not match the built-in info, so ignoring it"); + // return; + // } let qc_proposal_data = qc_msg.proposal.data; let sender = qc_msg.sender; @@ -376,7 +380,11 @@ impl BuilderProgress for BuilderState{ // handle the case when we hear a decide event before we have atleast one clone, in that case, we might exit the builder // and not make any progress; so we need to handle that case // Adhoc logic: if the number of subscrived receivers are more than 1, it means that there exists a clone and we can safely exit - if self.built_from_view_vid_leaf.0.get_u64() == 0 && self.tx_receiver.receiver_count() <=1 { + // if self.built_from_view_vid_leaf.0.get_u64() == 0 && self.tx_receiver.receiver_count() <=1 { + // tracing::info!("In bootstrapping phase"); + // //return Some(Status::ShouldContinue); + // } + if self.built_from_view_vid_leaf.0.get_u64() == 0{ tracing::info!("In bootstrapping phase"); //return Some(Status::ShouldContinue); } @@ -466,7 +474,7 @@ impl BuilderProgress for BuilderState{ builder_vid=%self.built_from_view_vid_leaf.1.clone(), builder_leaf=%self.built_from_view_vid_leaf.2.clone()))] fn build_block(&mut self, _matching_vid: VidCommitment) -> Option>{ - + if let Ok((payload, metadata)) = ::from_transactions( self.timestamp_to_tx.iter().filter_map(|(_ts, tx_hash)| { self.tx_hash_to_available_txns.get(tx_hash).map(|(_ts, tx, _source)| { @@ -507,27 +515,33 @@ impl BuilderProgress for BuilderState{ let vid = VidScheme::new(chunk_size, num_quorum_committee, &srs).unwrap(); vid.disperse(encoded_txns).unwrap(); }); - + + // let join_handle = task::spawn(async move{ + // println!("Calculating VID"); + // }); //self.global_state.write().block_hash_to_block.insert(block_hash, (payload, metadata, join_handle)); //let mut global_state = self.global_state.write().unwrap(); //self.global_state.write_arc().await.block_hash_to_block.insert(block_hash.clone(), (payload, metadata, join_handle)); // to sign combine the block_hash i.e builder commitment, block size and offered fee let mut combined_bytes: Vec = Vec::new(); - combined_bytes.extend_from_slice(&block_size.to_be_bytes()); + // TODO: see why it is signing is not working with 48 bytes, however it is working with 32 bytes + //combined_bytes.extend_from_slice(&block_size.to_ne_bytes()); combined_bytes.extend_from_slice(block_hash.as_ref()); - combined_bytes.extend_from_slice(&offered_fee.to_be_bytes()); + //combined_bytes.extend_from_slice(&offered_fee.to_ne_bytes()); let signature_over_block_info = ::SignatureKey::sign( - &self.builder_keys.1, combined_bytes.as_slice()) - .expect("Failed to sign tx hash"); + &self.builder_keys.1, combined_bytes.as_ref() + ).expect("Failed to sign tx hash"); //let signature = self.builder_keys.0.sign(&block_hash); return Some(ResponseMessage{block_hash: block_hash, block_size: block_size, offered_fee: offered_fee, block_payload: payload, metadata: metadata, join_handle: Arc::new(join_handle), signature: signature_over_block_info, sender: self.builder_keys.0.clone()}); }; - tracing::warn!("build the block, returning None"); + + + tracing::warn!("build block, returning None"); None } @@ -538,6 +552,8 @@ impl BuilderProgress for BuilderState{ let response = self.build_block(requested_vid_commitment); match response{ Some(response)=>{ + + tracing::info!("Builder {:?} Sending response {:?} to the request{:?}", self.built_from_view_vid_leaf, response, req); // send the response back self.response_sender.send(response.clone()).await.unwrap(); //let inner = Arc::unwrap_or_clone(response.join_handle); @@ -553,6 +569,9 @@ impl BuilderProgress for BuilderState{ } } + else { + tracing::info!("Builder {:?} Requested VID commitment does not match the built_from_view, so ignoring it", self.built_from_view_vid_leaf); + } } #[tracing::instrument(skip_all, name = "event loop", fields(builder_view=%self.built_from_view_vid_leaf.0.get_u64(), @@ -564,7 +583,7 @@ impl BuilderProgress for BuilderState{ loop{ while let Ok(req) = self.req_receiver.try_recv() { - tracing::info!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); + tracing::info!("Received request msg in builder {:?}: {:?}", self.built_from_view_vid_leaf, req); if let MessageType::RequestMessage(req) = req { self.process_block_request(req).await; } @@ -572,7 +591,7 @@ impl BuilderProgress for BuilderState{ futures::select!{ req = self.req_receiver.next() => { - tracing::info!("Received request msg in builder {}: {:?} from index", self.builder_keys.0, req); + tracing::info!("Received request msg in builder {:?}: {:?}", self.built_from_view_vid_leaf, req); match req { Some(req) => { if let MessageType::RequestMessage(req) = req { @@ -643,12 +662,15 @@ impl BuilderProgress for BuilderState{ let decide_status = self.process_decide_event(rdecide_msg).await; match decide_status{ Some(Status::ShouldExit) => { + tracing::debug!("Exiting the builder {:?}", self.built_from_view_vid_leaf); break; } Some(Status::ShouldContinue) => { + tracing::debug!("continue the builder {:?}", self.built_from_view_vid_leaf); continue; } None => { + tracing::debug!("None type: continue the builder {:?}", self.built_from_view_vid_leaf); continue; } } diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 7c63a54f..0fa3fcca 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -53,7 +53,6 @@ mod tests { } use super::*; - const TEST_NUM_NODES_IN_VID_COMPUTATION: usize = 4; /// This test simulates multiple builders receiving messages from the channels and processing them #[async_std::test] //#[instrument] @@ -89,6 +88,7 @@ mod tests { // no of test messages to send let num_test_messages = 3; let multiplication_factor = 5; + const TEST_NUM_NODES_IN_VID_COMPUTATION: usize = 4; // settingup the broadcast channels i.e [From hostshot: (tx, decide, da, qc, )], [From api:(req - broadcast, res - mpsc channel) ] let (tx_sender, tx_receiver) = broadcast::>(num_test_messages*multiplication_factor); @@ -104,7 +104,7 @@ mod tests { let mut sda_msgs: Vec> = Vec::new(); let mut sqc_msgs: Vec> = Vec::new(); let mut sreq_msgs: Vec> = Vec::new(); - let mut sres_msgs: Vec> = Vec::new(); + let mut rres_msgs: Vec> = Vec::new(); // generate num_test messages for each type and send it to the respective channels; @@ -147,7 +147,7 @@ mod tests { // Prepare the QC proposal message // calculate the vid commitment over the encoded_transactions - tracing::debug!("Encoded transactions: {:?}\n Num nodes:{}", encoded_transactions, TEST_NUM_NODES_IN_VID_COMPUTATION); + tracing::debug!("Encoded transactions: {:?} Num nodes:{}", encoded_transactions, TEST_NUM_NODES_IN_VID_COMPUTATION); let encoded_txns_vid_commitment = vid_commitment(&encoded_transactions, TEST_NUM_NODES_IN_VID_COMPUTATION); tracing::debug!("Encoded transactions vid commitment: {:?}", encoded_txns_vid_commitment); @@ -170,12 +170,15 @@ mod tests { justify_qc: sqc_msgs[(i-1) as usize].proposal.data.justify_qc.clone(), parent_commitment: sqc_msgs[(i-1) as usize].proposal.data.justify_qc.get_data().leaf_commit, block_header: sqc_msgs[(i-1) as usize].proposal.data.block_header.clone(), + // todo currently this is set to None in builder_state, see whether needs to make None here also block_payload: Some(BlockPayload::from_bytes(sda_msgs[(i-1) as usize].proposal.data.encoded_transactions.clone().into_iter(), metadata)), proposer_id: sqc_msgs[(i-1) as usize].proposal.data.proposer_id, }; + let q_data = QuorumData::{ leaf_commit: leaf.commit(), }; + let justify_qc = SimpleCertificate::, SuccessThreshold>{ data: q_data.clone(), vote_commitment: q_data.commit(), @@ -247,6 +250,9 @@ mod tests { tx_sender.broadcast(MessageType::TransactionMessage(stx_msg.clone())).await.unwrap(); da_sender.broadcast(MessageType::DAProposalMessage(sda_msg.clone())).await.unwrap(); qc_sender.broadcast(MessageType::QCMessage(sqc_msg.clone())).await.unwrap(); + + // add some delay before sending the decide messages so that builder_state can have some time to process da and qc messages + //task::sleep(std::time::Duration::from_secs(1)).await; //decide_sender.broadcast(MessageType::DecideMessage(sdecide_msg.clone())).await.unwrap(); //TODO: sending request message onto channel also @@ -257,13 +263,11 @@ mod tests { }); stx_msgs.push(stx_msg); - //sdecide_msgs.push(sdecide_msg); + sdecide_msgs.push(sdecide_msg); sda_msgs.push(sda_msg); sqc_msgs.push(sqc_msg); - //sreq_msgs.push(request_message); + sreq_msgs.push(request_message); } - - // form the quorum election config, required for the VID computation inside the builder_state let quorum_election_config = <::Membership as Membership>::default_election_config(TEST_NUM_NODES_IN_VID_COMPUTATION as u64); @@ -282,8 +286,8 @@ mod tests { assert_eq!(quorum_membership.total_nodes(), TEST_NUM_NODES_IN_VID_COMPUTATION); // instantiate the global state also - let global_state = Arc::new(RwLock::new(GlobalState::::new(req_sender, res_receiver))); - + let global_state = Arc::new(RwLock::new(GlobalState::::new(req_sender.clone(), res_receiver))); + let global_state_clone = global_state.clone(); // generate the keys for the buidler let seed = [201 as u8; 32]; let (builder_pub_key, builder_private_key) = BLSPubKey::generated_from_seed_indexed(seed,2011 as u64); @@ -296,7 +300,31 @@ mod tests { //builder_state.event_loop().await; builder_state.event_loop(); }); + handle.await; - task::sleep(std::time::Duration::from_secs(240)).await; + + // go through the request messages in sreq_msgs and send the request message + for req_msg in sreq_msgs.iter(){ + task::sleep(std::time::Duration::from_secs(1)).await; + req_sender.broadcast(req_msg.clone()).await.unwrap(); + } + + task::sleep(std::time::Duration::from_secs(2)).await; + // go through the decide messages in s_decide_msgs and send the request message + for decide_msg in sdecide_msgs.iter(){ + task::sleep(std::time::Duration::from_secs(1)).await; + decide_sender.broadcast(MessageType::DecideMessage(decide_msg.clone())).await.unwrap(); + } + + //let responses:Vec> = Vec::new(); + + while let Ok(res_msg) = global_state_clone.write_arc().await.response_receiver.try_recv(){ + rres_msgs.push(res_msg); + if rres_msgs.len() == (num_test_messages-1) as usize{ + break; + } + } + assert_eq!(rres_msgs.len(), (num_test_messages-1) as usize); + //task::sleep(std::time::Duration::from_secs(60)).await; } } From 073927c54681e23dec60e4543b794a4ef02c2185 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Tue, 13 Feb 2024 11:17:40 -0500 Subject: [PATCH 44/47] fix allow spwaning from clones also --- src/builder_state.rs | 20 +++++++++++++------- src/testing/basic_test.rs | 32 +++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index addbd981..a28cb9f6 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -251,10 +251,14 @@ impl BuilderProgress for BuilderState{ if self.built_from_view_vid_leaf.0.get_u64() == 0 { tracing::info!("In bootstrapping phase"); } - else if da_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0{ - tracing::info!("View number does not match the built_from_view, so ignoring it"); - return; + else if da_msg.proposal.data.view_number <= self.built_from_view_vid_leaf.0{ + tracing::info!("View number is lesser or equal from the built_from_view, so returning"); + return; } + // else if da_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0{ + // tracing::info!("View number does not match the built_from_view, so ignoring it"); + // return; + // } let da_proposal_data = da_msg.proposal.data.clone(); let sender = da_msg.sender; @@ -317,8 +321,10 @@ impl BuilderProgress for BuilderState{ if self.built_from_view_vid_leaf.0.get_u64() == 0{ tracing::info!("In bootstrapping phase"); } - else if qc_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0{ - tracing::info!("Either View number or leaf commit does not match the built-in info, so ignoring it"); + else if qc_msg.proposal.data.justify_qc.view_number != self.built_from_view_vid_leaf.0 || + qc_msg.proposal.data.justify_qc.get_data().leaf_commit != self.built_from_view_vid_leaf.2 + { + tracing::info!("Either View number or leaf commit from justify qc does not match the built-in info, so returning"); return; } // else if qc_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0 || @@ -380,11 +386,11 @@ impl BuilderProgress for BuilderState{ // handle the case when we hear a decide event before we have atleast one clone, in that case, we might exit the builder // and not make any progress; so we need to handle that case // Adhoc logic: if the number of subscrived receivers are more than 1, it means that there exists a clone and we can safely exit - // if self.built_from_view_vid_leaf.0.get_u64() == 0 && self.tx_receiver.receiver_count() <=1 { + // if self.built_from_view_vid_leaf.0.get_u64() == 0{ // tracing::info!("In bootstrapping phase"); // //return Some(Status::ShouldContinue); // } - if self.built_from_view_vid_leaf.0.get_u64() == 0{ + if self.built_from_view_vid_leaf.0.get_u64() == 0 && self.tx_receiver.receiver_count() <=1 { tracing::info!("In bootstrapping phase"); //return Some(Status::ShouldContinue); } diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 0fa3fcca..a716ba6c 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -159,37 +159,55 @@ mod tests { let justify_qc = match i{ 0 => QuorumCertificate::::genesis(), _ => { - let previous_qc = sqc_msgs[(i-1) as usize].proposal.data.justify_qc.clone(); + let previous_justify_qc = sqc_msgs[(i-1) as usize].proposal.data.justify_qc.clone(); + // Construct a leaf //let metadata = block_header.metadata(); - let metadata = sqc_msgs[(i-1) as usize].proposal.data.block_header.metadata(); + let _metadata = sqc_msgs[(i-1) as usize].proposal.data.block_header.metadata(); + // let leaf: Leaf<_> = Leaf { + // view_number: sqc_msgs[(i-1) as usize].proposal.data.justify_qc.view_number.clone(), + // justify_qc: sqc_msgs[(i-1) as usize].proposal.data.justify_qc.clone(), + // parent_commitment: sqc_msgs[(i-1) as usize].proposal.data.justify_qc.get_data().leaf_commit, + // block_header: sqc_msgs[(i-1) as usize].proposal.data.block_header.clone(), + // // todo currently this is set to None in builder_state, see whether needs to make None here also + // block_payload: Some(BlockPayload::from_bytes(sda_msgs[(i-1) as usize].proposal.data.encoded_transactions.clone().into_iter(), metadata)), + // proposer_id: sqc_msgs[(i-1) as usize].proposal.data.proposer_id, + // }; + let leaf: Leaf<_> = Leaf { view_number: sqc_msgs[(i-1) as usize].proposal.data.view_number.clone(), justify_qc: sqc_msgs[(i-1) as usize].proposal.data.justify_qc.clone(), parent_commitment: sqc_msgs[(i-1) as usize].proposal.data.justify_qc.get_data().leaf_commit, block_header: sqc_msgs[(i-1) as usize].proposal.data.block_header.clone(), - // todo currently this is set to None in builder_state, see whether needs to make None here also - block_payload: Some(BlockPayload::from_bytes(sda_msgs[(i-1) as usize].proposal.data.encoded_transactions.clone().into_iter(), metadata)), + block_payload: None, proposer_id: sqc_msgs[(i-1) as usize].proposal.data.proposer_id, }; - + let q_data = QuorumData::{ leaf_commit: leaf.commit(), }; + + let previous_qc_view_number = sqc_msgs[(i-1) as usize].proposal.data.view_number.get_u64(); + let view_number = if previous_qc_view_number == 0 && previous_justify_qc.view_number.get_u64() == 0{ + ViewNumber::new(0) + } else { + ViewNumber::new(1+previous_justify_qc.view_number.get_u64()) + }; let justify_qc = SimpleCertificate::, SuccessThreshold>{ data: q_data.clone(), vote_commitment: q_data.commit(), - view_number: previous_qc.get_view_number(), - signatures: previous_qc.signatures.clone(), + view_number: view_number, + signatures: previous_justify_qc.signatures.clone(), is_genesis: true, // todo setting true because we don't have signatures of QCType _pd: PhantomData, }; justify_qc }, }; + tracing::debug!("Iteration: {} justify_qc: {:?}", i, justify_qc); //::SignatureKey::sign(private_key, encoded_txns_vid_commitment.as_ref()).unwrap(), let qc_proposal = QuorumProposal::{ From d1c8230c0c16aecf7fbd74b53d34db31aca97985 Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Tue, 13 Feb 2024 12:12:29 -0500 Subject: [PATCH 45/47] fix spawning multiple clones --- src/builder_state.rs | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/src/builder_state.rs b/src/builder_state.rs index a28cb9f6..fd8b46db 100644 --- a/src/builder_state.rs +++ b/src/builder_state.rs @@ -248,18 +248,14 @@ impl BuilderProgress for BuilderState{ // bootstrapping part // if the view number is 0 then keep going, and don't return from it - if self.built_from_view_vid_leaf.0.get_u64() == 0 { + if self.built_from_view_vid_leaf.0.get_u64() == 0 && self.tx_receiver.receiver_count() <=1{ tracing::info!("In bootstrapping phase"); } else if da_msg.proposal.data.view_number <= self.built_from_view_vid_leaf.0{ tracing::info!("View number is lesser or equal from the built_from_view, so returning"); return; } - // else if da_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0{ - // tracing::info!("View number does not match the built_from_view, so ignoring it"); - // return; - // } - + let da_proposal_data = da_msg.proposal.data.clone(); let sender = da_msg.sender; @@ -318,7 +314,7 @@ impl BuilderProgress for BuilderState{ // bootstrapping part // if the view number is 0 then keep going, and don't return from it - if self.built_from_view_vid_leaf.0.get_u64() == 0{ + if self.built_from_view_vid_leaf.0.get_u64() == 0 && self.tx_receiver.receiver_count() <=1{ tracing::info!("In bootstrapping phase"); } else if qc_msg.proposal.data.justify_qc.view_number != self.built_from_view_vid_leaf.0 || @@ -327,11 +323,6 @@ impl BuilderProgress for BuilderState{ tracing::info!("Either View number or leaf commit from justify qc does not match the built-in info, so returning"); return; } - // else if qc_msg.proposal.data.view_number != self.built_from_view_vid_leaf.0 || - // qc_msg.proposal.data.justify_qc.get_data().leaf_commit != self.built_from_view_vid_leaf.2 { - // tracing::info!("Either View number or leaf commit does not match the built-in info, so ignoring it"); - // return; - // } let qc_proposal_data = qc_msg.proposal.data; let sender = qc_msg.sender; @@ -386,10 +377,6 @@ impl BuilderProgress for BuilderState{ // handle the case when we hear a decide event before we have atleast one clone, in that case, we might exit the builder // and not make any progress; so we need to handle that case // Adhoc logic: if the number of subscrived receivers are more than 1, it means that there exists a clone and we can safely exit - // if self.built_from_view_vid_leaf.0.get_u64() == 0{ - // tracing::info!("In bootstrapping phase"); - // //return Some(Status::ShouldContinue); - // } if self.built_from_view_vid_leaf.0.get_u64() == 0 && self.tx_receiver.receiver_count() <=1 { tracing::info!("In bootstrapping phase"); //return Some(Status::ShouldContinue); @@ -457,8 +444,6 @@ impl BuilderProgress for BuilderState{ }; self.built_from_view_vid_leaf.2 = leaf.commit(); - // let block_payload_txns = TestBlockPayload::from_bytes(encoded_txns.clone().into_iter(), &()).transactions; - // let encoded_txns_hash = Sha256::digest(&encoded_txns); let payload = ::from_bytes( da_proposal.encoded_transactions.clone().into_iter(), quorum_proposal.block_header.metadata(), @@ -521,10 +506,6 @@ impl BuilderProgress for BuilderState{ let vid = VidScheme::new(chunk_size, num_quorum_committee, &srs).unwrap(); vid.disperse(encoded_txns).unwrap(); }); - - // let join_handle = task::spawn(async move{ - // println!("Calculating VID"); - // }); //self.global_state.write().block_hash_to_block.insert(block_hash, (payload, metadata, join_handle)); //let mut global_state = self.global_state.write().unwrap(); //self.global_state.write_arc().await.block_hash_to_block.insert(block_hash.clone(), (payload, metadata, join_handle)); @@ -621,10 +602,6 @@ impl BuilderProgress for BuilderState{ self.process_external_transaction(rtx_msg.tx); } tracing::debug!("tx map size: {}", self.tx_hash_to_available_txns.len()); - // if self.built_from_view_vid_leaf.0.get_u64() == 1 && self.tx_hash_to_available_txns.len() == 2 { - // // get the first transaction from the tx_hash_to_available_txns - // break; - // } } } None => { From 118fbbd5fd1989f9fdb28d6088779da1c413df8a Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Tue, 13 Feb 2024 12:15:57 -0500 Subject: [PATCH 46/47] add more event count --- src/testing/basic_test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index a716ba6c..3928421b 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -86,7 +86,7 @@ mod tests { type Membership = GeneralStaticCommittee; } // no of test messages to send - let num_test_messages = 3; + let num_test_messages = 10; let multiplication_factor = 5; const TEST_NUM_NODES_IN_VID_COMPUTATION: usize = 4; From 1be55a757257e51856feeaf310c7b2457992b83f Mon Sep 17 00:00:00 2001 From: Himanshu Goyal Date: Tue, 13 Feb 2024 12:24:26 -0500 Subject: [PATCH 47/47] fix premature break --- src/testing/basic_test.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/testing/basic_test.rs b/src/testing/basic_test.rs index 3928421b..5b6e71b1 100644 --- a/src/testing/basic_test.rs +++ b/src/testing/basic_test.rs @@ -338,9 +338,9 @@ mod tests { while let Ok(res_msg) = global_state_clone.write_arc().await.response_receiver.try_recv(){ rres_msgs.push(res_msg); - if rres_msgs.len() == (num_test_messages-1) as usize{ - break; - } + // if rres_msgs.len() == (num_test_messages-1) as usize{ + // break; + // } } assert_eq!(rres_msgs.len(), (num_test_messages-1) as usize); //task::sleep(std::time::Duration::from_secs(60)).await;