Skip to content

Comments

feat: add transaction types to mina-tx-type crate#3481

Open
dannywillems wants to merge 3 commits intomasterfrom
dw/other-types-mina
Open

feat: add transaction types to mina-tx-type crate#3481
dannywillems wants to merge 3 commits intomasterfrom
dw/other-types-mina

Conversation

@dannywillems
Copy link
Member

@dannywillems dannywillems commented Feb 6, 2026

In a follow-up, we will add hashing, regtest, etc. We go step by step.

Summary

  • Add signed command types (payments and stake delegations), zkApp command types (account updates, verification keys, events, actions), fee transfer types, and top-level Transaction/UserCommand enums to the mina-tx-type crate
  • Add supporting types: currency (Balance, Nonce, Slot, SlotSpan, Length, TxnVersion), common utilities (SetOrKeep, OrIgnore, ClosedInterval, OneOrTwo), primitives (TokenId, Memo, AccountId), permissions (AuthRequired, Permissions), and preconditions (NetworkPreconditions, AccountPrecondition)
  • All types are no_std compatible with no circuit traits or mina-p2p-messages dependency, only mina-signer and mina-curves

Builds on top of #3427 which introduced the crate with Coinbase and currency types.

Test plan

  • cargo check -p mina-tx-type passes
  • cargo clippy -p mina-tx-type -- -D warnings passes clean
  • cargo test -p mina-tx-type passes (doc test)
  • CI passes

@dannywillems dannywillems changed the base branch from master to dw/tx-types February 6, 2026 21:02
@dannywillems dannywillems self-assigned this Feb 6, 2026
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Update {
/// zkApp state fields (8 field elements).
pub app_state: [SetOrKeep<Fp>; 8],
Copy link
Member Author

Choose a reason for hiding this comment

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

TODO: add a feature flag for berkeley and a feature flag for mesa, as it changes between both upgrades.

@dannywillems dannywillems moved this to In Progress in Rust node Feb 6, 2026
@dannywillems dannywillems moved this from In Progress to In Review in Rust node Feb 6, 2026
Base automatically changed from dw/tx-types to master February 6, 2026 22:01
Add the remaining Mina transaction types to the mina-tx-type crate:
currency (Balance, Nonce, Slot, SlotSpan, Length, TxnVersion),
common utility types (SetOrKeep, OrIgnore, ClosedInterval, OneOrTwo),
primitives (TokenId, Memo, AccountId, VotingFor, ZkAppUri, TokenSymbol),
permissions (AuthRequired, Permissions), signed commands (payments and
delegations), preconditions (network, account, epoch), zkApp commands
(account updates, verification keys, events, actions), fee transfers,
and top-level Transaction/UserCommand enums.
Copy link
Collaborator

@richardpringle richardpringle left a comment

Choose a reason for hiding this comment

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

I don't understand what all these common types are used for. I didn't see a single pattern match on the enums. There's a lot of code in here that's a maintenance burden if you ask me.

Copy link
Collaborator

Choose a reason for hiding this comment

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

FYI, I'm reviewing this like it's net new code. If it's moved code, that seems fine, I guess.

Comment on lines +7 to +13
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SetOrKeep<T> {
/// Set the field to this value.
Set(T),
/// Keep the field unchanged.
Keep,
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is effectively a duplicate of an Option<T> and I therefore don't see any of its value. What can it do that an Option<T> cannot?

Copy link
Member Author

Choose a reason for hiding this comment

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

It does replicate the OCaml structure available here.

I agree it is isomorphic to Option<T>.
I am not against changing it to something else later.

Check(T),
/// Ignore this field (no constraint).
Ignore,
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same thing for this. It's the same as both Option<T> and SetOrKeep<T>

pub lower: T,
/// The upper bound (inclusive).
pub upper: T,
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This type also already exists in the standard library:
https://doc.rust-lang.org/stable/std/ops/struct.RangeInclusive.html

One(T),
/// Exactly two elements.
Two(T, T),
}
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 it would be better to use standard types here too. (T, Option<T>) accomplishes the same thing.

Comment on lines +48 to +52
/// A hash precondition (check exact value or ignore).
pub type HashCheck<T> = OrIgnore<T>;

/// An equality-check precondition (check exact value or ignore).
pub type EqCheck<T> = OrIgnore<T>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are these here? Type aliases aren't meant to rename other types like this. EqCheck and OrIgnore names imply this single type should not be used for the same thing, but it can, because theres aren't two types, it's one type with two completely different names.


impl_number_u32!(Length, "A blockchain length (block height).");

impl_number_u32!(TxnVersion, "A transaction version number.");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same comments about the other stuff. I think it would be much better to replace all of this with new-types and just use the underlying values. Dependent code on these type should still mostly work. Even in places where it doesn't, it should only take small fixes

/// Format: byte 0 = tag (0x01 for user), byte 1 = length,
/// bytes 2..34 = content (padded with zeros).
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Memo(pub [u8; 34]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

For something like this it's better to have

use bytemuck::{Pod, Zeroable};

/// A transaction memo (34 bytes).
///
/// Format: byte 0 = tag (0x01 for user), byte 1 = length,
/// bytes 2..34 = content (padded with zeros).
///
/// # Example
///
/// ```
/// use bytemuck::{bytes_of, from_bytes};
/// # // Mocking the struct location for the doctest
/// # use playground::Memo;
///
/// // 1. Represent raw data (e.g., from a network stream)
/// let mut raw_bytes = [0u8; 34];
/// raw_bytes[0] = 0x01;       // Tag
/// raw_bytes[1] = 0x05;       // Length
/// raw_bytes[2..7].copy_from_slice(b"Hello"); // Content
///
/// // 2. Zero-cost cast from bytes to &Memo
/// // This cannot fail here because the size (34) and alignment (1) match.
/// let memo: &Memo = from_bytes(&raw_bytes);
///
/// assert_eq!(memo.tag, 1);
/// assert_eq!(memo.length, 5);
/// assert_eq!(&memo.content[..5], b"Hello");
///
/// // 3. Zero-cost cast back to bytes
/// let bytes: &[u8] = bytes_of(memo);
/// assert_eq!(bytes.len(), 34);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Pod, Zeroable)]
#[repr(C)]
pub struct Memo {
    /// Byte 0: Tag (0x01 for user)
    pub tag: u8,
    /// Byte 1: Length of the content
    pub length: u8,
    /// Bytes 2..34: Content (padded with zeros)
    pub content: [u8; 32],
}

/// The public key of the new delegate.
new_delegate: CompressedPubKey,
},
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why an enum with a single variant? That might make sense if we wanted to add #[non_exhaustive] to future proof things, but that isn't being done here.

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

Labels

None yet

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

2 participants