mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-12 05:06:48 +00:00
Compare commits
3 Commits
pratik/ote
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df395d6851 | ||
|
|
8e618d68cd | ||
|
|
cee157485e |
2
.github/scripts/strategy-matrix/linux.json
vendored
2
.github/scripts/strategy-matrix/linux.json
vendored
@@ -10,7 +10,7 @@
|
||||
|
||||
{
|
||||
"compiler": ["gcc", "clang"],
|
||||
"build_type": ["Debug"],
|
||||
"build_type": ["Debug", "Release"],
|
||||
"arch": ["amd64"],
|
||||
"sanitizers": ["address", "undefinedbehavior"]
|
||||
},
|
||||
|
||||
@@ -233,8 +233,10 @@ words:
|
||||
- pyenv
|
||||
- pyparsing
|
||||
- qalloc
|
||||
- qbsprofile
|
||||
- queuable
|
||||
- Raphson
|
||||
- rcflags
|
||||
- replayer
|
||||
- rerere
|
||||
- retriable
|
||||
|
||||
@@ -1,6 +1,26 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
inherit (import ./packages.nix { inherit pkgs; }) commonPackages;
|
||||
# conan is in the binary cache for Linux but not for Darwin, so on Darwin
|
||||
# it is always built from source — and its bundled test suite is unreliable
|
||||
# in the sandbox: `test_qbsprofile_rcflags` needs gcc (absent on Darwin, see
|
||||
# https://github.com/NixOS/nixpkgs/pull/528995) and the patch tests are
|
||||
# flaky from source. We only use conan as a build tool, so skip its tests on
|
||||
# Darwin. Scoped to the dev shell (not the CI env, which builds conan on
|
||||
# Linux from the cache). Drop once the fix reaches nixos-unstable and the
|
||||
# lock is bumped.
|
||||
pkgs_patched =
|
||||
if pkgs.stdenv.isDarwin then
|
||||
pkgs.extend (
|
||||
final: prev: {
|
||||
conan = prev.conan.overridePythonAttrs (_: {
|
||||
doCheck = false;
|
||||
});
|
||||
}
|
||||
)
|
||||
else
|
||||
pkgs;
|
||||
|
||||
inherit (import ./packages.nix { pkgs = pkgs_patched; }) commonPackages;
|
||||
|
||||
# Supported compiler versions
|
||||
gccVersion = pkgs.lib.range 13 15;
|
||||
|
||||
@@ -3,12 +3,21 @@
|
||||
#include <test/jtx/Oracle.h>
|
||||
#include <test/jtx/amount.h>
|
||||
|
||||
#include <xrpld/app/ledger/OpenLedger.h>
|
||||
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/unit_test/suite.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -312,11 +321,91 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testNullTxReadMeta()
|
||||
{
|
||||
testcase("Null txRead metadata");
|
||||
using namespace jtx;
|
||||
|
||||
// Verify that iteratePriceData handles a null txRead result
|
||||
// gracefully (returns early) rather than crashing with a
|
||||
// nullptr dereference. This simulates local data corruption
|
||||
// where a transaction referenced by sfPreviousTxnID is missing
|
||||
// from the ledger's transaction map.
|
||||
Env env(*this);
|
||||
auto const baseFee = static_cast<int>(env.current()->fees().base.drops());
|
||||
|
||||
Account const owner{"owner"};
|
||||
env.fund(XRP(1'000), owner);
|
||||
|
||||
// Create oracle with XRP/USD and XRP/EUR
|
||||
Oracle oracle(
|
||||
env,
|
||||
{.owner = owner,
|
||||
.series = {{"XRP", "USD", 740, 1}, {"XRP", "EUR", 840, 1}},
|
||||
.fee = baseFee});
|
||||
|
||||
// Update oracle to only have XRP/EUR, pushing XRP/USD into
|
||||
// history. iteratePriceData will need to read historical tx
|
||||
// metadata to find the XRP/USD price.
|
||||
oracle.set(UpdateArg{.series = {{"XRP", "EUR", 850, 1}}, .fee = baseFee});
|
||||
|
||||
OraclesData const oracles{{owner, oracle.documentID()}};
|
||||
|
||||
// Precondition: with an uncorrupted oracle, the historical
|
||||
// traversal must succeed and produce a price for XRP/USD.
|
||||
// This proves the test reaches iteratePriceData's history
|
||||
// path; without it, a future change that breaks the setup
|
||||
// could turn the post-corruption assertion into a vacuous
|
||||
// pass (objectNotFound is reachable from many unrelated
|
||||
// code paths).
|
||||
{
|
||||
auto const ret = Oracle::aggregatePrice(env, "XRP", "USD", oracles);
|
||||
BEAST_EXPECT(!ret.isMember(jss::error));
|
||||
BEAST_EXPECT(ret.isMember(jss::median));
|
||||
}
|
||||
|
||||
// Simulate data corruption: modify the oracle SLE in the open
|
||||
// ledger to have a bogus sfPreviousTxnID that doesn't exist in
|
||||
// any ledger. sfPreviousTxnLgrSeq still points to a valid closed
|
||||
// ledger, so getLedgerBySeq succeeds but txRead returns null.
|
||||
auto const oracleKeylet = keylet::oracle(owner, oracle.documentID());
|
||||
uint256 const bogusTxnID{0xABCABCAB};
|
||||
bool const modified = env.app().getOpenLedger().modify(
|
||||
[&oracleKeylet, &bogusTxnID](OpenView& view, beast::Journal) -> bool {
|
||||
auto const sle = view.read(oracleKeylet);
|
||||
if (!sle)
|
||||
return false;
|
||||
auto replacement = std::make_shared<SLE>(*sle, sle->key());
|
||||
replacement->setFieldH256(sfPreviousTxnID, bogusTxnID);
|
||||
view.rawReplace(replacement);
|
||||
return true;
|
||||
});
|
||||
|
||||
// Confirm the injection actually took effect: modify must
|
||||
// report success, and re-reading the SLE must show the
|
||||
// bogus hash. Otherwise the failure-mode assertion below
|
||||
// would not be exercising the null-txRead path at all.
|
||||
BEAST_EXPECT(modified);
|
||||
if (auto const sle = env.current()->read(oracleKeylet); BEAST_EXPECT(sle))
|
||||
BEAST_EXPECT(sle->getFieldH256(sfPreviousTxnID) == bogusTxnID);
|
||||
|
||||
// Query for XRP/USD using the "current" (open) ledger.
|
||||
// The oracle SLE now has a bogus sfPreviousTxnID. The current
|
||||
// oracle only has EUR, so iteratePriceData will try to read
|
||||
// history. txRead returns null for the bogus hash, and the
|
||||
// null check should cause a graceful early return instead of
|
||||
// a nullptr dereference.
|
||||
auto const ret = Oracle::aggregatePrice(env, "XRP", "USD", oracles);
|
||||
BEAST_EXPECT(ret[jss::error].asString() == "objectNotFound");
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testErrors();
|
||||
testRpc();
|
||||
testNullTxReadMeta();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user