From 3c0860cc6b4707c99b606451c72662830dd7835a Mon Sep 17 00:00:00 2001 From: jeluard Date: Sun, 9 Feb 2025 14:37:21 +0100 Subject: [PATCH] feat: make ledger wasm compatible Signed-off-by: jeluard --- .github/workflows/CI.yml | 13 +- Cargo.lock | 157 ++++------------- Cargo.toml | 4 +- crates/amaru/Cargo.toml | 1 + crates/amaru/src/bin/amaru/cmd/import.rs | 8 +- crates/amaru/src/bin/amaru/cmd/mod.rs | 2 +- crates/amaru/src/lib.rs | 2 + crates/amaru/src/pipeline.rs | 153 ++++++++++++++++ crates/amaru/src/sync/mod.rs | 7 +- crates/amaru/src/sync/pull.rs | 27 ++- crates/consensus/Cargo.toml | 3 +- crates/consensus/src/consensus/header.rs | 2 +- .../src/consensus/header_validation.rs | 6 +- crates/consensus/src/consensus/mod.rs | 14 +- crates/kernel/Cargo.toml | 25 +++ crates/{ledger => kernel}/src/iter/borrow.rs | 0 crates/{ledger => kernel}/src/iter/mod.rs | 0 .../src/kernel.rs => kernel/src/lib.rs} | 52 +++++- crates/kernel/src/store.rs | 165 ++++++++++++++++++ .../{ouroboros => kernel}/src/traits/mod.rs | 0 crates/ledger/Cargo.toml | 18 +- crates/ledger/src/lib.rs | 153 +--------------- crates/ledger/src/rewards.rs | 14 +- crates/ledger/src/state.rs | 14 +- crates/ledger/src/state/diff_epoch_reg.rs | 2 +- crates/ledger/src/state/transaction.rs | 2 +- crates/ledger/src/state/volatile_db.rs | 10 +- crates/ledger/src/store.rs | 2 +- crates/ledger/src/store/columns/accounts.rs | 6 +- crates/ledger/src/store/columns/pools.rs | 8 +- crates/ledger/src/store/columns/pots.rs | 3 +- crates/ledger/src/store/columns/slots.rs | 6 +- crates/ledger/src/store/columns/utxo.rs | 4 +- crates/ouroboros/Cargo.toml | 3 +- crates/ouroboros/src/consensus/test.rs | 2 +- crates/ouroboros/src/consensus/validator.rs | 2 +- crates/ouroboros/src/lib.rs | 1 - crates/ouroboros/src/protocol/mod.rs | 2 +- crates/stores/Cargo.toml | 11 +- crates/stores/src/rocksdb/columns/pools.rs | 3 +- crates/stores/src/rocksdb/mod.rs | 15 +- 41 files changed, 552 insertions(+), 370 deletions(-) create mode 100644 crates/amaru/src/pipeline.rs create mode 100644 crates/kernel/Cargo.toml rename crates/{ledger => kernel}/src/iter/borrow.rs (100%) rename crates/{ledger => kernel}/src/iter/mod.rs (100%) rename crates/{ledger/src/kernel.rs => kernel/src/lib.rs} (91%) create mode 100644 crates/kernel/src/store.rs rename crates/{ouroboros => kernel}/src/traits/mod.rs (100%) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 29878ac2..4fe8348d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -44,7 +44,12 @@ jobs: - runner: ubuntu-latest target: wasm32-unknown-unknown packages: -p amaru-ledger - optional: true + command: build + - runner: ubuntu-latest + target: riscv32im-risc0-zkvm-elf + packages: -p amaru-ledger + extra-args: +nightly -Zbuild-std=std,panic_abort + command: build # Disabled for now #- runner: ubuntu-latest # target: aarch64-unknown-linux-musl @@ -60,13 +65,15 @@ jobs: - name: Run tests run: | set +e + EXTRA_ARGS="${{ matrix.environments.extra-args || '' }}" SCOPE="${{ matrix.environments.packages || '--workspace' }}" + COMMAND="${{ matrix.environments.command || 'test' }}" if [[ "${{ matrix.environments.cross-compile }}" == "true" ]] ; then cargo install cross --git https://github.com/cross-rs/cross # cross doesn't load .cargo/config.toml, see https://github.com/cross-rs/cross/issues/562 - $HOME/.cargo/bin/cross test --locked --all-features $SCOPE --target ${{ matrix.environments.target }} + $HOME/.cargo/bin/cross $COMMAND --locked --all-features $SCOPE --target ${{ matrix.environments.target }} else - cargo test $SCOPE --locked --target ${{ matrix.environments.target }} + cargo $EXTRA_ARGS $COMMAND $SCOPE --locked --target ${{ matrix.environments.target }} fi exitcode="$?" if [[ "${{ matrix.environments.optional }}" == "true" && "$exitcode" != "0" ]] ; then diff --git a/Cargo.lock b/Cargo.lock index 10d35dab..242b83a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,6 +31,7 @@ name = "amaru" version = "0.1.0" dependencies = [ "amaru-consensus", + "amaru-kernel", "amaru-ledger", "amaru-ouroboros", "amaru-stores", @@ -69,6 +70,7 @@ dependencies = [ name = "amaru-consensus" version = "0.1.0" dependencies = [ + "amaru-kernel", "amaru-ledger", "amaru-ouroboros", "async-trait", @@ -93,36 +95,52 @@ dependencies = [ ] [[package]] -name = "amaru-ledger" +name = "amaru-kernel" version = "0.1.0" dependencies = [ - "amaru-ouroboros", - "async-trait", "bech32 0.11.0", - "gasket", "hex", "num", "pallas-addresses", "pallas-codec", "pallas-crypto", - "pallas-network", "pallas-primitives", "proptest", "serde", "thiserror 2.0.11", +] + +[[package]] +name = "amaru-ledger" +version = "0.1.0" +dependencies = [ + "amaru-kernel", + "hex", + "num", + "proptest", + "serde", + "thiserror 2.0.11", "tracing", ] +[[package]] +name = "amaru-ledger-in-browser" +version = "0.1.0" +dependencies = [ + "amaru-kernel", + "amaru-ledger", +] + [[package]] name = "amaru-ouroboros" version = "0.1.0" dependencies = [ + "amaru-kernel", "criterion", "ctor", "hex", "insta", "kes-summed-ed25519", - "mockall", "pallas-codec", "pallas-crypto", "pallas-math", @@ -144,9 +162,11 @@ dependencies = [ name = "amaru-stores" version = "0.1.0" dependencies = [ + "amaru-kernel", "amaru-ledger", "hex", "pallas-codec", + "proptest", "rocksdb", "tracing", ] @@ -539,21 +559,6 @@ dependencies = [ "syn", ] -[[package]] -name = "bit-set" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" - [[package]] name = "bitflags" version = "2.8.0" @@ -1079,12 +1084,6 @@ dependencies = [ "syn", ] -[[package]] -name = "downcast" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" - [[package]] name = "ed25519" version = "2.2.3" @@ -1202,12 +1201,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fragile" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" - [[package]] name = "futures-channel" version = "0.3.31" @@ -1894,6 +1887,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "libredox" version = "0.1.3" @@ -2061,32 +2060,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "mockall" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2" -dependencies = [ - "cfg-if", - "downcast", - "fragile", - "mockall_derive", - "predicates", - "predicates-tree", -] - -[[package]] -name = "mockall_derive" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "nom" version = "7.1.3" @@ -2202,6 +2175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2578,32 +2552,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "predicates" -version = "3.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" -dependencies = [ - "anstyle", - "predicates-core", -] - -[[package]] -name = "predicates-core" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" - -[[package]] -name = "predicates-tree" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" -dependencies = [ - "predicates-core", - "termtree", -] - [[package]] name = "proc-macro2" version = "1.0.93" @@ -2619,17 +2567,11 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ - "bit-set", - "bit-vec", "bitflags", - "lazy_static", "num-traits", "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.5", - "rusty-fork", - "tempfile", "unarray", ] @@ -2656,12 +2598,6 @@ dependencies = [ "syn", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.38" @@ -2881,18 +2817,6 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" -[[package]] -name = "rusty-fork" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" -dependencies = [ - "fnv", - "quick-error", - "tempfile", - "wait-timeout", -] - [[package]] name = "ryu" version = "1.0.19" @@ -3180,12 +3104,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "termtree" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" - [[package]] name = "test-case" version = "3.3.1" @@ -3627,15 +3545,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "wait-timeout" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" -dependencies = [ - "libc", -] - [[package]] name = "walkdir" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 904de29f..eae2c4cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ indoc = "2.0" miette = "7.2.0" minicbor = "0.25.1" mockall = "0.13" -num = "0.4.3" +num = { version = "0.4.3", default-features = false, features = ["alloc"] } opentelemetry = "0.27.1" opentelemetry-otlp = "0.27.0" opentelemetry_sdk = "0.27.1" @@ -55,7 +55,7 @@ vrf_dalek = { git = "https://github.com/txpipe/vrf", rev = "044b45a1a919ba9d9c24 kes-summed-ed25519 = { git = "https://github.com/txpipe/kes", rev = "f69fb357d46f6a18925543d785850059569d7e78" } # dev-dependencies -proptest = "1.5.0" +proptest = { version = "1.5.0", default-features = false, features = ["alloc"] } insta = "1.41.1" envpath = "0.0.1-beta.3" criterion = "0.5.1" diff --git a/crates/amaru/Cargo.toml b/crates/amaru/Cargo.toml index b0434154..21fe699a 100644 --- a/crates/amaru/Cargo.toml +++ b/crates/amaru/Cargo.toml @@ -36,6 +36,7 @@ tracing-subscriber = { workspace = true, features = ["env-filter", "std", "json" tracing.workspace = true amaru-consensus = { path = "../consensus" } +amaru-kernel = { path = "../kernel" } amaru-ledger = { path = "../ledger" } amaru-ouroboros = { path = "../ouroboros" } amaru-stores = { path = "../stores" } diff --git a/crates/amaru/src/bin/amaru/cmd/import.rs b/crates/amaru/src/bin/amaru/cmd/import.rs index 8c0fc33b..988ee613 100644 --- a/crates/amaru/src/bin/amaru/cmd/import.rs +++ b/crates/amaru/src/bin/amaru/cmd/import.rs @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +use amaru_kernel::{ + epoch_from_slot, DRep, Epoch, Lovelace, Point, PoolId, PoolParams, Set, StakeCredential, + TransactionInput, TransactionOutput, STAKE_CREDENTIAL_DEPOSIT, +}; use amaru_ledger::{ self, - kernel::{ - epoch_from_slot, DRep, Epoch, Lovelace, Point, PoolId, PoolParams, Set, StakeCredential, - TransactionInput, TransactionOutput, STAKE_CREDENTIAL_DEPOSIT, - }, store::{ Store, {self}, }, diff --git a/crates/amaru/src/bin/amaru/cmd/mod.rs b/crates/amaru/src/bin/amaru/cmd/mod.rs index 798fba35..18766df8 100644 --- a/crates/amaru/src/bin/amaru/cmd/mod.rs +++ b/crates/amaru/src/bin/amaru/cmd/mod.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use amaru_ouroboros::protocol::Point; +use amaru_kernel::Point; pub(crate) mod daemon; pub(crate) mod import; diff --git a/crates/amaru/src/lib.rs b/crates/amaru/src/lib.rs index b5710404..40b7cc27 100644 --- a/crates/amaru/src/lib.rs +++ b/crates/amaru/src/lib.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod pipeline; + /// Sync pipeline /// /// The sync pipeline is responsible for fetching blocks from the upstream node and diff --git a/crates/amaru/src/pipeline.rs b/crates/amaru/src/pipeline.rs new file mode 100644 index 00000000..69dbbabb --- /dev/null +++ b/crates/amaru/src/pipeline.rs @@ -0,0 +1,153 @@ +use std::sync::Arc; + +use amaru_kernel::{cbor, Hash, Hasher, MintedBlock, Point}; +use gasket::framework::{AsWorkError, WorkSchedule, WorkerError}; +use tracing::{instrument, trace_span, Level, Span}; + +use amaru_ledger::{ + state::{self, BackwardError}, + store::Store, + BlockValidationResult, RawBlock, ValidateBlockEvent, +}; + +pub type UpstreamPort = gasket::messaging::InputPort; +pub type DownstreamPort = gasket::messaging::OutputPort; + +const EVENT_TARGET: &str = "amaru::ledger"; + +pub struct Stage +where + S: Store, +{ + pub upstream: UpstreamPort, + pub downstream: DownstreamPort, + pub state: state::State, +} + +impl gasket::framework::Stage for Stage { + type Unit = ValidateBlockEvent; + type Worker = Worker; + + fn name(&self) -> &str { + "ledger" + } + + fn metrics(&self) -> gasket::metrics::Registry { + gasket::metrics::Registry::default() + } +} + +impl Stage { + pub fn new(store: S) -> (Self, Point) { + let state = state::State::new(Arc::new(std::sync::Mutex::new(store))); + + let tip = state.tip().into_owned(); + + ( + Self { + upstream: Default::default(), + downstream: Default::default(), + state, + }, + tip, + ) + } + + pub async fn roll_forward( + &mut self, + point: Point, + raw_block: RawBlock, + parent: &Span, + ) -> BlockValidationResult { + // TODO: use instrument macro + let span_forward = trace_span!( + target: EVENT_TARGET, + parent: parent, + "forward", + header.height = tracing::field::Empty, + header.slot = tracing::field::Empty, + header.hash = tracing::field::Empty, + stable.epoch = tracing::field::Empty, + tip.epoch = tracing::field::Empty, + tip.relative_slot = tracing::field::Empty, + ) + .entered(); + + let (block_header_hash, block) = parse_block(&raw_block[..]); + + span_forward.record("header.height", block.header.header_body.block_number); + span_forward.record("header.slot", block.header.header_body.slot); + span_forward.record("header.hash", hex::encode(block_header_hash)); + + let result = match self.state.forward(&span_forward, &point, block) { + Ok(_) => BlockValidationResult::BlockValidated(point, parent.clone()), + Err(_) => BlockValidationResult::BlockForwardStorageFailed(point, parent.clone()), + }; + + span_forward.exit(); + result + } + + pub async fn rollback_to(&mut self, point: Point) -> BlockValidationResult { + let span_backward = trace_span!( + target: EVENT_TARGET, + "backward", + point.slot = point.slot_or_default(), + point.hash = tracing::field::Empty, + ); + + if let Point::Specific(_, header_hash) = &point { + span_backward.record("point.hash", hex::encode(header_hash)); + } + + match self.state.backward(&point) { + Ok(_) => BlockValidationResult::RolledBackTo(point), + Err(BackwardError::UnknownRollbackPoint(_)) => { + BlockValidationResult::InvalidRollbackPoint(point) + } + } + } +} + +pub struct Worker {} + +#[async_trait::async_trait(?Send)] +impl gasket::framework::Worker> for Worker { + async fn bootstrap(_stage: &Stage) -> Result { + Ok(Self {}) + } + + async fn schedule( + &mut self, + stage: &mut Stage, + ) -> Result, WorkerError> { + let unit = stage.upstream.recv().await.or_panic()?; + Ok(WorkSchedule::Unit(unit.payload)) + } + + async fn execute( + &mut self, + unit: &ValidateBlockEvent, + stage: &mut Stage, + ) -> Result<(), WorkerError> { + let result = match unit { + ValidateBlockEvent::Validated(point, raw_block, parent_span) => { + stage + .roll_forward(point.clone(), raw_block.to_vec(), parent_span) + .await + } + + ValidateBlockEvent::Rollback(point) => stage.rollback_to(point.clone()).await, + }; + + Ok(stage.downstream.send(result.into()).await.or_panic()?) + } +} + +#[instrument(level = Level::TRACE, skip(bytes), fields(block.size = bytes.len()))] +fn parse_block(bytes: &[u8]) -> (Hash<32>, MintedBlock<'_>) { + let (_, block): (u16, MintedBlock<'_>) = cbor::decode(bytes) + .unwrap_or_else(|_| panic!("failed to decode Conway block: {:?}", hex::encode(bytes))); + + (Hasher::<256>::hash(block.header.raw_cbor()), block) +} diff --git a/crates/amaru/src/sync/mod.rs b/crates/amaru/src/sync/mod.rs index e3198247..896f45a1 100644 --- a/crates/amaru/src/sync/mod.rs +++ b/crates/amaru/src/sync/mod.rs @@ -20,9 +20,10 @@ use amaru_consensus::{ store::{rocksdb::RocksDBStore, ChainStore}, }, }; +use amaru_kernel::Point; use amaru_ouroboros::protocol::{ peer::{Peer, PeerSession}, - Point, PullEvent, + PullEvent, }; use amaru_stores::rocksdb::RocksDB; use gasket::{ @@ -35,6 +36,8 @@ use pallas_primitives::conway::Epoch; use std::{collections::HashMap, path::PathBuf, sync::Arc}; use tokio::sync::Mutex; +use crate::pipeline::Stage; + pub mod fetch; pub mod pull; @@ -74,7 +77,7 @@ pub fn bootstrap( // FIXME: Take from config / command args let store = RocksDB::new(&config.ledger_dir) .unwrap_or_else(|e| panic!("unable to open ledger store: {e:?}")); - let (mut ledger, tip) = amaru_ledger::Stage::new(store); + let (mut ledger, tip) = Stage::new(store); let peer_sessions: Vec = clients .iter() diff --git a/crates/amaru/src/sync/pull.rs b/crates/amaru/src/sync/pull.rs index eafbccca..1f7a448d 100644 --- a/crates/amaru/src/sync/pull.rs +++ b/crates/amaru/src/sync/pull.rs @@ -12,13 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use amaru_kernel::Point; use amaru_ouroboros::protocol::{peer::PeerSession, PullEvent, RawHeader}; use gasket::framework::*; use miette::miette; -use pallas_network::miniprotocols::{ - chainsync::{HeaderContent, NextResponse, Tip}, - Point, -}; +use pallas_network::miniprotocols::chainsync::{HeaderContent, NextResponse, Tip}; use pallas_traverse::MultiEraHeader; use std::time::Duration; use tokio::time::timeout; @@ -79,9 +77,16 @@ impl Stage { pub async fn find_intersection(&self) -> Result<(), WorkerError> { let mut peer_client = self.peer_session.peer_client.lock().await; let client = (*peer_client).chainsync(); - + fn new_point(point: &Point) -> pallas_network::miniprotocols::Point { + match point.clone() { + Point::Origin => pallas_network::miniprotocols::Point::Origin, + Point::Specific(slot, hash) => { + pallas_network::miniprotocols::Point::Specific(slot, hash) + } + } + } let (point, _) = client - .find_intersect(self.intersection.clone()) + .find_intersect(self.intersection.iter().map(new_point).collect()) .await .or_restart()?; @@ -178,7 +183,15 @@ impl gasket::framework::Worker for Worker { stage.roll_forward(&header).await?; } NextResponse::RollBackward(point, tip) => { - stage.roll_back(point, tip).await?; + fn new_point(point: pallas_network::miniprotocols::Point) -> Point { + match point.clone() { + pallas_network::miniprotocols::Point::Origin => Point::Origin, + pallas_network::miniprotocols::Point::Specific(slot, hash) => { + Point::Specific(slot, hash) + } + } + } + stage.roll_back(new_point(point), tip).await?; } NextResponse::Await => {} }; diff --git a/crates/consensus/Cargo.toml b/crates/consensus/Cargo.toml index 53019bd6..4371674f 100644 --- a/crates/consensus/Cargo.toml +++ b/crates/consensus/Cargo.toml @@ -26,8 +26,9 @@ thiserror.workspace = true tokio.workspace = true tracing.workspace = true -amaru-ouroboros = { path = "../ouroboros" } +amaru-kernel = { path = "../kernel" } amaru-ledger = { path = "../ledger" } +amaru-ouroboros = { path = "../ouroboros" } [dev-dependencies] envpath.workspace = true diff --git a/crates/consensus/src/consensus/header.rs b/crates/consensus/src/consensus/header.rs index 20dd9ecb..624b5611 100644 --- a/crates/consensus/src/consensus/header.rs +++ b/crates/consensus/src/consensus/header.rs @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use amaru_kernel::Point; use pallas_codec::minicbor; use pallas_crypto::hash::Hash; -use pallas_network::miniprotocols::Point; use pallas_primitives::babbage; use pallas_traverse::ComputeHash; diff --git a/crates/consensus/src/consensus/header_validation.rs b/crates/consensus/src/consensus/header_validation.rs index 7c082273..065de3c3 100644 --- a/crates/consensus/src/consensus/header_validation.rs +++ b/crates/consensus/src/consensus/header_validation.rs @@ -12,10 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use amaru_ledger::kernel::epoch_from_slot; -use amaru_ouroboros::{ - consensus::BlockValidator, traits::HasStakeDistribution, validator::Validator, -}; +use amaru_kernel::{epoch_from_slot, traits::HasStakeDistribution}; +use amaru_ouroboros::{consensus::BlockValidator, validator::Validator}; use gasket::framework::*; use pallas_crypto::hash::Hash; use pallas_math::math::FixedDecimal; diff --git a/crates/consensus/src/consensus/mod.rs b/crates/consensus/src/consensus/mod.rs index f0692112..65e0cfd6 100644 --- a/crates/consensus/src/consensus/mod.rs +++ b/crates/consensus/src/consensus/mod.rs @@ -13,11 +13,9 @@ // limitations under the License. use crate::consensus::header_validation::assert_header; +use amaru_kernel::{traits::HasStakeDistribution, Point}; use amaru_ledger::ValidateBlockEvent; -use amaru_ouroboros::{ - protocol::{peer, peer::*, Point, PullEvent}, - traits::HasStakeDistribution, -}; +use amaru_ouroboros::protocol::{peer, peer::*, PullEvent}; use chain_selection::ChainSelector; use gasket::framework::*; use header::{point_hash, ConwayHeader, Header}; @@ -109,7 +107,13 @@ impl HeaderStage { .expect("Unknown peer, bailing out"); let mut session = peer_session.peer_client.lock().await; let client = (*session).blockfetch(); - client.fetch_single(point.clone()).await.or_restart()? + let new_point: pallas_network::miniprotocols::Point = match point.clone() { + Point::Origin => pallas_network::miniprotocols::Point::Origin, + Point::Specific(slot, hash) => { + pallas_network::miniprotocols::Point::Specific(slot, hash) + } + }; + client.fetch_single(new_point).await.or_restart()? }; self.downstream diff --git a/crates/kernel/Cargo.toml b/crates/kernel/Cargo.toml new file mode 100644 index 00000000..c64fab61 --- /dev/null +++ b/crates/kernel/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "amaru-kernel" +version.workspace = true +edition.workspace = true +description.workspace = true +license.workspace = true +authors.workspace = true +repository.workspace = true +homepage.workspace = true +documentation.workspace = true +rust-version.workspace = true + +[dependencies] +bech32.workspace = true +hex.workspace = true +num.workspace = true +pallas-addresses.workspace = true +pallas-codec.workspace = true +pallas-crypto.workspace = true +pallas-primitives.workspace = true +serde.workspace = true +thiserror.workspace = true + +[dev-dependencies] +proptest.workspace = true \ No newline at end of file diff --git a/crates/ledger/src/iter/borrow.rs b/crates/kernel/src/iter/borrow.rs similarity index 100% rename from crates/ledger/src/iter/borrow.rs rename to crates/kernel/src/iter/borrow.rs diff --git a/crates/ledger/src/iter/mod.rs b/crates/kernel/src/iter/mod.rs similarity index 100% rename from crates/ledger/src/iter/mod.rs rename to crates/kernel/src/iter/mod.rs diff --git a/crates/ledger/src/kernel.rs b/crates/kernel/src/lib.rs similarity index 91% rename from crates/ledger/src/kernel.rs rename to crates/kernel/src/lib.rs index d5f88001..82b79f09 100644 --- a/crates/ledger/src/kernel.rs +++ b/crates/kernel/src/lib.rs @@ -25,6 +25,7 @@ use std::sync::LazyLock; use num::{rational::Ratio, BigUint}; use pallas_addresses::*; +use pallas_codec::minicbor::{decode, encode, Decode, Decoder, Encode, Encoder}; pub use pallas_codec::{ minicbor as cbor, utils::{NonEmptyKeyValuePairs, Nullable, Set}, @@ -39,6 +40,9 @@ pub use pallas_primitives::{ }, }; +pub mod iter; +pub mod traits; + // Constants // ---------------------------------------------------------------------------- @@ -110,7 +114,53 @@ pub const OPTIMAL_STAKE_POOLS_COUNT: usize = 500; pub type Lovelace = u64; -pub type Point = pallas_network::miniprotocols::Point; +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +pub enum Point { + Origin, + Specific(u64, Vec), +} + +impl Point { + pub fn slot_or_default(&self) -> u64 { + match self { + Point::Origin => 0, + Point::Specific(slot, _) => *slot, + } + } +} + +impl Encode<()> for Point { + fn encode( + &self, + e: &mut Encoder, + _ctx: &mut (), + ) -> Result<(), encode::Error> { + match self { + Point::Origin => e.array(0)?, + Point::Specific(slot, hash) => e.array(2)?.u64(*slot)?.bytes(hash)?, + }; + + Ok(()) + } +} + +impl<'b> Decode<'b, ()> for Point { + fn decode(d: &mut Decoder<'b>, _ctx: &mut ()) -> Result { + let size = d.array()?; + + match size { + Some(0) => Ok(Point::Origin), + Some(2) => { + let slot = d.u64()?; + let hash = d.bytes()?; + Ok(Point::Specific(slot, Vec::from(hash))) + } + _ => Err(decode::Error::message( + "can't decode Point from array of size", + )), + } + } +} pub type PoolId = Hash<28>; diff --git a/crates/kernel/src/store.rs b/crates/kernel/src/store.rs new file mode 100644 index 00000000..6899e60d --- /dev/null +++ b/crates/kernel/src/store.rs @@ -0,0 +1,165 @@ +// Copyright 2024 PRAGMA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{Epoch, Point, PoolId, TransactionInput, TransactionOutput}; +use crate::rewards::Pots; +use crate::columns::*; +pub use crate::rewards::{RewardsSummary, StakeDistribution}; +use std::{borrow::BorrowMut, io, iter}; +use thiserror::Error; + +#[derive(Debug, Error)] +#[error(transparent)] +pub enum OpenErrorKind { + #[error(transparent)] + IO(#[from] io::Error), + #[error("no ledger stable snapshot found; at least one is expected")] + NoStableSnapshot, +} + +#[derive(Error, Debug)] +pub enum StoreError { + #[error(transparent)] + Internal(#[from] Box), + #[error("error sending work unit through output port")] + Send, + #[error("error opening the store")] + Open(#[source] OpenErrorKind), +} + +// Store +// ---------------------------------------------------------------------------- + +pub trait Snapshot { + /// The most recent snapshot. Note that we never starts from genesis; so there's always a + /// snapshot available. + fn most_recent_snapshot(&self) -> Epoch; + + /// Get details about a specific Pool + fn pool(&self, pool: &PoolId) -> Result, StoreError>; + + /// Get details about a specific UTxO + fn utxo(&self, input: &TransactionInput) -> Result, StoreError>; + + /// Get current values of the treasury and reserves accounts. + fn pots(&self) -> Result; + + fn iter_utxos(&self) -> Result, StoreError>; + + fn iter_block_issuers( + &self, + ) -> Result, StoreError>; + + fn iter_pools(&self) -> Result, StoreError>; + + fn iter_accounts( + &self, + ) -> Result, StoreError>; +} + +pub trait Store: Snapshot + Send + Sync { + fn for_epoch(&self, epoch: Epoch) -> Result; + + /// Access the tip of the stable store, corresponding to the latest point that was saved. + fn tip(&self) -> Result; + + /// Add or remove entries to/from the store. The exact semantic of 'add' and 'remove' depends + /// on the column type. All updates are atomatic and attached to the given `Point`. + fn save( + &self, + point: &Point, + issuer: Option<&pools::Key>, + add: Columns< + impl Iterator, + impl Iterator, + impl Iterator, + >, + remove: Columns< + impl Iterator, + impl Iterator, + impl Iterator, + >, + withdrawals: impl Iterator, + ) -> Result<(), StoreError>; + + /// Construct and save on-disk a snapshot of the store. The epoch number is used when + /// there's no existing snapshot and, to ensure that snapshots are taken in order. + /// + /// Idempotent + /// + /// /!\ IMPORTANT /!\ + /// It is the **caller's** responsibility to ensure that the snapshot is done at the right + /// moment. The store has no notion of when is an epoch boundary, and thus deferred that + /// decision entirely to the caller owning the store. + fn next_snapshot( + &mut self, + epoch: Epoch, + rewards_summary: Option, + ) -> Result<(), StoreError>; + + /// Compute stake distribution using database snapshots. + fn stake_distribution(&self, epoch: Epoch) -> Result; + + /// Compute rewards using database snapshots and a previously computed stake distribution. + fn rewards_summary( + &self, + stake_distribution: StakeDistribution, + ) -> Result; + + /// Get current values of the treasury and reserves accounts. + fn with_pots( + &self, + with: impl FnMut(Box + '_>) -> A, + ) -> Result; + + /// Provide an access to iterate over pools, in a way that enforces: + /// + /// 1. That mutations will be persisted on-disk + /// + /// 2. That all operations are consistent and atomic (the iteration occurs on a snapshot, and + /// the mutation apply to the iterated items) + fn with_pools(&self, with: impl FnMut(pools::Iter<'_, '_>)) -> Result<(), StoreError>; + + /// Provide an access to iterate over accounts, similar to 'with_pools'. + fn with_accounts(&self, with: impl FnMut(accounts::Iter<'_, '_>)) -> Result<(), StoreError>; + + /// Provide an iterator over slot leaders, similar to 'with_pools'. Note that slot leaders are + /// stored as a bounded FIFO, so it only make sense to use this function at the end of an epoch + /// (or at the beginning, before any block is applied, depending on your perspective). + fn with_block_issuers(&self, with: impl FnMut(slots::Iter<'_, '_>)) -> Result<(), StoreError>; + + /// Provide an access to iterate over utxo, similar to 'with_pools'. + fn with_utxo(&self, with: impl FnMut(utxo::Iter<'_, '_>)) -> Result<(), StoreError>; +} + +// Columns +// ---------------------------------------------------------------------------- + +/// A summary of all database columns, in a single struct. This can be derived to provide updates +/// operations on multiple columns in a single db-transaction. +pub struct Columns { + pub utxo: U, + pub pools: P, + pub accounts: A, +} + +impl Default for Columns, iter::Empty

, iter::Empty> { + fn default() -> Self { + Self { + utxo: iter::empty(), + pools: iter::empty(), + accounts: iter::empty(), + } + } +} diff --git a/crates/ouroboros/src/traits/mod.rs b/crates/kernel/src/traits/mod.rs similarity index 100% rename from crates/ouroboros/src/traits/mod.rs rename to crates/kernel/src/traits/mod.rs diff --git a/crates/ledger/Cargo.toml b/crates/ledger/Cargo.toml index 6c3b4665..03f24b11 100644 --- a/crates/ledger/Cargo.toml +++ b/crates/ledger/Cargo.toml @@ -11,21 +11,19 @@ documentation.workspace = true rust-version.workspace = true [dependencies] -async-trait.workspace = true -bech32.workspace = true -gasket.workspace = true hex.workspace = true -num = { workspace = true, features = ["num-bigint"] } -pallas-addresses.workspace = true -pallas-codec.workspace = true -pallas-crypto.workspace = true -pallas-network.workspace = true -pallas-primitives.workspace = true +num.workspace = true serde.workspace = true tracing.workspace = true thiserror.workspace = true -amaru-ouroboros = { path = "../ouroboros" } +amaru-kernel = { path = "../kernel" } [dev-dependencies] proptest.workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] + +[target.'cfg(not(std))'.dependencies] +num = { version = "0.4.3", default-features = false, features = ["alloc", "libm"] } \ No newline at end of file diff --git a/crates/ledger/src/lib.rs b/crates/ledger/src/lib.rs index e9bea976..b8c4d006 100644 --- a/crates/ledger/src/lib.rs +++ b/crates/ledger/src/lib.rs @@ -12,15 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::kernel::{Hash, Hasher, MintedBlock, Point}; -use gasket::framework::*; -use pallas_codec::minicbor as cbor; -use state::BackwardError; -use std::sync::Arc; -use store::Store; -use tracing::{instrument, trace_span, warn, Level, Span}; - -const EVENT_TARGET: &str = "amaru::ledger"; +use amaru_kernel::Point; +use tracing::Span; pub type RawBlock = Vec; @@ -38,151 +31,9 @@ pub enum BlockValidationResult { RolledBackTo(Point), } -pub type UpstreamPort = gasket::messaging::InputPort; -pub type DownstreamPort = gasket::messaging::OutputPort; - /// Iterators /// /// A set of additional primitives around iterators. Not Amaru-specific so-to-speak. -pub mod iter; -pub mod kernel; pub mod rewards; pub mod state; pub mod store; - -pub struct Stage -where - S: Store, -{ - pub upstream: UpstreamPort, - pub downstream: DownstreamPort, - pub state: state::State, -} - -impl gasket::framework::Stage for Stage { - type Unit = ValidateBlockEvent; - type Worker = Worker; - - fn name(&self) -> &str { - "ledger" - } - - fn metrics(&self) -> gasket::metrics::Registry { - gasket::metrics::Registry::default() - } -} - -impl Stage { - pub fn new(store: S) -> (Self, Point) { - let state = state::State::new(Arc::new(std::sync::Mutex::new(store))); - - let tip = state.tip().into_owned(); - - ( - Self { - upstream: Default::default(), - downstream: Default::default(), - state, - }, - tip, - ) - } - - pub async fn roll_forward( - &mut self, - point: Point, - raw_block: RawBlock, - parent: &Span, - ) -> BlockValidationResult { - // TODO: use instrument macro - let span_forward = trace_span!( - target: EVENT_TARGET, - parent: parent, - "forward", - header.height = tracing::field::Empty, - header.slot = tracing::field::Empty, - header.hash = tracing::field::Empty, - stable.epoch = tracing::field::Empty, - tip.epoch = tracing::field::Empty, - tip.relative_slot = tracing::field::Empty, - ) - .entered(); - - let (block_header_hash, block) = parse_block(&raw_block[..]); - - span_forward.record("header.height", block.header.header_body.block_number); - span_forward.record("header.slot", block.header.header_body.slot); - span_forward.record("header.hash", hex::encode(block_header_hash)); - - let result = match self.state.forward(&span_forward, &point, block) { - Ok(_) => BlockValidationResult::BlockValidated(point, parent.clone()), - Err(_) => BlockValidationResult::BlockForwardStorageFailed(point, parent.clone()), - }; - - span_forward.exit(); - result - } - - pub async fn rollback_to(&mut self, point: Point) -> BlockValidationResult { - let span_backward = trace_span!( - target: EVENT_TARGET, - "backward", - point.slot = point.slot_or_default(), - point.hash = tracing::field::Empty, - ); - - if let Point::Specific(_, header_hash) = &point { - span_backward.record("point.hash", hex::encode(header_hash)); - } - - match self.state.backward(&point) { - Ok(_) => BlockValidationResult::RolledBackTo(point), - Err(BackwardError::UnknownRollbackPoint(_)) => { - BlockValidationResult::InvalidRollbackPoint(point) - } - } - } -} - -pub struct Worker {} - -#[async_trait::async_trait(?Send)] -impl gasket::framework::Worker> for Worker { - async fn bootstrap(_stage: &Stage) -> Result { - Ok(Self {}) - } - - async fn schedule( - &mut self, - stage: &mut Stage, - ) -> Result, WorkerError> { - let unit = stage.upstream.recv().await.or_panic()?; - Ok(WorkSchedule::Unit(unit.payload)) - } - - async fn execute( - &mut self, - unit: &ValidateBlockEvent, - stage: &mut Stage, - ) -> Result<(), WorkerError> { - let result = match unit { - ValidateBlockEvent::Validated(point, raw_block, parent_span) => { - stage - .roll_forward(point.clone(), raw_block.to_vec(), parent_span) - .await - } - - ValidateBlockEvent::Rollback(point) => stage.rollback_to(point.clone()).await, - }; - - Ok(stage.downstream.send(result.into()).await.or_panic()?) - } -} - -#[instrument(level = Level::TRACE, skip(bytes), fields(block.size = bytes.len()))] -fn parse_block(bytes: &[u8]) -> (Hash<32>, MintedBlock<'_>) { - let (_, block): (u16, MintedBlock<'_>) = cbor::decode(bytes) - .unwrap_or_else(|_| panic!("failed to decode Conway block: {:?}", hex::encode(bytes))); - - (Hasher::<256>::hash(block.header.raw_cbor()), block) -} diff --git a/crates/ledger/src/rewards.rs b/crates/ledger/src/rewards.rs index 3e69aa08..2e15f273 100644 --- a/crates/ledger/src/rewards.rs +++ b/crates/ledger/src/rewards.rs @@ -96,14 +96,12 @@ the system at a certain point in time. We always take snapshots _at the end of e certain mutations are applied to the system. */ -use crate::{ - kernel::{ - encode_bech32, expect_stake_credential, output_lovelace, output_stake_credential, Epoch, - Hash, Lovelace, PoolId, PoolParams, StakeCredential, ACTIVE_SLOT_COEFF_INVERSE, - MAX_LOVELACE_SUPPLY, MONETARY_EXPANSION, OPTIMAL_STAKE_POOLS_COUNT, PLEDGE_INFLUENCE, - SHELLEY_EPOCH_LENGTH, TREASURY_TAX, - }, - store::{columns::*, Snapshot, StoreError}, +use crate::store::{columns::*, Snapshot, StoreError}; +use amaru_kernel::{ + encode_bech32, expect_stake_credential, output_lovelace, output_stake_credential, Epoch, Hash, + Lovelace, PoolId, PoolParams, StakeCredential, ACTIVE_SLOT_COEFF_INVERSE, MAX_LOVELACE_SUPPLY, + MONETARY_EXPANSION, OPTIMAL_STAKE_POOLS_COUNT, PLEDGE_INFLUENCE, SHELLEY_EPOCH_LENGTH, + TREASURY_TAX, }; use num::{ rational::Ratio, diff --git a/crates/ledger/src/state.rs b/crates/ledger/src/state.rs index f0d89fa1..148937ed 100644 --- a/crates/ledger/src/state.rs +++ b/crates/ledger/src/state.rs @@ -19,16 +19,16 @@ pub mod transaction; pub mod volatile_db; use crate::{ - kernel::{ - self, epoch_from_slot, Epoch, Hash, Hasher, MintedBlock, Point, PoolId, Slot, - TransactionInput, TransactionOutput, CONSENSUS_SECURITY_PARAM, MAX_KES_EVOLUTION, - SLOTS_PER_KES_PERIOD, STABILITY_WINDOW, - }, rewards::{RewardsSummary, StakeDistribution}, state::volatile_db::{StoreUpdate, VolatileDB, VolatileState}, store::{columns::*, Store, StoreError}, }; -use amaru_ouroboros::traits::{HasStakeDistribution, PoolSummary}; +use amaru_kernel::{ + self, epoch_from_slot, + traits::{HasStakeDistribution, PoolSummary}, + Epoch, Hash, Hasher, MintedBlock, Point, PoolId, Slot, TransactionInput, TransactionOutput, + CONSENSUS_SECURITY_PARAM, MAX_KES_EVOLUTION, SLOTS_PER_KES_PERIOD, STABILITY_WINDOW, +}; use std::{ borrow::Cow, collections::{BTreeSet, VecDeque}, @@ -163,7 +163,7 @@ impl State { block: MintedBlock<'_>, ) -> Result<(), StateError> { let issuer = Hasher::<224>::hash(&block.header.header_body.issuer_vkey[..]); - let relative_slot = kernel::relative_slot(point.slot_or_default()); + let relative_slot = amaru_kernel::relative_slot(point.slot_or_default()); let state = self.apply_block(span, block).map_err(StateError::Storage)?; diff --git a/crates/ledger/src/state/diff_epoch_reg.rs b/crates/ledger/src/state/diff_epoch_reg.rs index 6d5cbe86..867174cd 100644 --- a/crates/ledger/src/state/diff_epoch_reg.rs +++ b/crates/ledger/src/state/diff_epoch_reg.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::kernel::Epoch; +use amaru_kernel::Epoch; use std::collections::BTreeMap; /// A compact data-structure tracking deferred registration & unregistration changes in a key:value diff --git a/crates/ledger/src/state/transaction.rs b/crates/ledger/src/state/transaction.rs index fd2da55a..ae99ad5d 100644 --- a/crates/ledger/src/state/transaction.rs +++ b/crates/ledger/src/state/transaction.rs @@ -16,7 +16,7 @@ use super::{ diff_bind::DiffBind, diff_epoch_reg::DiffEpochReg, diff_set::DiffSet, volatile_db::VolatileState, }; -use crate::kernel::{ +use amaru_kernel::{ output_lovelace, reward_account_to_stake_credential, Certificate, Hash, Lovelace, MintedTransactionBody, NonEmptyKeyValuePairs, PoolId, PoolParams, Set, StakeCredential, TransactionInput, TransactionOutput, STAKE_CREDENTIAL_DEPOSIT, diff --git a/crates/ledger/src/state/volatile_db.rs b/crates/ledger/src/state/volatile_db.rs index f15b535c..b4b0cc66 100644 --- a/crates/ledger/src/state/volatile_db.rs +++ b/crates/ledger/src/state/volatile_db.rs @@ -13,12 +13,10 @@ // limitations under the License. use super::{diff_bind::DiffBind, diff_epoch_reg::DiffEpochReg, diff_set::DiffSet}; -use crate::{ - kernel::{ - epoch_from_slot, Epoch, Lovelace, Point, PoolId, PoolParams, StakeCredential, - TransactionInput, TransactionOutput, - }, - store::{self, columns::*}, +use crate::store::{self, columns::*}; +use amaru_kernel::{ + epoch_from_slot, Epoch, Lovelace, Point, PoolId, PoolParams, StakeCredential, TransactionInput, + TransactionOutput, }; use std::collections::{BTreeSet, VecDeque}; diff --git a/crates/ledger/src/store.rs b/crates/ledger/src/store.rs index 82f3e952..b95289fa 100644 --- a/crates/ledger/src/store.rs +++ b/crates/ledger/src/store.rs @@ -14,9 +14,9 @@ pub mod columns; -use super::kernel::{Epoch, Point, PoolId, TransactionInput, TransactionOutput}; use crate::rewards::Pots; pub use crate::rewards::{RewardsSummary, StakeDistribution}; +use amaru_kernel::{Epoch, Point, PoolId, TransactionInput, TransactionOutput}; use columns::*; use std::{borrow::BorrowMut, io, iter}; use thiserror::Error; diff --git a/crates/ledger/src/store/columns/accounts.rs b/crates/ledger/src/store/columns/accounts.rs index ca0e30ee..509da84a 100644 --- a/crates/ledger/src/store/columns/accounts.rs +++ b/crates/ledger/src/store/columns/accounts.rs @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{ +use amaru_kernel::{ + cbor, iter::borrow as iter_borrow, - kernel::{Lovelace, PoolId, StakeCredential}, + {Lovelace, PoolId, StakeCredential}, }; -use pallas_codec::minicbor::{self as cbor}; pub const EVENT_TARGET: &str = "amaru::ledger::store::accounts"; diff --git a/crates/ledger/src/store/columns/pools.rs b/crates/ledger/src/store/columns/pools.rs index dcb4d652..64910b3c 100644 --- a/crates/ledger/src/store/columns/pools.rs +++ b/crates/ledger/src/store/columns/pools.rs @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{ +use amaru_kernel::{ + cbor, iter::borrow as iter_borrow, - kernel::{Epoch, PoolId, PoolParams}, + {Epoch, PoolId, PoolParams}, }; -use pallas_codec::minicbor::{self as cbor}; use tracing::trace; pub const EVENT_TARGET: &str = "amaru::ledger::store::pools"; @@ -228,7 +228,7 @@ impl<'a, C> cbor::decode::Decode<'a, C> for Row { #[cfg(test)] mod tests { use super::*; - use crate::kernel::{Hash, Nullable, RationalNumber}; + use amaru_kernel::{Hash, Nullable, RationalNumber}; use proptest::prelude::*; prop_compose! { diff --git a/crates/ledger/src/store/columns/pots.rs b/crates/ledger/src/store/columns/pots.rs index 484ad98f..1eac659d 100644 --- a/crates/ledger/src/store/columns/pots.rs +++ b/crates/ledger/src/store/columns/pots.rs @@ -13,8 +13,7 @@ // limitations under the License. /// This modules captures protocol-wide value pots such as treasury and reserves accounts. -use crate::kernel::Lovelace; -use pallas_codec::minicbor::{self as cbor}; +use amaru_kernel::{cbor, Lovelace}; #[derive(Debug, Clone, PartialEq)] pub struct Row { diff --git a/crates/ledger/src/store/columns/slots.rs b/crates/ledger/src/store/columns/slots.rs index 4a718561..3d8dcacf 100644 --- a/crates/ledger/src/store/columns/slots.rs +++ b/crates/ledger/src/store/columns/slots.rs @@ -13,11 +13,11 @@ // limitations under the License. /// This modules captures blocks made by slot leaders throughout epochs. -use crate::{ +use amaru_kernel::{ + cbor, iter::borrow as iter_borrow, - kernel::{PoolId, Slot}, + {PoolId, Slot}, }; -use pallas_codec::minicbor::{self as cbor}; pub type Key = Slot; diff --git a/crates/ledger/src/store/columns/utxo.rs b/crates/ledger/src/store/columns/utxo.rs index f1a797c8..0133ab4d 100644 --- a/crates/ledger/src/store/columns/utxo.rs +++ b/crates/ledger/src/store/columns/utxo.rs @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{ +use amaru_kernel::{ iter::borrow as iter_borrow, - kernel::{TransactionInput, TransactionOutput}, + {TransactionInput, TransactionOutput}, }; pub type Key = TransactionInput; diff --git a/crates/ouroboros/Cargo.toml b/crates/ouroboros/Cargo.toml index 386babd2..443e68cb 100644 --- a/crates/ouroboros/Cargo.toml +++ b/crates/ouroboros/Cargo.toml @@ -13,7 +13,6 @@ rust-version.workspace = true [dependencies] hex.workspace = true kes-summed-ed25519.workspace = true -mockall.workspace = true pallas-codec.workspace = true pallas-crypto.workspace = true pallas-math.workspace = true @@ -26,6 +25,8 @@ tokio.workspace = true tracing.workspace = true vrf_dalek.workspace = true +amaru-kernel = { path = "../kernel" } + [dev-dependencies] ctor.workspace = true insta = { workspace = true, features = ["yaml"] } diff --git a/crates/ouroboros/src/consensus/test.rs b/crates/ouroboros/src/consensus/test.rs index 1eec963b..c75ea7ee 100644 --- a/crates/ouroboros/src/consensus/test.rs +++ b/crates/ouroboros/src/consensus/test.rs @@ -1,10 +1,10 @@ /// A module to expose functions for testing purpose use crate::consensus::validator::BlockValidator; use crate::{ - traits::{HasStakeDistribution, PoolSummary}, validator::{ValidationError, Validator}, Lovelace, PoolId, Slot, VrfKeyhash, }; +use amaru_kernel::traits::{HasStakeDistribution, PoolSummary}; use pallas_codec::minicbor; use pallas_crypto::hash::Hash; use pallas_math::math::FixedDecimal; diff --git a/crates/ouroboros/src/consensus/validator.rs b/crates/ouroboros/src/consensus/validator.rs index 384c0c02..c31250fe 100644 --- a/crates/ouroboros/src/consensus/validator.rs +++ b/crates/ouroboros/src/consensus/validator.rs @@ -1,11 +1,11 @@ use crate::{ issuer_vkey_to_pool_id, kes::{KesPublicKey, KesSignature}, - traits::HasStakeDistribution, validator::{ValidationError, Validator}, vrf::{VrfProof, VrfProofBytes, VrfProofHashBytes, VrfPublicKey, VrfPublicKeyBytes}, PoolId, VrfKeyhash, }; +use amaru_kernel::traits::HasStakeDistribution; use pallas_crypto::{ hash::{Hash, Hasher}, key::ed25519::{PublicKey, Signature}, diff --git a/crates/ouroboros/src/lib.rs b/crates/ouroboros/src/lib.rs index b2750b7c..c7bbe8a8 100644 --- a/crates/ouroboros/src/lib.rs +++ b/crates/ouroboros/src/lib.rs @@ -18,7 +18,6 @@ use pallas_crypto::hash::{Hash, Hasher}; pub mod consensus; pub mod kes; pub mod protocol; -pub mod traits; pub mod validator; pub mod vrf; diff --git a/crates/ouroboros/src/protocol/mod.rs b/crates/ouroboros/src/protocol/mod.rs index ac0cf25d..26e62b8c 100644 --- a/crates/ouroboros/src/protocol/mod.rs +++ b/crates/ouroboros/src/protocol/mod.rs @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +use amaru_kernel::Point; use peer::Peer; use tracing::span::Span; pub mod peer; pub type RawHeader = Vec; -pub type Point = pallas_network::miniprotocols::Point; #[derive(Clone)] pub enum PullEvent { diff --git a/crates/stores/Cargo.toml b/crates/stores/Cargo.toml index 43a2ae25..84c61b82 100644 --- a/crates/stores/Cargo.toml +++ b/crates/stores/Cargo.toml @@ -11,8 +11,13 @@ documentation.workspace = true rust-version.workspace = true [dependencies] -amaru-ledger = { path = "../ledger" } +hex.workspace = true +pallas-codec.workspace = true rocksdb.workspace = true tracing.workspace = true -pallas-codec.workspace = true -hex.workspace = true + +amaru-kernel = { path = "../kernel" } +amaru-ledger = { path = "../ledger" } + +[dev-dependencies] +proptest.workspace = true \ No newline at end of file diff --git a/crates/stores/src/rocksdb/columns/pools.rs b/crates/stores/src/rocksdb/columns/pools.rs index 3c35001a..2a345119 100644 --- a/crates/stores/src/rocksdb/columns/pools.rs +++ b/crates/stores/src/rocksdb/columns/pools.rs @@ -14,7 +14,8 @@ use super::super::common::{as_key, as_value, PREFIX_LEN}; use crate::rocksdb::scolumns::pools::{Key, Row, Value, EVENT_TARGET}; -use amaru_ledger::{kernel::Epoch, store::StoreError}; +use amaru_kernel::Epoch; +use amaru_ledger::store::StoreError; use rocksdb::{OptimisticTransactionDB, ThreadMode, Transaction}; use tracing::error; diff --git a/crates/stores/src/rocksdb/mod.rs b/crates/stores/src/rocksdb/mod.rs index d23244bd..8cbc18b2 100644 --- a/crates/stores/src/rocksdb/mod.rs +++ b/crates/stores/src/rocksdb/mod.rs @@ -13,13 +13,14 @@ // limitations under the License. use ::rocksdb::{self, checkpoint, OptimisticTransactionDB, Options, SliceTransform}; -use amaru_ledger::{ +use amaru_kernel::{ iter::borrow::{self as iter_borrow, borrowable_proxy::BorrowableProxy, IterBorrow}, - kernel::{Epoch, Point, PoolId, TransactionInput, TransactionOutput}, - rewards::{Pots, StakeDistribution}, - store::{ - columns as scolumns, Columns, OpenErrorKind, RewardsSummary, Snapshot, Store, StoreError, - }, + {Epoch, Point, PoolId, TransactionInput, TransactionOutput}, +}; +use amaru_ledger::store::{Columns, OpenErrorKind, RewardsSummary, Snapshot, Store, StoreError}; +use amaru_ledger::{ + rewards::Pots, + store::{columns as scolumns, StakeDistribution}, }; use columns::*; use common::{as_value, PREFIX_LEN}; @@ -166,7 +167,7 @@ impl Snapshot for RocksDB { iter::(&self.db, utxo::PREFIX) } - fn pots(&self) -> Result { + fn pots(&self) -> Result { pots::get(&self.db.transaction()).map(|row| Pots::from(&row)) }