Compare commits

..

7 Commits

Author SHA1 Message Date
Ed Hennis
e27b19d4d6 Merge branch 'develop' into ximinez/after-is-never-null 2026-06-05 18:48:46 -04:00
Ed Hennis
b364d8cf5e Merge branch 'develop' into ximinez/after-is-never-null 2026-06-04 13:32:27 -04:00
Ed Hennis
3f957d56ed Merge branch 'develop' into ximinez/after-is-never-null 2026-06-04 10:09:23 -04:00
Ed Hennis
231dc888aa Merge branch 'develop' into ximinez/after-is-never-null 2026-06-02 11:58:38 -04:00
Ed Hennis
3f52b71c89 Merge branch 'develop' into ximinez/after-is-never-null 2026-06-01 14:24:34 -04:00
Ed Hennis
4659ec0a7b Merge branch 'develop' into ximinez/after-is-never-null 2026-05-28 23:37:51 -04:00
Ed Hennis
88b81ee66e fix: Improve Invariant documentation to emphasize that "after" is never null
- Expand the description in InvariantChecker_PROTOTYPE::visitEntry.
- Add an explicit assertion in "XRPLNotCreated::visitEntry".
2026-05-28 23:34:13 -04:00
15 changed files with 69 additions and 108 deletions

View File

@@ -1,5 +1,5 @@
{
"image_tag": "sha-63ffdc3",
"image_tag": "sha-8abe82e",
"configs": {
"ubuntu": [
{
@@ -67,7 +67,7 @@
"compiler": ["gcc"],
"build_type": ["Release"],
"arch": ["amd64"],
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-63ffdc3"
"image": "debian:bookworm"
}
],
@@ -76,7 +76,7 @@
"compiler": ["gcc"],
"build_type": ["Release"],
"arch": ["amd64"],
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-63ffdc3"
"image": "registry.access.redhat.com/ubi9/ubi:latest"
}
]
}

View File

@@ -22,8 +22,7 @@ on:
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 }}
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:

View File

@@ -20,8 +20,7 @@ on:
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 }}
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:

View File

@@ -14,7 +14,7 @@ on:
jobs:
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
run-hooks:
uses: XRPLF/actions/.github/workflows/pre-commit.yml@312aaab296060ff89d7f798dcab59f019bea6e02
uses: XRPLF/actions/.github/workflows/pre-commit.yml@cba1f0891650baf1a9c88624dc2d72573be2eb81
with:
runs_on: ubuntu-latest
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-41ec7c1" }'

View File

@@ -41,13 +41,13 @@ env:
jobs:
build:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-63ffdc3
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-8abe82e
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
with:
enable_ccache: false

View File

@@ -113,7 +113,7 @@ jobs:
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
with:
enable_ccache: ${{ inputs.ccache_enabled }}
@@ -370,7 +370,7 @@ jobs:
- name: Upload coverage report
if: ${{ github.repository == 'XRPLF/rippled' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with:
disable_search: true
disable_telem: true

View File

@@ -29,14 +29,14 @@ jobs:
if: ${{ inputs.check_only_changed }}
permissions:
contents: read
uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@312aaab296060ff89d7f798dcab59f019bea6e02
uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@224f3c48d3014d082a1129237b8291ff0b0a331f
run-clang-tidy:
name: Run clang tidy
needs: [determine-files]
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-63ffdc3"
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-8abe82e"
permissions:
contents: read
issues: write
@@ -45,7 +45,7 @@ jobs:
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
with:
enable_ccache: false

View File

@@ -68,6 +68,31 @@ jobs:
timeout-minutes: 30
steps:
# Packaging runs in a vanilla distro image, so the tooling has to come
# from the distro's archive: debhelper for deb, rpm-build (and the
# systemd / find-debuginfo macros it depends on) for rpm. Run this
# before actions/checkout so the latter can use git (real history) for
# build_pkg.sh's SOURCE_DATE_EPOCH; otherwise it falls back to a tarball
# download and the timestamp comes from wall-clock time.
- name: Install packaging tooling (deb)
if: ${{ matrix.distro == 'debian' }}
run: |
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends \
ca-certificates \
debhelper \
git
- name: Install packaging tooling (rpm)
if: ${{ matrix.distro == 'rhel' }}
run: |
dnf install -y --setopt=install_weak_deps=False \
git \
rpm-build \
redhat-rpm-config \
systemd-rpm-macros
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

View File

@@ -40,7 +40,7 @@ defaults:
jobs:
upload:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-63ffdc3
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-8abe82e
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

View File

@@ -67,7 +67,7 @@ jobs:
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
with:
enable_ccache: false

View File

@@ -65,9 +65,13 @@ public:
/**
* @brief called for each ledger entry in the current transaction.
*
* @param isDelete true if the SLE is being deleted
* @param before ledger entry before modification by the transaction
* @param after ledger entry after modification by the transaction
* @param isDelete true if the SLE is being deleted.
* @param before ledger entry before modification by the
* transaction.
* @param after ledger entry after modification by the transaction.
* `after` IS NEVER NULL. `isDelete` is the only correct way to check for deletions.
* Check for null defensively, but do not make any logic decisions based on whether `after` is
* set, because it will always be set.
*/
void
visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after);

View File

@@ -11,8 +11,6 @@
#include <xrpl/protocol/Serializer.h>
#include <xrpl/protocol/UintTypes.h>
#include <boost/endian/conversion.hpp>
#include <cstddef>
#include <cstdint>
#include <cstring>
@@ -47,9 +45,6 @@ STIssue::STIssue(SerialIter& sit, SField const& name) : STBase{name}
{
MPTID mptID;
std::uint32_t sequence = sit.get32();
// Preserve the existing LE memcpy result on every host endian.
// Wire 04 03 02 01 becomes MPTID bytes 01 02 03 04 on both.
sequence = boost::endian::native_to_little(sequence);
static_assert(MPTID::size() == sizeof(sequence) + sizeof(currencyOrAccount));
memcpy(mptID.data(), &sequence, sizeof(sequence));
memcpy(
@@ -105,9 +100,6 @@ STIssue::add(Serializer& s) const
s.addBitString(noAccount());
std::uint32_t sequence = 0;
memcpy(&sequence, issue.getMptID().data(), sizeof(sequence));
// Preserve the existing LE ledger bytes on every host endian.
// MPTID bytes 01 02 03 04 become wire bytes 04 03 02 01 on both.
sequence = boost::endian::native_to_little(sequence);
s.add32(sequence);
});
}

View File

@@ -135,24 +135,28 @@ XRPNotCreated::visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref a
}
}
if (after)
if (!after)
{
switch (after->getType())
{
case ltACCOUNT_ROOT:
drops_ += (*after)[sfBalance].xrp().drops();
break;
case ltPAYCHAN:
if (!isDelete)
drops_ += ((*after)[sfAmount] - (*after)[sfBalance]).xrp().drops();
break;
case ltESCROW:
if (!isDelete && isXRP((*after)[sfAmount]))
drops_ += (*after)[sfAmount].xrp().drops();
break;
default:
break;
}
// LCOV_EXCL_START
UNREACHABLE("xrpl::XRPNotCreated::visitEntry : after can't be null");
return;
// LCOV_EXCL_STOP
}
switch (after->getType())
{
case ltACCOUNT_ROOT:
drops_ += (*after)[sfBalance].xrp().drops();
break;
case ltPAYCHAN:
if (!isDelete)
drops_ += ((*after)[sfAmount] - (*after)[sfBalance]).xrp().drops();
break;
case ltESCROW:
if (!isDelete && isXRP((*after)[sfAmount]))
drops_ += (*after)[sfAmount].xrp().drops();
break;
default:
break;
}
}

View File

@@ -3,19 +3,14 @@
#include <test/jtx/amount.h> // IWYU pragma: keep
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/strHex.h>
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STIssue.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/protocol/UintTypes.h>
#include <cstdint>
namespace xrpl::test {
class STIssue_test : public beast::unit_test::Suite
@@ -142,69 +137,12 @@ public:
"000000000000000000000000000000000000000000000002");
}
void
testMPTSerialization()
{
testcase("MPT serialization");
using namespace jtx;
Account const alice{"alice"};
struct Vector
{
std::uint32_t sequence;
std::uint32_t legacySequence;
};
// 0x01020304 pins canonical MPTID bytes 01 02 03 04 and
// preserved STIssue wire bytes 04 03 02 01 on BE and LE.
Vector const vectors[] = {
{.sequence = 0x00000001, .legacySequence = 0x01000000},
{.sequence = 0x01020304, .legacySequence = 0x04030201},
{.sequence = 0xa1b2c3d4, .legacySequence = 0xd4c3b2a1},
};
for (auto const& vector : vectors)
{
MPTID const mptID = makeMptID(vector.sequence, alice);
MPTIssue const issue{mptID};
STIssue const stIssue(sfAsset, Asset{issue});
Serializer actual;
stIssue.add(actual);
// STIssue preserves the existing little-endian validator ledger bytes.
Serializer expected;
expected.addBitString(alice.id());
expected.addBitString(noAccount());
{
std::array<unsigned char, 4> bytes;
auto const seq = boost::endian::native_to_little(vector.sequence);
memcpy(bytes.data(), &seq, 4);
expected.addRaw(bytes.data(), bytes.size());
}
BEAST_EXPECTS(strHex(actual) == strHex(expected), strHex(actual));
// Decoding the preserved wire format must recover the canonical MPTID.
SerialIter iter(expected.slice());
STIssue const decoded(iter, sfAsset);
BEAST_EXPECT(decoded.holds<MPTIssue>());
BEAST_EXPECT(decoded.value().get<MPTIssue>().getMptID() == mptID);
// A decoded ledger value must serialize back to the same bytes.
Serializer roundTrip;
decoded.add(roundTrip);
BEAST_EXPECTS(strHex(roundTrip) == strHex(expected), strHex(roundTrip));
}
}
void
run() override
{
// compliments other unit tests to ensure complete coverage
testConstructor();
testCompare();
testMPTSerialization();
}
};

View File

@@ -53,4 +53,4 @@ foreach(module IN LISTS test_modules)
)
endforeach()
gtest_discover_tests(xrpl_tests DISCOVERY_TIMEOUT 60)
gtest_discover_tests(xrpl_tests)