Skip to content

Commit 28e3ddf

Browse files
Merge branch 'next' into santiagopittella-merge-main-to-next
2 parents 67f39b7 + f31cb55 commit 28e3ddf

43 files changed

Lines changed: 941 additions & 1084 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,30 @@ jobs:
139139
- name: Doc tests
140140
run: cargo test --doc --workspace --all-features
141141

142+
# Temporary Diesel schema drift checks. Delete this job once Diesel is removed.
143+
diesel-schema:
144+
name: diesel schema
145+
runs-on: warp-ubuntu-latest-x64-8x
146+
timeout-minutes: 30
147+
steps:
148+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
149+
with:
150+
persist-credentials: false
151+
- name: Rustup
152+
run: rustup toolchain install --no-self-update
153+
- uses: WarpBuilds/rust-cache@9d0cc3090d9c87de74ea67617b246e978735b1a1 # v2.9.1
154+
with:
155+
shared-key: ${{ github.job }}
156+
prefix-key: ${{ env.CACHE_PREFIX }}
157+
save-if: ${{ env.SAVE_CACHE }}
158+
- uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18
159+
with:
160+
tool: diesel_cli@2.3.9
161+
- name: Check Diesel schemas
162+
run: |
163+
cargo test --locked --workspace --all-features \
164+
diesel_schema_is_in_sync_with_migrations -- --ignored
165+
142166
doc:
143167
runs-on: warp-ubuntu-latest-x64-8x
144168
steps:

Cargo.lock

Lines changed: 10 additions & 73 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ deadpool = { default-features = false, version = "0.12" }
8484
deadpool-diesel = { version = "0.6" }
8585
deadpool-sync = { default-features = false, version = "0.1" }
8686
diesel = { version = "2.3" }
87-
diesel_migrations = { version = "2.3" }
8887
fs-err = { version = "3" }
8988
futures = { version = "0.3" }
9089
hex = { version = "0.4" }

bin/ntx-builder/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ anyhow = { workspace = true }
2222
backon = { workspace = true }
2323
clap = { features = ["env", "string"], workspace = true }
2424
diesel = { features = ["numeric", "sqlite"], workspace = true }
25-
diesel_migrations = { features = ["sqlite"], workspace = true }
2625
futures = { workspace = true }
2726
humantime = { workspace = true }
2827
libsqlite3-sys = { workspace = true }
@@ -44,7 +43,8 @@ tracing = { workspace = true }
4443
url = { workspace = true }
4544

4645
[build-dependencies]
47-
build-rs = { workspace = true }
46+
build-rs = { workspace = true }
47+
miden-node-db = { workspace = true }
4848

4949
[dev-dependencies]
5050
miden-node-utils = { features = ["testing"], workspace = true }

bin/ntx-builder/build.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
// This build.rs is required to trigger the `diesel_migrations::embed_migrations!` proc-macro in
2-
// `src/db/migrations.rs` to include the latest version of the migrations into the binary, see
3-
// <https://docs.rs/diesel_migrations/latest/diesel_migrations/macro.embed_migrations.html#automatic-rebuilds>.
1+
fn main() -> Result<(), Box<dyn std::error::Error>> {
2+
miden_node_db::migration::Migrator::generate("src/db/migrations")?;
43

5-
fn main() {
6-
build_rs::output::rerun_if_changed("src/db/migrations");
74
// If we do one re-write, the default rules are disabled,
85
// hence we need to trigger explicitly on `Cargo.toml`.
96
// <https://doc.rust-lang.org/cargo/reference/build-scripts.html#rerun-if-changed>
107
build_rs::output::rerun_if_changed("Cargo.toml");
8+
Ok(())
119
}
Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,73 @@
1-
use diesel::SqliteConnection;
2-
use diesel_migrations::{EmbeddedMigrations, MigrationHarness, embed_migrations};
1+
use std::path::Path;
2+
33
use miden_node_db::DatabaseError;
44
use tracing::instrument;
55

66
use crate::COMPONENT;
7-
use crate::db::schema_hash::verify_schema;
87

9-
// The rebuild is automatically triggered by `build.rs` as described in
10-
// <https://docs.rs/diesel_migrations/latest/diesel_migrations/macro.embed_migrations.html#automatic-rebuilds>.
11-
pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("src/db/migrations");
8+
include!(concat!(env!("OUT_DIR"), "/db_migrator.rs"));
129

1310
#[instrument(level = "debug", target = COMPONENT, skip_all, err)]
14-
pub fn apply_migrations(conn: &mut SqliteConnection) -> Result<(), DatabaseError> {
15-
let migrations = conn.pending_migrations(MIGRATIONS).expect("In memory migrations never fail");
16-
tracing::info!(target: COMPONENT, migrations = migrations.len(), "Applying pending migrations");
17-
18-
let Err(e) = conn.run_pending_migrations(MIGRATIONS) else {
19-
// Migrations applied successfully, verify schema hash.
20-
verify_schema(conn)?;
21-
return Ok(());
22-
};
23-
tracing::warn!(target: COMPONENT, "Failed to apply migration: {e:?}");
24-
// Something went wrong; revert the last migration.
25-
conn.revert_last_migration(MIGRATIONS)
26-
.expect("Duality is maintained by the developer");
11+
pub fn apply_migrations(database_filepath: &Path) -> Result<(), DatabaseError> {
12+
let migrator = migrator().map_err(DatabaseError::migration)?;
13+
tracing::info!(
14+
target: COMPONENT,
15+
migration_count = migrator.schema_hashes().len(),
16+
"Applying database migrations"
17+
);
2718

19+
migrator.migrate(database_filepath).map_err(DatabaseError::migration)?;
2820
Ok(())
2921
}
22+
23+
#[cfg(test)]
24+
mod tests {
25+
use std::process::Command;
26+
27+
use anyhow::{Context, Result, ensure};
28+
use miden_node_db::migration::SchemaHash;
29+
30+
use super::*;
31+
32+
const EXPECTED_SCHEMA_HASHES: [SchemaHash; 1] = [SchemaHash::from_hex(
33+
"c6434bc6a142cd96dd4072bea641546d99788b1495cb0e52c2d98b9138f9c30d",
34+
)];
35+
36+
#[test]
37+
fn migration_schema_hashes_are_stable() -> Result<()> {
38+
let migrator = migrator()?;
39+
40+
assert_eq!(migrator.schema_hashes(), &EXPECTED_SCHEMA_HASHES);
41+
Ok(())
42+
}
43+
44+
#[test]
45+
#[ignore = "requires diesel CLI; CI runs this in the diesel-schema job"]
46+
fn diesel_schema_is_in_sync_with_migrations() -> Result<()> {
47+
let temp_dir = tempfile::tempdir()?;
48+
let database_filepath = temp_dir.path().join("ntx-builder.sqlite3");
49+
apply_migrations(&database_filepath)?;
50+
51+
let output = Command::new("diesel")
52+
.arg("print-schema")
53+
.arg("--database-url")
54+
.arg(&database_filepath)
55+
.current_dir(env!("CARGO_MANIFEST_DIR"))
56+
.output()
57+
.context(
58+
"failed to run diesel CLI; install it with \
59+
`cargo install diesel_cli --no-default-features --features sqlite`",
60+
)?;
61+
62+
ensure!(
63+
output.status.success(),
64+
"diesel print-schema failed: {}",
65+
String::from_utf8_lossy(&output.stderr)
66+
);
67+
68+
let generated =
69+
String::from_utf8(output.stdout).context("diesel CLI output is not UTF-8")?;
70+
assert_eq!(generated, include_str!("schema.rs"));
71+
Ok(())
72+
}
73+
}

bin/ntx-builder/src/db/migrations/2026020900000_setup/up.sql renamed to bin/ntx-builder/src/db/migrations/001_initial.sql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ CREATE TABLE chain_state (
44
-- Singleton constraint: only one row allowed.
55
id INTEGER NOT NULL PRIMARY KEY CHECK (id = 0),
66
-- Block number of the chain tip.
7-
block_num INTEGER NOT NULL,
7+
block_num BIGINT NOT NULL,
88
-- Serialized BlockHeader.
99
block_header BLOB NOT NULL,
1010

@@ -33,7 +33,7 @@ CREATE UNIQUE INDEX idx_accounts_inflight ON accounts(account_id, transaction_id
3333
CREATE INDEX idx_accounts_account ON accounts(account_id);
3434
CREATE INDEX idx_accounts_tx ON accounts(transaction_id) WHERE transaction_id IS NOT NULL;
3535

36-
-- Notes: committed, inflight, and nullified all in one table.
36+
-- Notes: committed, inflight, and nullified - all in one table.
3737
-- created_by = NULL means committed note; non-NULL means created by inflight tx.
3838
-- consumed_by = NULL means unconsumed; non-NULL means consumed by inflight tx.
3939
-- committed_at = block number when the consuming transaction was committed on-chain.
@@ -49,7 +49,7 @@ CREATE TABLE notes (
4949
-- Backoff tracking: number of failed execution attempts.
5050
attempt_count INTEGER NOT NULL DEFAULT 0,
5151
-- Backoff tracking: block number of the last failed attempt. NULL if never attempted.
52-
last_attempt INTEGER,
52+
last_attempt BIGINT,
5353
-- Latest execution error message. NULL if no error recorded.
5454
last_error TEXT,
5555
-- NULL if the note came from a committed block; transaction ID if created by inflight tx.
@@ -58,7 +58,7 @@ CREATE TABLE notes (
5858
consumed_by BLOB,
5959
-- Block number at which the note's consuming transaction was committed.
6060
-- NULL while the note is still pending or in-flight; set on block commit.
61-
committed_at INTEGER,
61+
committed_at BIGINT,
6262

6363
CONSTRAINT notes_attempt_count_non_negative CHECK (attempt_count >= 0),
6464
CONSTRAINT notes_last_attempt_is_u32 CHECK (last_attempt BETWEEN 0 AND 0xFFFFFFFF),

bin/ntx-builder/src/db/migrations/2026020900000_setup/down.sql

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)