Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/integration_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
--rm \
--publish 5005:5005 \
--publish 6006:6006 \
--volume "${{ github.workspace }}/.ci-config/":"/etc/opt/xrpld/" \
--volume "${{ github.workspace }}/.ci-config/":"/etc/xrpld/" \
--name xrpld-service \
${{ env.XRPLD_DOCKER_IMAGE }} --standalone

Expand Down
32 changes: 27 additions & 5 deletions .github/workflows/unit_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,44 @@ jobs:
RUST_BACKTRACE: 1
Comment thread
kuan121 marked this conversation as resolved.

- name: Test for no_std
run: cargo test --release --no-default-features --features embassy-rt,core,utils,wallet,models,helpers,websocket,json-rpc
run: cargo test --release --no-default-features --features
embassy-rt,core,utils,wallet,models,helpers,websocket,json-rpc
env:
RUST_BACKTRACE: 1

- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov

# Unit-test coverage is scoped via Cargo features rather than path
# exclusion. The minimal feature set (`std,core,utils,wallet,models`)
# compiles only the pure-logic modules — pure crypto, codec, address
# codec, transaction models, and the `signing` module. Integration-
# territory code (CLI, async network clients, sync wrappers around
# network calls, faucet client) is gated behind `helpers`/`json-rpc`/
# `websocket`/`cli` features, so it simply isn't compiled here and
# doesn't appear in the coverage report. Those files are exercised by
# the integration-test workflow against a live rippled.
- name: Generate coverage report
run: cargo llvm-cov --lcov --output-path lcov.info
run: |
cargo llvm-cov \
--no-default-features --features std,core,utils,wallet,models \
--lcov --output-path lcov.info

- name: Check coverage thresholds
run: |
cargo llvm-cov --summary-only \
--fail-under-lines 73 \
--fail-under-regions 75 \
--fail-under-functions 67
--no-default-features --features std,core,utils,wallet,models \
--fail-under-lines 83 \
--fail-under-regions 85 \
--fail-under-functions 73
Comment on lines +64 to +66

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: the fail threshold parameters are redundant with the Codecov checks, because the latter also performs coverage checks.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Only lines would be covered by codecov, not regions and functions. I would say let's just keep them for extra rigor


- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov.info
flags: unit
fail_ci_if_error: true

- name: Upload coverage report
uses: actions/upload-artifact@v4
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- New `xrpl::signing` module containing the pure-crypto signing helpers (`sign`, `multisign`, `prepare_transaction`) extracted from `asynch::transaction` and `transaction`. Available with just `core + models + wallet` features (no `helpers`/runtime/client dependency). The legacy paths `asynch::transaction::sign` and `transaction::multisign` are preserved as re-exports for backward compatibility.
- Expanded unit-test coverage and raised CI thresholds: lines `73 → 83`, regions `75 → 85`, functions `67 → 73`.
- Codecov integration with per-PR project (≥83%) and patch (≥80% on new/modified lines) gates.

### Changed

- Unit-test and integration-test coverage are now scoped via Cargo feature flags rather than path regex. The unit-test workflow builds with `--no-default-features --features std,core,utils,wallet,models`, so integration-territory code (CLI, async clients, sync wrappers, faucet) simply isn't compiled and doesn't appear in the unit coverage report.
- Network-dependent inline tests in `src/asynch/transaction/` and `src/asynch/wallet/` (`test_autofill_txn`, `test_autofill_and_sign`, `test_submit_and_wait`, `test_generate_faucet_wallet`) are now gated behind `feature = "integration"` so `cargo test --release` is hermetic by default.

### Fixed

- `RipplePathFind::destination_amount` changed from `Currency<'a>` to `Amount<'a>` to match the XRPL wire format.
- `NoRippleCheckRole` no longer serializes with the `#[serde(tag = "role")]` discriminator; now emits a plain `snake_case` string matching the XRPL wire format.

## [[v1.1.0]]

### Added
Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ From the `xrpl-rust` folder, run the following commands:
```bash
# Sets up the xrpld standalone Docker container — skip if you already have it running
docker run -p 5005:5005 -p 6006:6006 --rm -it --name xrpld_standalone \
--volume "$PWD/.ci-config/:/etc/opt/xrpld/" \
--volume "$PWD/.ci-config/:/etc/xrpld/" \
rippleci/xrpld:develop --standalone
cargo test --release --features integration,std,json-rpc,helpers
```
Expand All @@ -91,7 +91,7 @@ Breaking down the `docker run` command:
- `--rm` closes the container automatically when it exits.
- `-it` keeps stdin open so you can stop the node with Ctrl-C.
- `--name xrpld_standalone` is an instance name for clarity.
- `--volume $PWD/.ci-config/:/etc/opt/xrpld/`: bind-mounts the host directory (left side) into the container (right side). `xrpld.cfg` lives in `$PWD/.ci-config/`, and this command is intended to be run from the root of the `xrpl-rust` project. The `xrpld` binary searches for its configuration file inside `/etc/opt/xrpld/`. An absolute path is required, so we use `$PWD` instead of `./`.
- `--volume $PWD/.ci-config/:/etc/xrpld/`: bind-mounts the host directory (left side) into the container (right side). `xrpld.cfg` lives in `$PWD/.ci-config/`, and this command is intended to be run from the root of the `xrpl-rust` project. The `xrpld` binary searches for its configuration file inside `/etc/xrpld/`. An absolute path is required, so we use `$PWD` instead of `./`.
- `rippleci/xrpld` is an image that is regularly updated with the latest `xrpld` releases (the binary formerly known as `rippled`; see xrpl.js PR #3270).
- `--standalone` starts `xrpld` in standalone mode, where ledgers only close on demand.

Expand All @@ -114,7 +114,7 @@ cargo llvm-cov --summary-only
The CI enforces the following minimum thresholds (current baseline is ~78% lines / ~68% regions / ~75% functions, measured with default features only — integration tests are excluded from coverage):

| Metric | Minimum |
|-----------|---------|
| --------- | ------- |
| Lines | 75% |
| Regions | 65% |
| Functions | 72% |
Expand Down
21 changes: 21 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
coverage:
Comment thread
pdp2121 marked this conversation as resolved.
status:
project:
default:
target: 83%
threshold: 1%
flags:
- unit
patch:
default:
target: 80%
threshold: 1%

comment:
layout: "reach, diff, flags, files"
require_changes: false

flags:
unit:
paths:
- src/
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ services:
xrpld:
image: rippleci/xrpld:develop
volumes:
- ./.ci-config:/etc/opt/xrpld
- ./.ci-config:/etc/xrpld
ports:
- "5005:5005"
- "6006:6006"
Expand Down
38 changes: 19 additions & 19 deletions src/asynch/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,27 @@ use thiserror_no_std::Error;
use super::clients::exceptions::XRPLClientException;
#[cfg(feature = "helpers")]
use super::{
transaction::exceptions::{
XRPLSignTransactionException, XRPLSubmitAndWaitException, XRPLTransactionHelperException,
},
transaction::exceptions::{XRPLSubmitAndWaitException, XRPLTransactionHelperException},
wallet::exceptions::XRPLFaucetException,
};
#[cfg(feature = "helpers")]
#[cfg(feature = "wallet")]
use crate::wallet::exceptions::XRPLWalletException;
// Available whenever `signing` is compiled (which requires core+models+wallet),
// or whenever `helpers` is on — the former is a subset of the latter.
#[cfg(all(feature = "core", feature = "models", feature = "wallet"))]
use crate::{
core::exceptions::XRPLCoreException,
models::transactions::exceptions::XRPLTransactionFieldException,
transaction::exceptions::XRPLMultisignException, utils::exceptions::XRPLUtilsException,
wallet::exceptions::XRPLWalletException,
signing::exceptions::{XRPLMultisignException, XRPLSignTransactionException},
utils::exceptions::XRPLUtilsException,
};
use crate::{models::XRPLModelException, XRPLSerdeJsonError};

pub type XRPLHelperResult<T, E = XRPLHelperException> = core::result::Result<T, E>;

#[derive(Debug, Error)]
pub enum XRPLHelperException {
#[cfg(feature = "helpers")]
#[cfg(feature = "wallet")]
#[error("XRPL Wallet error: {0}")]
XRPLWalletError(#[from] XRPLWalletException),
#[cfg(feature = "helpers")]
Expand All @@ -33,18 +35,21 @@ pub enum XRPLHelperException {
XRPLTransactionHelperError(#[from] XRPLTransactionHelperException),
#[error("XRPL Model error: {0}")]
XRPLModelError(#[from] XRPLModelException),
#[cfg(feature = "helpers")]
#[cfg(all(feature = "core", feature = "models", feature = "wallet"))]
#[error("XRPL Core error: {0}")]
XRPLCoreError(#[from] XRPLCoreException),
#[cfg(feature = "helpers")]
#[cfg(all(feature = "core", feature = "models", feature = "wallet"))]
#[error("XRPL Transaction Field error: {0}")]
XRPLTransactionFieldError(#[from] XRPLTransactionFieldException),
#[cfg(feature = "helpers")]
#[cfg(all(feature = "core", feature = "models", feature = "wallet"))]
#[error("XRPL Utils error: {0}")]
XRPLUtilsError(#[from] XRPLUtilsException),
#[cfg(feature = "helpers")]
#[cfg(all(feature = "core", feature = "models", feature = "wallet"))]
#[error("XRPL MultiSign error: {0}")]
XRPLMultiSignError(#[from] XRPLMultisignException),
#[cfg(all(feature = "core", feature = "models", feature = "wallet"))]
#[error("XRPL Sign Transaction error: {0}")]
XRPLSignTransactionError(#[from] XRPLSignTransactionException),
#[cfg(any(feature = "json-rpc", feature = "websocket"))]
#[error("XRPL Client error: {0}")]
XRPLClientError(#[from] XRPLClientException),
Expand All @@ -63,14 +68,9 @@ impl From<serde_json::Error> for XRPLHelperException {
}
}

#[cfg(feature = "helpers")]
impl From<XRPLSignTransactionException> for XRPLHelperException {
fn from(error: XRPLSignTransactionException) -> Self {
XRPLHelperException::XRPLTransactionHelperError(
XRPLTransactionHelperException::XRPLSignTransactionError(error),
)
}
}
// `XRPLSignTransactionException` is now a direct variant of
// `XRPLHelperException` (see `XRPLSignTransactionError`), so the `From` impl
// is derived automatically.

#[cfg(feature = "helpers")]
impl From<XRPLSubmitAndWaitException> for XRPLHelperException {
Expand Down
15 changes: 4 additions & 11 deletions src/asynch/transaction/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ use core::num::ParseIntError;
use alloc::string::String;
use thiserror_no_std::Error;

// XRPLSignTransactionException now lives in `crate::signing::exceptions`.
// Re-exported here for backward compatibility.
pub use crate::signing::exceptions::XRPLSignTransactionException;

#[derive(Error, Debug, PartialEq)]
#[non_exhaustive]
pub enum XRPLTransactionHelperException {
Expand All @@ -18,17 +22,6 @@ pub enum XRPLTransactionHelperException {
XRPLSubmitAndWaitError(#[from] XRPLSubmitAndWaitException),
}

#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum XRPLSignTransactionException {
#[error("{0:?} value does not match X-Address tag")]
TagFieldMismatch(String),
#[error("Fee value of {0:?} is likely entered incorrectly, since it is much larger than the typical XRP transaction cost. If this is intentional, use `check_fee=Some(false)`.")]
FeeTooHigh(String),
#[error("Wallet is required to sign transaction")]
WalletRequired,
}

#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[non_exhaustive]
pub enum XRPLSubmitAndWaitException {
Expand Down
Loading
Loading