mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-21 14:11:07 +00:00
Compare commits
9 Commits
dependabot
...
ximinez/nu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e907273ce6 | ||
|
|
60b49f3fe0 | ||
|
|
4c869ee16c | ||
|
|
3825ac1721 | ||
|
|
b2f45813e0 | ||
|
|
e305a7546e | ||
|
|
cbf2c87d7c | ||
|
|
e0ced0e375 | ||
|
|
e17d381879 |
4
.github/workflows/build-nix-images.yml
vendored
4
.github/workflows/build-nix-images.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Build Nix Docker images
|
||||
name: Build `nix` Docker images
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -36,7 +36,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
build-merge:
|
||||
name: Build and push nix-${{ matrix.distro.name }}
|
||||
name: Build and push `nix-${{ matrix.distro.name }}` image
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
4
.github/workflows/build-packaging-images.yml
vendored
4
.github/workflows/build-packaging-images.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Build packaging Docker images
|
||||
name: Build `packaging` Docker images
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -26,7 +26,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
build-merge:
|
||||
name: Build and push packaging-${{ matrix.distro.name }}
|
||||
name: Build and push `packaging-${{ matrix.distro.name }}` image
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
36
.github/workflows/build-pre-commit-image.yml
vendored
Normal file
36
.github/workflows/build-pre-commit-image.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Build `pre-commit` Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- ".github/workflows/build-pre-commit-image.yml"
|
||||
- "bin/pre-commit/Dockerfile"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/build-pre-commit-image.yml"
|
||||
- "bin/pre-commit/Dockerfile"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
# Read `on-trigger.yml` for the rationale behind this concurrency group name.
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && github.sha || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
build-merge:
|
||||
name: Build and push `pre-commit` image
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@ee03d31bcc4501d7599dc1b1ecd7a34af582ad1c
|
||||
with:
|
||||
image_name: xrpld/pre-commit
|
||||
dockerfile: bin/pre-commit/Dockerfile
|
||||
base_image: ubuntu:26.04
|
||||
push: ${{ github.event_name == 'push' }}
|
||||
2
.github/workflows/pre-commit.yml
vendored
2
.github/workflows/pre-commit.yml
vendored
@@ -17,4 +17,4 @@ jobs:
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@1bde119a1ab71305ba5d3716e7a82cea1c7bdede
|
||||
with:
|
||||
runs_on: ubuntu-latest
|
||||
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-41ec7c1" }'
|
||||
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-4c869ee" }'
|
||||
|
||||
2
.github/workflows/reusable-package.yml
vendored
2
.github/workflows/reusable-package.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ repos:
|
||||
types_or: [c++, c]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: dd18dad857d6133e90bbe478f4f2f22ec0030269 # frozen: v22.1.5
|
||||
rev: f4d7745e17a28aad7eed2f4874ca8d1568c11c4c # frozen: v22.1.8
|
||||
hooks:
|
||||
- id: clang-format
|
||||
args: [--style=file]
|
||||
@@ -68,7 +68,7 @@ repos:
|
||||
- id: gersemi
|
||||
|
||||
- repo: https://github.com/rbubley/mirrors-prettier
|
||||
rev: 39e2973981e6d2f9b6c543b0086a2d2393abdc89 # frozen: v3.9.4
|
||||
rev: 9337a74165b178ae2c766f60bee7252a0f06f3e8 # frozen: v3.9.5
|
||||
hooks:
|
||||
- id: prettier
|
||||
args: [--end-of-line=auto]
|
||||
|
||||
38
bin/pre-commit/Dockerfile
Normal file
38
bin/pre-commit/Dockerfile
Normal file
@@ -0,0 +1,38 @@
|
||||
ARG BASE_IMAGE=ubuntu:26.04
|
||||
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"]
|
||||
ENTRYPOINT ["/bin/bash"]
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN <<EOF
|
||||
pkgs=()
|
||||
pkgs+=(curl) # Required to install nix.
|
||||
pkgs+=(git) # Required for prepare-runner.
|
||||
pkgs+=(libatomic1) # Required to run pre-commit provided `node`.
|
||||
pkgs+=(python3) # Python 3 interpreter.
|
||||
pkgs+=(python3-pip) # Package manager for Python applications.
|
||||
pkgs+=(xz-utils) # Required to install nix
|
||||
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends "${pkgs[@]}"
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
EOF
|
||||
|
||||
ARG PRE_COMMIT_VERSION=4.6.0
|
||||
RUN pip install --no-cache --break-system-packages \
|
||||
pre-commit==${PRE_COMMIT_VERSION}
|
||||
|
||||
RUN sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon --yes
|
||||
|
||||
# Add nix to PATH and set NIX environment variables,
|
||||
# so nix is available in all shells including non-interactive shells (e.g., GitHub Actions).
|
||||
ENV PATH="/nix/var/nix/profiles/default/bin:${PATH}"
|
||||
ENV NIX_PROFILES="/nix/var/nix/profiles/default"
|
||||
ENV NIX_SSL_CERT_FILE="/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"
|
||||
|
||||
# Verify nix installation
|
||||
RUN nix --version
|
||||
@@ -20,6 +20,22 @@ compiler.libcxx={{ detect_api.detect_libcxx(compiler, version, compiler_exe) }}
|
||||
{% endif %}
|
||||
|
||||
[conf]
|
||||
{# The Boost recipe builds with b2, which doesn't use Conan's toolchain files. #}
|
||||
{# Instead it hand-rolls the compiler for user-config.jam, #}
|
||||
{# and its fallback probes a version-suffixed binary (e.g. `g++-15`) before plain `g++`. #}
|
||||
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-15` suffix), #}
|
||||
{# so on a host that also has a system `g++-15` the probe escapes Nix #}
|
||||
{# and picks the system compiler, which is mismatched with the Nix libraries #}
|
||||
{# and breaks the build (e.g. Boost.Stacktrace link checks fail). #}
|
||||
{# Pinning the executables here short-circuits that probe so Boost (and the rest of the toolchain) #}
|
||||
{# resolve the same compiler. #}
|
||||
{# Not part of the package ID, so binaries stay shareable. #}
|
||||
{% if os != "Windows" %}
|
||||
{% set cc_exe = {"gcc": "gcc", "clang": "clang", "apple-clang": "clang"}.get(compiler) %}
|
||||
{% set cxx_exe = {"gcc": "g++", "clang": "clang++", "apple-clang": "clang++"}.get(compiler) %}
|
||||
tools.build:compiler_executables={'c':'{{ cc_exe }}','cpp':'{{ cxx_exe }}'}
|
||||
{% endif %}
|
||||
|
||||
{# By default, Conan tries to reuse binaries built with different cppstd versions. #}
|
||||
{# We want to avoid that to improve reproduceability, so we add the cppstd version to the package ID. #}
|
||||
{# More info: https://docs.conan.io/2/reference/extensions/binary_compatibility.html #}
|
||||
|
||||
@@ -260,6 +260,11 @@ public:
|
||||
unsigned
|
||||
pop() noexcept;
|
||||
|
||||
// if true, there are no recoverable digits in the guard, though there may be dropped digits
|
||||
// (xbit_)
|
||||
[[nodiscard]] bool
|
||||
unrecoverable() const noexcept;
|
||||
|
||||
// if true, there are no digits in the guard, including dropped digits (xbit_)
|
||||
[[nodiscard]] bool
|
||||
empty() const noexcept;
|
||||
@@ -277,6 +282,17 @@ public:
|
||||
void
|
||||
doDropDigit(T& mantissa, int& exponent) noexcept;
|
||||
|
||||
/**
|
||||
* Drop a digit from the mantissa, and increment the exponent, storing the dropped digit in
|
||||
* this Guard.
|
||||
*
|
||||
* If a drop will not do anything meaningful (there are no recoverable digits in the guard, and
|
||||
* the mantissa is 0), and if targetExponent > exponent, simply set exponent to targetExponent.
|
||||
*/
|
||||
template <class T>
|
||||
void
|
||||
doDropDigitWithTarget(T& mantissa, int& exponent, int const targetExponent) noexcept;
|
||||
|
||||
// Modify the result to the correctly rounded value
|
||||
template <UnsignedMantissa T>
|
||||
void
|
||||
@@ -374,10 +390,16 @@ Number::Guard::pop() noexcept
|
||||
return d;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Number::Guard::unrecoverable() const noexcept
|
||||
{
|
||||
return digits_ == 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Number::Guard::empty() const noexcept
|
||||
{
|
||||
return digits_ == 0 && !xbit_;
|
||||
return unrecoverable() && !xbit_;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -401,6 +423,22 @@ Number::Guard::doDropDigit<uint128_t>(uint128_t& mantissa, int& exponent) noexce
|
||||
++exponent;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
Number::Guard::doDropDigitWithTarget(T& mantissa, int& exponent, int const targetExponent) noexcept
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
targetExponent > exponent, "Number::Guard::doDropDigitWithTarget : something to do");
|
||||
if (mantissa == 0 && unrecoverable() && targetExponent > exponent)
|
||||
{
|
||||
// No number of dropped digits is going to change any of the operative parameters at this
|
||||
// point.
|
||||
exponent = targetExponent;
|
||||
return;
|
||||
}
|
||||
doDropDigit(mantissa, exponent);
|
||||
}
|
||||
|
||||
template <UnsignedMantissa T>
|
||||
void
|
||||
Number::Guard::pushOverflow(T mantissa)
|
||||
@@ -935,6 +973,8 @@ Number::operator+=(Number const& y)
|
||||
// 1. First, shrink the mantissa of shrinkM/shrinkE while shrinkM ends in 0.
|
||||
while (shrinkE < expandE && shrinkM % 10 == 0)
|
||||
{
|
||||
// Don't use doDropDigitWithTarget here, because the loop will stop before the
|
||||
// mantissa gets to 0.
|
||||
g.doDropDigit(shrinkM, shrinkE);
|
||||
}
|
||||
|
||||
@@ -952,7 +992,7 @@ Number::operator+=(Number const& y)
|
||||
// digits will be put into the Guard. This is the only step for non-Enabled330 modes.
|
||||
while (shrinkE < expandE)
|
||||
{
|
||||
g.doDropDigit(shrinkM, shrinkE);
|
||||
g.doDropDigitWithTarget(shrinkM, shrinkE, expandE);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <exception>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
@@ -176,61 +177,32 @@ struct STNumber_test : public beast::unit_test::Suite
|
||||
numberFromJson(sfNumber, std::to_string(kUMax)) ==
|
||||
STNumber(sfNumber, Number(kUMax, 0)));
|
||||
|
||||
auto const expectJsonThrows = [this](
|
||||
json::Value const& num, std::string const& expected) {
|
||||
try
|
||||
{
|
||||
numberFromJson(sfNumber, num);
|
||||
fail();
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Json: " << num.asString() << " got exception: " << e.what()
|
||||
<< ", expected: " << expected;
|
||||
BEAST_EXPECTS(std::string(e.what()) == expected, out.str());
|
||||
}
|
||||
};
|
||||
|
||||
// Obvious overflows tested here
|
||||
expectJsonThrows("1e2000000", "Number::normalize 2");
|
||||
expectJsonThrows("1e2000000000", "Number::normalize 2");
|
||||
|
||||
// Obvious non-numbers tested here
|
||||
try
|
||||
{
|
||||
auto _ = numberFromJson(sfNumber, "");
|
||||
BEAST_EXPECT(false);
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
std::string const expected = "'' is not a number";
|
||||
BEAST_EXPECT(e.what() == expected);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto _ = numberFromJson(sfNumber, "e");
|
||||
BEAST_EXPECT(false);
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
std::string const expected = "'e' is not a number";
|
||||
BEAST_EXPECT(e.what() == expected);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto _ = numberFromJson(sfNumber, "1e");
|
||||
BEAST_EXPECT(false);
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
std::string const expected = "'1e' is not a number";
|
||||
BEAST_EXPECT(e.what() == expected);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto _ = numberFromJson(sfNumber, "e2");
|
||||
BEAST_EXPECT(false);
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
std::string const expected = "'e2' is not a number";
|
||||
BEAST_EXPECT(e.what() == expected);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto _ = numberFromJson(sfNumber, json::Value());
|
||||
BEAST_EXPECT(false);
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
std::string const expected = "not a number";
|
||||
BEAST_EXPECT(e.what() == expected);
|
||||
}
|
||||
expectJsonThrows("", "'' is not a number");
|
||||
expectJsonThrows("e", "'e' is not a number");
|
||||
expectJsonThrows("1e", "'1e' is not a number");
|
||||
expectJsonThrows("e2", "'e2' is not a number");
|
||||
expectJsonThrows(json::Value(), "not a number");
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <xrpl/basics/Number.h>
|
||||
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/protocol/IOUAmount.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
@@ -183,6 +184,17 @@ TEST(NumberTest, limits)
|
||||
}
|
||||
EXPECT_TRUE(caught);
|
||||
|
||||
try
|
||||
{
|
||||
Number{1, 2000000, Number::Normalized{}};
|
||||
ADD_FAILURE();
|
||||
}
|
||||
catch (std::overflow_error const& e)
|
||||
{
|
||||
std::string const expected = "Number::normalize 2";
|
||||
EXPECT_EQ(e.what(), expected) << e.what();
|
||||
}
|
||||
|
||||
if (scale == MantissaRange::MantissaScale::Large330)
|
||||
{
|
||||
// Normalization with the other scales, including the older large mantissa scales, will
|
||||
@@ -403,6 +415,37 @@ TEST(NumberTest, add)
|
||||
}
|
||||
EXPECT_TRUE(caught);
|
||||
}
|
||||
|
||||
// Special case: Exponents at each end of the allowable range
|
||||
for (auto const round :
|
||||
{Number::RoundingMode::ToNearest,
|
||||
Number::RoundingMode::TowardsZero,
|
||||
Number::RoundingMode::Downward,
|
||||
Number::RoundingMode::Upward})
|
||||
{
|
||||
NumberRoundModeGuard const rg{round};
|
||||
auto const x =
|
||||
Number{Number::minMantissa(), Number::kMaxExponent, Number::Normalized{}};
|
||||
auto const y =
|
||||
Number{Number::minMantissa(), Number::kMinExponent, Number::Normalized{}};
|
||||
EXPECT_EQ(x.exponent(), Number::kMaxExponent);
|
||||
EXPECT_NE(x, beast::kZero);
|
||||
EXPECT_EQ(y.exponent(), Number::kMinExponent);
|
||||
EXPECT_NE(y, beast::kZero);
|
||||
auto const result = x + y;
|
||||
|
||||
if (round == Number::RoundingMode::Upward)
|
||||
{
|
||||
// Rounding upward will take that little x-bit and round result up to the next
|
||||
// representable value.
|
||||
EXPECT_NE(result, x);
|
||||
EXPECT_EQ(result, (Number{x.mantissa() + 1, x.exponent()}));
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_EQ(result, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user