Skip to content

Commit 0775284

Browse files
authored
Merge pull request #1540 from o1-labs/dw/cli-tx
mina-node-account: document + move tests + add tests in CI
2 parents e0c71dc + 14fdc1e commit 0775284

File tree

8 files changed

+174
-106
lines changed

8 files changed

+174
-106
lines changed

.github/workflows/tests.yaml

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ env:
1717
MINA_PANIC_ON_BUG: true
1818
CARGO_INCREMENTAL: 1
1919
RUSTFLAGS: "-C overflow-checks=off -C debug-assertions=off"
20+
RUST_STABLE_VERSION: "1.84"
21+
RUST_NIGHTLY_VERSION: "nightly"
22+
OCAML_VERSION: "4.14.2"
23+
CACHE_VERSION: "v0"
2024

2125
concurrency:
2226
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -31,17 +35,14 @@ jobs:
3135
- name: Setup Rust
3236
uses: ./.github/actions/setup-rust
3337
with:
34-
toolchain: 1.84
38+
toolchain: ${{ env.RUST_STABLE_VERSION }}
3539
enable-cache: false
3640
- name: Clean cargo cache
3741
run: cargo clean
3842

3943
ledger-tests:
4044
timeout-minutes: 20
4145
runs-on: ubuntu-24.04
42-
strategy:
43-
matrix:
44-
ocaml_version: [4.14.2]
4546
steps:
4647
- name: Git checkout
4748
uses: actions/checkout@v5
@@ -52,13 +53,13 @@ jobs:
5253
- name: Use shared OCaml setting up steps
5354
uses: ./.github/actions/setup-ocaml
5455
with:
55-
ocaml_version: ${{ matrix.ocaml_version }}
56+
ocaml_version: ${{ env.OCAML_VERSION }}
5657

5758
- name: Setup Rust
5859
uses: ./.github/actions/setup-rust
5960
with:
60-
toolchain: nightly
61-
cache-prefix: ledger-v0
61+
toolchain: ${{ env.RUST_NIGHTLY_VERSION }}
62+
cache-prefix: ledger-${{ env.CACHE_VERSION }}
6263

6364
- name: Download circuits files
6465
uses: ./.github/actions/setup-circuits
@@ -82,8 +83,8 @@ jobs:
8283
- name: Setup Rust
8384
uses: ./.github/actions/setup-rust
8485
with:
85-
toolchain: nightly
86-
cache-prefix: p2p-messages-v0
86+
toolchain: ${{ env.RUST_NIGHTLY_VERSION }}
87+
cache-prefix: p2p-messages-${{ env.CACHE_VERSION }}
8788

8889
- name: Download circuits files
8990
uses: ./.github/actions/setup-circuits
@@ -127,9 +128,6 @@ jobs:
127128
vrf-tests:
128129
timeout-minutes: 20
129130
runs-on: ubuntu-24.04
130-
strategy:
131-
matrix:
132-
ocaml_version: [4.14.2]
133131
steps:
134132
- name: Git checkout
135133
uses: actions/checkout@v5
@@ -140,13 +138,13 @@ jobs:
140138
- name: Use shared OCaml setting up steps
141139
uses: ./.github/actions/setup-ocaml
142140
with:
143-
ocaml_version: ${{ matrix.ocaml_version }}
141+
ocaml_version: ${{ env.OCAML_VERSION }}
144142

145143
- name: Setup Rust
146144
uses: ./.github/actions/setup-rust
147145
with:
148-
toolchain: nightly
149-
cache-prefix: vrf-v0
146+
toolchain: ${{ env.RUST_NIGHTLY_VERSION }}
147+
cache-prefix: vrf-${{ env.CACHE_VERSION }}
150148

151149
- name: Build vrf tests
152150
run: make build-vrf
@@ -167,8 +165,8 @@ jobs:
167165
- name: Setup Rust
168166
uses: ./.github/actions/setup-rust
169167
with:
170-
toolchain: 1.84
171-
cache-prefix: p2p-v0
168+
toolchain: ${{ env.RUST_STABLE_VERSION }}
169+
cache-prefix: p2p-${{ env.CACHE_VERSION }}
172170

173171
- name: Test p2p crate
174172
run: make test-p2p
@@ -187,13 +185,13 @@ jobs:
187185
- name: Use shared OCaml setting up steps
188186
uses: ./.github/actions/setup-ocaml
189187
with:
190-
ocaml_version: 4.14.2
188+
ocaml_version: ${{ env.OCAML_VERSION }}
191189

192190
- name: Setup Rust
193191
uses: ./.github/actions/setup-rust
194192
with:
195-
toolchain: 1.84
196-
cache-prefix: build-v0
193+
toolchain: ${{ env.RUST_STABLE_VERSION }}
194+
cache-prefix: build-${{ env.CACHE_VERSION }}
197195

198196
- name: Release build
199197
run: make build-release
@@ -222,6 +220,25 @@ jobs:
222220
path: target/release/mina
223221
retention-days: 7
224222

223+
account-tests:
224+
timeout-minutes: 20
225+
runs-on: ubuntu-24.04
226+
steps:
227+
- name: Git checkout
228+
uses: actions/checkout@v5
229+
230+
- name: Setup build dependencies
231+
uses: ./.github/actions/setup-build-deps
232+
233+
- name: Setup Rust
234+
uses: ./.github/actions/setup-rust
235+
with:
236+
toolchain: ${{ env.RUST_STABLE_VERSION }}
237+
cache-prefix: build-${{ env.CACHE_VERSION }}
238+
239+
- name: Run account tests
240+
run: make test-account
241+
225242
build-tests:
226243
timeout-minutes: 60
227244
runs-on: ubuntu-22.04
@@ -235,13 +252,13 @@ jobs:
235252
- name: Use shared OCaml setting up steps
236253
uses: ./.github/actions/setup-ocaml
237254
with:
238-
ocaml_version: 4.14.2
255+
ocaml_version: ${{ env.OCAML_VERSION }}
239256

240257
- name: Setup Rust
241258
uses: ./.github/actions/setup-rust
242259
with:
243-
toolchain: 1.84
244-
cache-prefix: build-tests-v0
260+
toolchain: ${{ env.RUST_STABLE_VERSION }}
261+
cache-prefix: build-tests-${{ env.CACHE_VERSION }}
245262

246263
- name: Build tests
247264
run: make build-tests
@@ -266,13 +283,13 @@ jobs:
266283
- name: Use shared OCaml setting up steps
267284
uses: ./.github/actions/setup-ocaml
268285
with:
269-
ocaml_version: 4.14.2
286+
ocaml_version: ${{ env.OCAML_VERSION }}
270287

271288
- name: Setup Rust
272289
uses: ./.github/actions/setup-rust
273290
with:
274-
toolchain: 1.84
275-
cache-prefix: build-tests-webrtc-v0
291+
toolchain: ${{ env.RUST_STABLE_VERSION }}
292+
cache-prefix: build-tests-webrtc-${{ env.CACHE_VERSION }}
276293

277294
- name: Build tests
278295
run: make build-tests-webrtc
@@ -297,8 +314,8 @@ jobs:
297314
- name: Setup Rust
298315
uses: ./.github/actions/setup-rust
299316
with:
300-
toolchain: nightly
301-
cache-prefix: build-wasm-v0
317+
toolchain: ${{ env.RUST_NIGHTLY_VERSION }}
318+
cache-prefix: build-wasm-${{ env.CACHE_VERSION }}
302319

303320
- name: Setup wasm tooling
304321
run: make setup-wasm

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4040
dummy values ([#1514](https://github.com/o1-labs/mina-rust/pull/1514))
4141
- **CI/Documentation**: add a script to check the references to the OCaml code
4242
([#1525](https://github.com/o1-labs/mina-rust/pull/1525)).
43+
- **mina-node-account**: move tests into `node/account/tests`, document the
44+
library and run the tests in CI
45+
([#1540](https://github.com/o1-labs/mina-rust/pull/1540)).
4346

4447
### Changed
4548

Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,12 @@ test-release: ## Run tests in release mode
302302

303303
.PHONY: test-vrf
304304
test-vrf: ## Run VRF tests, requires nightly Rust
305-
@cd vrf && cargo +$(NIGHTLY_RUST_VERSION) test --release -- -Z unstable-options --report-time
305+
@cd vrf && cargo +$(NIGHTLY_RUST_VERSION) test --release -- \
306+
-Z unstable-options --report-time
307+
308+
.PHONY: test-account
309+
test-account: ## Run account tests
310+
@cargo test -p mina-node-account
306311

307312
.PHONY: test-p2p-messages
308313
test-p2p-messages:

node/account/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ name = "mina-node-account"
33
version = "0.17.0"
44
edition = "2021"
55
license = "Apache-2.0"
6+
description = "Account management for Mina nodes, including key generation, encryption, and address handling"
67

78
[dependencies]
89
anyhow = { workspace = true }

node/account/src/lib.rs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,68 @@
1-
mod secret_key;
2-
pub use secret_key::AccountSecretKey;
1+
//! Account management for Mina nodes
2+
//!
3+
//! This crate provides a high-level interface for managing Mina accounts,
4+
//! built on top of the
5+
//! [`mina-signer`](https://github.com/o1-labs/proof-systems/tree/master/signer)
6+
//! crate. It handles cryptographic key generation, encryption/decryption of
7+
//! secret keys, and address handling.
8+
//!
9+
//! # Overview
10+
//!
11+
//! The crate exports two main types:
12+
//! - [`AccountSecretKey`] - Represents a private key that can be used to
13+
//! sign transactions
14+
//! - [`AccountPublicKey`] - Represents a public key/address for receiving
15+
//! transactions
16+
//!
17+
//! # Key Features
18+
//!
19+
//! - **Key Generation**: Generate new random keypairs for Mina accounts
20+
//! - **Key Encryption**: Encrypt and decrypt secret keys using password-based
21+
//! encryption
22+
//! - **Address Format**: Encode and decode Mina addresses using the standard
23+
//! Base58Check format
24+
//! - **Key Import/Export**: Read and write encrypted keys from/to files
25+
//!
26+
//! # Example Usage
27+
//!
28+
//! ```
29+
//! use mina_node_account::{AccountSecretKey, AccountPublicKey};
30+
//! use std::env;
31+
//!
32+
//! // Generate a new keypair
33+
//! let secret_key = AccountSecretKey::rand();
34+
//! let public_key = secret_key.public_key();
35+
//!
36+
//! // Save encrypted key to file in temp directory
37+
//! let temp_dir = env::temp_dir();
38+
//! let path = temp_dir.join(format!("test-wallet-{}", public_key));
39+
//! let password = "secure-password";
40+
//! secret_key.to_encrypted_file(&path, password)
41+
//! .expect("Failed to save key");
42+
//!
43+
//! // Load encrypted key from file
44+
//! let loaded_key = AccountSecretKey::from_encrypted_file(&path, password)
45+
//! .expect("Failed to load key");
46+
//!
47+
//! // Get the public address
48+
//! let address = AccountPublicKey::from(loaded_key.public_key());
49+
//! println!("Address: {}", address);
50+
//!
51+
//! // Verify the keys match
52+
//! assert_eq!(secret_key.public_key().to_string(),
53+
//! loaded_key.public_key().to_string());
54+
//!
55+
//! // Clean up
56+
//! std::fs::remove_file(&path).ok();
57+
//! ```
58+
//!
59+
//! # Cryptography
60+
//!
61+
//! Mina uses the Pasta curves (Pallas and Vesta) for its cryptographic
62+
//! operations. These curves are specifically designed for efficient
63+
//! recursive zero-knowledge proof composition.
364
465
mod public_key;
66+
mod secret_key;
567
pub use public_key::AccountPublicKey;
68+
pub use secret_key::AccountSecretKey;

node/account/src/public_key.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::{fmt, str::FromStr};
2-
31
use mina_p2p_messages::{
42
b58::FromBase58CheckError,
53
binprot::{
@@ -8,9 +6,9 @@ use mina_p2p_messages::{
86
},
97
v2::{NonZeroCurvePoint, NonZeroCurvePointUncompressedStableV1},
108
};
11-
use serde::{Deserialize, Serialize};
12-
139
use mina_signer::{CompressedPubKey, PubKey};
10+
use serde::{Deserialize, Serialize};
11+
use std::{fmt, str::FromStr};
1412

1513
#[derive(
1614
BinProtWrite, BinProtRead, Serialize, Deserialize, Debug, Ord, PartialOrd, Eq, PartialEq, Clone,

node/account/src/secret_key.rs

Lines changed: 2 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
use std::{fmt, fs, io, path::Path, str::FromStr};
2-
1+
use super::AccountPublicKey;
32
use mina_core::{
43
constants::GENESIS_PRODUCER_SK, EncryptedSecretKey, EncryptedSecretKeyFile, EncryptionError,
54
};
65
use mina_p2p_messages::{bigint::BigInt, v2::SignatureLibPrivateKeyStableV1};
76
use mina_signer::{keypair::KeypairError, seckey::SecKeyError, CompressedPubKey, Keypair};
87
use rand::{rngs::StdRng, CryptoRng, Rng, SeedableRng};
98
use serde::{Deserialize, Serialize};
10-
11-
use super::AccountPublicKey;
9+
use std::{fmt, fs, io, path::Path, str::FromStr};
1210

1311
#[derive(Clone)]
1412
pub struct AccountSecretKey(Keypair);
@@ -193,70 +191,3 @@ impl<'de> serde::Deserialize<'de> for AccountSecretKey {
193191
b58.parse().map_err(serde::de::Error::custom)
194192
}
195193
}
196-
197-
#[cfg(test)]
198-
mod tests {
199-
use std::env;
200-
201-
use super::*;
202-
203-
#[test]
204-
fn test_account_secret_key_bs58check_decode() {
205-
let parsed: AccountSecretKey = "EKFWgzXsoMYcP1Hnj7dBhsefxNucZ6wyz676Qg5uMFNzytXAi2Ww"
206-
.parse()
207-
.unwrap();
208-
assert_eq!(
209-
parsed.0.get_address(),
210-
"B62qjVQLxt9nYMWGn45mkgwYfcz8e8jvjNCBo11VKJb7vxDNwv5QLPS"
211-
);
212-
}
213-
214-
#[test]
215-
fn test_account_secret_key_display() {
216-
let parsed: AccountSecretKey = "EKFWgzXsoMYcP1Hnj7dBhsefxNucZ6wyz676Qg5uMFNzytXAi2Ww"
217-
.parse()
218-
.unwrap();
219-
assert_eq!(
220-
&parsed.to_string(),
221-
"EKFWgzXsoMYcP1Hnj7dBhsefxNucZ6wyz676Qg5uMFNzytXAi2Ww"
222-
);
223-
}
224-
225-
#[test]
226-
fn test_encrypt_decrypt() {
227-
let password = "not-very-secure-pass";
228-
229-
let new_key = AccountSecretKey::rand();
230-
let tmp_dir = env::temp_dir();
231-
let tmp_path = format!("{}/{}-key", tmp_dir.display(), new_key.public_key());
232-
233-
// dump encrypted file
234-
new_key
235-
.to_encrypted_file(&tmp_path, password)
236-
.expect("Failed to encrypt secret key");
237-
238-
// load and decrypt
239-
let decrypted = AccountSecretKey::from_encrypted_file(&tmp_path, password)
240-
.unwrap_or_else(|_| panic!("Failed to decrypt secret key file: {}", tmp_path));
241-
242-
assert_eq!(
243-
new_key.public_key(),
244-
decrypted.public_key(),
245-
"Encrypted and decrypted public keys do not match"
246-
);
247-
}
248-
249-
#[test]
250-
fn test_ocaml_key_decrypt() {
251-
let password = "not-very-secure-pass";
252-
let key_path = "../tests/files/accounts/test-key-1";
253-
let expected_public_key = "B62qmg7n4XqU3SFwx9KD9B7gxsKwxJP5GmxtBpHp1uxyN3grujii9a1";
254-
let decrypted = AccountSecretKey::from_encrypted_file(key_path, password)
255-
.unwrap_or_else(|_| panic!("Failed to decrypt secret key file: {}", key_path));
256-
257-
assert_eq!(
258-
expected_public_key.to_string(),
259-
decrypted.public_key().to_string()
260-
)
261-
}
262-
}

0 commit comments

Comments
 (0)