Skip to content

chore: migrate to protocol v0.14.0-beta.1#1784

Draft
mmagician wants to merge 22 commits intonextfrom
mmagician-claude/update-base-to-beta
Draft

chore: migrate to protocol v0.14.0-beta.1#1784
mmagician wants to merge 22 commits intonextfrom
mmagician-claude/update-base-to-beta

Conversation

@mmagician
Copy link
Contributor

@mmagician mmagician commented Mar 11, 2026

Summary

  • Update all miden-protocol dependencies from 0.14.0-alpha.1 to 0.14.0-beta.1
  • Update miden-crypto from 0.19.7 to 0.22
  • Remove miden-air dependency
  • Bump node workspace version to 0.14.0-beta.1

Key API migrations

  • Serialization traits moved to utils::serde submodule
  • Felt::as_int() -> Felt::as_canonical_u64()
  • falcon512_rpo -> falcon512_poseidon2
  • ProvenTransactionBuilder removed, use ProvenTransaction::new() + TxAccountUpdate (refactor: remove ProvenTransactionBuilder in favor of ProvenTransaction::new protocol#2567)
  • OutputNote variants: Full -> Public, Header -> Private
  • Asset is now key-value (two words instead of one)
  • MmrProof fields are now methods
  • account_id_to_smt_key -> AccountIdKey::from()
  • SmtStorage trait methods now take &mut self
  • AccountStateForest rewritten to replace removed LargeSmtForest

Test plan

  • cargo check --all-targets passes
  • make lint passes (clippy, formatting, machete)
  • CI passes

🤖 Generated with Claude Code

@mmagician mmagician added the no changelog This PR does not require an entry in the `CHANGELOG.md` file label Mar 11, 2026
Update all miden-protocol dependencies from 0.14.0-alpha.1 to
0.14.0-beta.1 (crates.io). Update miden-crypto from 0.19.7 to 0.22.
Bump node workspace version to 0.14.0-beta.1.

Key migration changes:
- Serialization traits moved to utils::serde submodule
- Felt::as_int() -> Felt::as_canonical_u64()
- falcon512_rpo -> falcon512_poseidon2
- ProvenTransactionBuilder removed, use ProvenTransaction::new()
- OutputNote variants: Full -> Public, Header -> Private
- Asset is now key-value (two words instead of one)
- MmrProof fields are now methods
- account_id_to_smt_key -> AccountIdKey::from()
- miden-air removed (replaced by miden-core 0.21)
- SmtStorage trait methods now take &mut self
- Various other API changes in miden-crypto 0.22
@mmagician mmagician force-pushed the mmagician-claude/update-base-to-beta branch from b785bde to 922cd86 Compare March 11, 2026 19:46
@mmagician mmagician changed the title chore: migrate to protocol v0.14.0-beta.1 chore: migrate to protocol v0.14.0-beta.1 Mar 11, 2026
@mmagician mmagician force-pushed the mmagician-claude/update-base-to-beta branch from bb9974c to 5320e57 Compare March 12, 2026 10:29
@mmagician
Copy link
Contributor Author

(force pushed coz I had unsigned commits)

Comment on lines 76 to 78
#[error("the ntx task panicked")]
#[expect(dead_code)]
Panic(#[source] JoinError),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably can be removed

claude added 3 commits March 12, 2026 13:39
- Use LargeSmt::load() instead of LargeSmt::new() in load_smt to
  support loading from non-empty RocksDB storage on restart (new() now
  errors with StorageNotEmpty in miden-crypto 0.22)
- Fix prune logic to remove all versions before cutoff while keeping
  at least one version per lineage to preserve current state
- Only pop roots from SmtForest that are no longer referenced by any
  lineage (prevents removing shared roots)
- Fix test helpers tree_id_for_root/tree_id_for_vault_root to use
  get_root_at_block instead of latest_root
- Update all prune test assertions for the new version-tracking model
  (our AccountStateForest uses explicit version entries rather than
  LargeSmtForest's deduplicated tree count)
Replace ~130 lines of hand-rolled DER parsing with proper library calls:
- Use spki::SubjectPublicKeyInfoRef::from_der() for SPKI public key parsing
- Use k256::ecdsa::Signature::from_der() for DER signature decoding

This restores the simplicity of the original code before the migration,
where PublicKey::from_der() and Signature::from_der() were available
directly on the miden-crypto types.
Resolve conflicts in ntx-builder query tests by keeping test_utils
imports and fixing TransactionId::new() signature for the beta API.
batch.put_cf(metadata_cf, ENTRY_COUNT_KEY, new_entry_count.to_be_bytes());
}

batch.put_cf(metadata_cf, ROOT_KEY, new_root.to_bytes());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why was this removed?

self.initial_account_commitment,
self.final_account_commitment,
Word::empty(),
AccountUpdateDetails::Private,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering why this is set to Private.
ProvenTransaction::new used to default to Private if no account_update was specified, so this preserves the behavior

claude added 4 commits March 12, 2026 15:05
Remove stale comment about missing re-exports (fixed in miden-crypto
0.22.5) and import from miden_protocol::crypto::merkle::smt to match
the convention used on next.
Public and private accounts were created with overlapping seed index
ranges, which in the v0.14 beta can produce accounts with duplicate
ID prefixes. Use separate non-overlapping index offsets for each
storage mode within a block.
The previous approach used low-entropy seeds (index padded with zeros)
which could produce AccountId prefix collisions during the hash
grinding process. Use a seeded PRNG to generate full 32-byte random
seeds per account while maintaining deterministic behavior.
Resolve conflict in state/loader.rs imports: keep RocksDbOptions from
next's rocksdb config PR and AccountIdKey from our beta migration.
Comment on lines +513 to +515
let rebuilt = PublicOutputNote::new(public_note.as_note().clone())
.expect("rebuilding an already-valid public output note should not fail");
OutputNote::Public(rebuilt)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this works but we might want to propagate minify_script to PublicOutputNote to avoid the reconstruction.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minify_script() is called in PublicOutputNote::new() - so, by construction all PublicOutputNotes have minified scripts. But maybe I didn't understand the comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite: I was thinking of mutating PublicOutputNote, something like:

fn strip_output_note_decorators<'a>(
    notes: impl Iterator<Item = &'a OutputNote> + 'a,
) -> impl Iterator<Item = OutputNote> + 'a {
    notes.map(|note| match note {
        OutputNote::Public(public_note) => {
            let minified = public_note.clone().minify_script(); // <------ would need this
            OutputNote::Public(public_note) 
        },
        OutputNote::Private(header) => OutputNote::Private(header.clone()),
    })
}

so rather than fully reconstructing PublicOutputNote::new(), we would avoid some of the other checks that new constructor performs. These checks are not expensive at all, but I think it would also be cleaner to "only do the work necessary" to strip the decorators, using the constructor to do it feels somewhat hacky.

/// `SmtForest` for efficient account storage reconstruction.
/// Populated during block import with storage and vault SMTs.
forest: LargeSmtForest<ForestInMemoryBackend>,
forest: SmtForest,
Copy link
Contributor Author

@mmagician mmagician Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm is this change correct? What's the reason this was changed to not use LargeSmtForest anymore?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the ForestInMemoryBackend is not available in in miden-crypto 0.22 and it decided to replace it with SmtForest plus some extra functionality. @drahnr (or maybe @bobbinth) should ForestInMemoryBackend be ported to 0.22 or what is the expectation here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to not undo the migration to LargeSmtForest in next, it simplified a lot of code.

claude and others added 2 commits March 12, 2026 16:55
- Remove dead `Panic(JoinError)` variant from `NtxError`
- Remove unused `get_root`/`set_root` and `ROOT_KEY` from `RocksDbStorage`
- Replace verbose `std::iter::empty` with `Vec::new()` in rpc tests
- Extract inline fee construction to `test_fee()` variable in store tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment on lines +2976 to +2977
// cutoff = 53 - 50 = 3: each of the 3 lineages has one version < 3 that gets removed
// (account1 v=1, account2 v=2, account3 v=2), since each also has a newer version.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also I don't fully understand the lineage changes cc @drahnr

.subject_public_key
.as_bytes()
.ok_or_else(|| DeserializationError::InvalidValue("Invalid SPKI BIT STRING".into()))?;
let pub_key = PublicKey::read_from_bytes(sec1_bytes)?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want these diffs. As in we want to keep:

let pub_key = PublicKey::from_der(spki_der)?;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the parsing was introduced during the migration because miden-crypto 0.22 does not contain the PublicKey::from_der() and Signature::from_der() methods. Should this also be ported to 0.22.X?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If from_der() is not in v0.22, @sergerad - could you make a quick PR to cherry-pick relevant commits into v0.22.x branch in miden-crypto and I'll make another patch release.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just in case, there's also this that might need porting. You probably saw already but mentioning it in the unlikely case you didn't, so that we don't waste a patch release.

@SantiagoPittella
Copy link
Collaborator

I created #1793 using this PR as base. It is a really simple one. If you prefer I can push the commit here, or feel free to just copy the code.

@mmagician
Copy link
Contributor Author

go right ahead @SantiagoPittella!

@igamigo
Copy link
Collaborator

igamigo commented Mar 13, 2026

Pushed a commit to point to 0xMiden/protocol#2598 which fixes the stress test (and the overall functionality of the account tree). Also removed the crypto patch in favor of updating the package version to the recently-released 0.22.6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no changelog This PR does not require an entry in the `CHANGELOG.md` file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants