Compare commits

..

28 Commits

Author SHA1 Message Date
Valentin Balaschenko
ab9644267d sync with develop 2025-11-03 15:11:11 +00:00
Bart
25c5e3b17f chore: Remove version number in find_dependency for OpenSSL (#5985)
We are already using OpenSSL 3.5.2. The version number in the `find_dependency` statement is optional, and belongs in `conanfile.py` anyway.
2025-11-03 13:53:19 +00:00
Jingchen
8eb233c2ea refactor: Modularize shamap and nodestore (#5668)
This change moves the shamap and nodestore from `xrpld` to `libxrpl`.
2025-10-31 22:25:16 +00:00
Jingchen
50fc93f742 refactor: Retire fixMasterKeyAsRegularKey amendment (#5959)
Amendments activated for more than 2 years can be retired. This change retires the fixMasterKeyAsRegularKey amendment.
2025-10-31 21:01:44 +00:00
Jingchen
ab45a8a737 refactor: Retire fixReducedOffersV1 amendment (#5972)
Amendments activated for more than 2 years can be retired. This change retires the fixReducedOffersV1 amendment.
2025-10-31 20:25:05 +00:00
Jingchen
dfafb141cc refactor: Retire fixAmendmentMajorityCalc amendment (#5961)
Amendments activated for more than 2 years can be retired. This change retires the fixAmendmentMajorityCalc amendment.
2025-10-31 20:01:12 +00:00
Mayukha Vadari
4e32d2ed98 refactor: Clean up TxMeta (#5845)
This change:
* Simplifies the `TxMeta` constructors - both were setting the same set of fields, and to make it harder for future bugs to arise and keep the code DRY, we can combine those into one helper function.
* Removes an unused constructor.
* Renames the variables to avoid Hungarian naming.
* Removes a bunch of now-unnecessary helper functions.
2025-10-31 19:29:30 +00:00
yinyiqian1
fa69918124 fix: Address permission delegation vulnerability (#5825)
This change introduces the `featurePermissionDelegationV1_1` amendment, which is designed to supersede both `featurePermissionDelegation` and `fixDelegateV1_1 amendments, which should be considered deprecated. The `checkPermission` function will now return `terNO_DELEGATE_PERMISSION` when a delegate transaction lacks the necessary permissions.
2025-10-31 15:01:06 -04:00
Ed Hennis
cbbb2b1be0 test: Count crashed test suites (#5924)
When outputting the unit test summary, this change counts crashed tests as failures.
2025-10-31 17:10:53 +00:00
Vlad
cf2d763fa1 refactor: Improve txset handling (#5951) 2025-10-31 16:10:14 +00:00
Bronek Kozicki
2dd1d682ac Remove directory size limit (#5935)
This change introduces the `fixDirectoryLimit` amendment to remove the directory pages limit. We found that the directory size limit is easier to hit than originally assumed, and there is no good reason to keep this limit, since the object reserve provides the necessary incentive to avoid creating unnecessary objects on the ledger.
2025-10-30 21:31:03 +00:00
Bronek Kozicki
4cb1084c02 fix: Change Credential sfSubjectNode to optional (#5936)
Field `sfSubjectNode` is not populated by `CredentialCreate` in self-issued credentials. Rather than fixup the Credentials already on the ledger, we can in this case safely change the object template for this field from `soeREQUIRED` to `soeOPTIONAL`.
2025-10-30 21:04:55 +00:00
Ed Hennis
8d1b3b3994 refactor: Add support for extra transaction signature validation (#5851)
- Restructures `STTx` signature checking code to be able to handle
  a `sigObject`, which may be the full transaction, or may be an object
  field containing a separate signature. Either way, the `sigObject` can
  be a single- or multi-sign signature.
- This is distinct from 550f90a75e (#5594), which changed the check in
  Transactor, which validates whether a given account is allowed to sign
  for the given transaction. This cryptographically checks the signature
  validity.
2025-10-30 15:39:56 -04:00
Pratik Mankawde
b39d7a6519 refactor: Retire fixQualityUpperBound amendment (#5960)
Amendments activated for more than 2 years can be retired. This change retires the fixQualityUpperBound amendment.
2025-10-30 18:47:47 +00:00
Pratik Mankawde
b0910e359e refactor: Retire fix1623 amendment (#5928)
Amendments activated for more than 2 years can be retired. This change retires the fix1623 amendment.
2025-10-30 17:33:08 +00:00
Pratik Mankawde
44e027e516 refactor: Retire fixTakerDryOfferRemoval amendment (#5958)
Amendments activated for more than 2 years can be retired. This change retires the fixTakerDryOfferRemoval amendment.
2025-10-30 11:27:01 -04:00
Bart
a10f42a3aa ci: Check whether test failures are caused by port exhaustion (#5938)
This change adds an extra step to the CI test job that outputs network info, which may allow us to confirm whether random test failures are caused by port exhaustion.
2025-10-30 13:19:51 +00:00
Ayaz Salikhov
efd4c1b95d chore: Use new prepare-runner (#5970)
See: XRPLF/actions#19.
2025-10-30 08:49:44 -04:00
Valentin Balaschenko
415a412d42 refactoring: removing uncesssary optimisation 2025-10-16 13:10:34 +01:00
Valentin Balaschenko
2cc54c7c3f Merge branch 'vlntb/mem-leak-ledger-history-3' of github.com:XRPLF/rippled into vlntb/mem-leak-ledger-history-3 2025-10-16 12:59:43 +01:00
Valentin Balaschenko
33e1a19a2e levelization 2025-10-16 12:57:53 +01:00
Valentin Balaschenko
12aa7c877a Merge branch 'develop' into vlntb/mem-leak-ledger-history-3 2025-10-16 12:47:39 +01:00
Valentin Balaschenko
bcf9a1ae38 debug traces 2025-10-16 12:36:42 +01:00
Valentin Balaschenko
f9c642c2b5 added unit-tests 2025-10-16 12:17:24 +01:00
Valentin Balaschenko
ba7b561a29 move container to lib 2025-10-15 18:00:40 +01:00
Valentin Balaschenko
265284249c encasulate lock inside container 2025-10-15 17:37:36 +01:00
Valentin Balaschenko
6050b84151 Merge branch 'develop' into vlntb/mem-leak-ledger-history-3 2025-10-15 16:31:22 +01:00
Valentin Balaschenko
9006bbda9d using clearLedgerCachePrior 2025-10-08 19:31:11 +01:00
232 changed files with 2326 additions and 17060 deletions

View File

@@ -17,7 +17,7 @@ Loop: xrpld.app xrpld.rpc
xrpld.rpc > xrpld.app xrpld.rpc > xrpld.app
Loop: xrpld.app xrpld.shamap Loop: xrpld.app xrpld.shamap
xrpld.app > xrpld.shamap xrpld.shamap ~= xrpld.app
Loop: xrpld.core xrpld.perflog Loop: xrpld.core xrpld.perflog
xrpld.perflog == xrpld.core xrpld.perflog == xrpld.core

View File

@@ -8,6 +8,10 @@ libxrpl.ledger > xrpl.ledger
libxrpl.ledger > xrpl.protocol libxrpl.ledger > xrpl.protocol
libxrpl.net > xrpl.basics libxrpl.net > xrpl.basics
libxrpl.net > xrpl.net libxrpl.net > xrpl.net
libxrpl.nodestore > xrpl.basics
libxrpl.nodestore > xrpl.json
libxrpl.nodestore > xrpl.nodestore
libxrpl.nodestore > xrpl.protocol
libxrpl.protocol > xrpl.basics libxrpl.protocol > xrpl.basics
libxrpl.protocol > xrpl.json libxrpl.protocol > xrpl.json
libxrpl.protocol > xrpl.protocol libxrpl.protocol > xrpl.protocol
@@ -18,6 +22,9 @@ libxrpl.server > xrpl.basics
libxrpl.server > xrpl.json libxrpl.server > xrpl.json
libxrpl.server > xrpl.protocol libxrpl.server > xrpl.protocol
libxrpl.server > xrpl.server libxrpl.server > xrpl.server
libxrpl.shamap > xrpl.basics
libxrpl.shamap > xrpl.protocol
libxrpl.shamap > xrpl.shamap
test.app > test.jtx test.app > test.jtx
test.app > test.rpc test.app > test.rpc
test.app > test.toplevel test.app > test.toplevel
@@ -25,11 +32,11 @@ test.app > test.unit_test
test.app > xrpl.basics test.app > xrpl.basics
test.app > xrpld.app test.app > xrpld.app
test.app > xrpld.core test.app > xrpld.core
test.app > xrpld.nodestore
test.app > xrpld.overlay test.app > xrpld.overlay
test.app > xrpld.rpc test.app > xrpld.rpc
test.app > xrpl.json test.app > xrpl.json
test.app > xrpl.ledger test.app > xrpl.ledger
test.app > xrpl.nodestore
test.app > xrpl.protocol test.app > xrpl.protocol
test.app > xrpl.resource test.app > xrpl.resource
test.basics > test.jtx test.basics > test.jtx
@@ -86,8 +93,7 @@ test.nodestore > test.toplevel
test.nodestore > test.unit_test test.nodestore > test.unit_test
test.nodestore > xrpl.basics test.nodestore > xrpl.basics
test.nodestore > xrpld.core test.nodestore > xrpld.core
test.nodestore > xrpld.nodestore test.nodestore > xrpl.nodestore
test.nodestore > xrpld.unity
test.overlay > test.jtx test.overlay > test.jtx
test.overlay > test.toplevel test.overlay > test.toplevel
test.overlay > test.unit_test test.overlay > test.unit_test
@@ -95,8 +101,8 @@ test.overlay > xrpl.basics
test.overlay > xrpld.app test.overlay > xrpld.app
test.overlay > xrpld.overlay test.overlay > xrpld.overlay
test.overlay > xrpld.peerfinder test.overlay > xrpld.peerfinder
test.overlay > xrpld.shamap
test.overlay > xrpl.protocol test.overlay > xrpl.protocol
test.overlay > xrpl.shamap
test.peerfinder > test.beast test.peerfinder > test.beast
test.peerfinder > test.unit_test test.peerfinder > test.unit_test
test.peerfinder > xrpl.basics test.peerfinder > xrpl.basics
@@ -131,19 +137,22 @@ test.server > xrpl.json
test.server > xrpl.server test.server > xrpl.server
test.shamap > test.unit_test test.shamap > test.unit_test
test.shamap > xrpl.basics test.shamap > xrpl.basics
test.shamap > xrpld.nodestore test.shamap > xrpl.nodestore
test.shamap > xrpld.shamap
test.shamap > xrpl.protocol test.shamap > xrpl.protocol
test.shamap > xrpl.shamap
test.toplevel > test.csf test.toplevel > test.csf
test.toplevel > xrpl.json test.toplevel > xrpl.json
test.unit_test > xrpl.basics test.unit_test > xrpl.basics
tests.libxrpl > xrpl.basics tests.libxrpl > xrpl.basics
tests.libxrpl > xrpl.ledger
tests.libxrpl > xrpl.json tests.libxrpl > xrpl.json
tests.libxrpl > xrpl.net tests.libxrpl > xrpl.net
xrpl.json > xrpl.basics xrpl.json > xrpl.basics
xrpl.ledger > xrpl.basics xrpl.ledger > xrpl.basics
xrpl.ledger > xrpl.protocol xrpl.ledger > xrpl.protocol
xrpl.net > xrpl.basics xrpl.net > xrpl.basics
xrpl.nodestore > xrpl.basics
xrpl.nodestore > xrpl.protocol
xrpl.protocol > xrpl.basics xrpl.protocol > xrpl.basics
xrpl.protocol > xrpl.json xrpl.protocol > xrpl.json
xrpl.resource > xrpl.basics xrpl.resource > xrpl.basics
@@ -152,17 +161,21 @@ xrpl.resource > xrpl.protocol
xrpl.server > xrpl.basics xrpl.server > xrpl.basics
xrpl.server > xrpl.json xrpl.server > xrpl.json
xrpl.server > xrpl.protocol xrpl.server > xrpl.protocol
xrpl.shamap > xrpl.basics
xrpl.shamap > xrpl.nodestore
xrpl.shamap > xrpl.protocol
xrpld.app > test.unit_test xrpld.app > test.unit_test
xrpld.app > xrpl.basics xrpld.app > xrpl.basics
xrpld.app > xrpld.conditions xrpld.app > xrpld.conditions
xrpld.app > xrpld.consensus xrpld.app > xrpld.consensus
xrpld.app > xrpld.nodestore
xrpld.app > xrpld.perflog xrpld.app > xrpld.perflog
xrpld.app > xrpl.json xrpld.app > xrpl.json
xrpld.app > xrpl.ledger xrpld.app > xrpl.ledger
xrpld.app > xrpl.net xrpld.app > xrpl.net
xrpld.app > xrpl.nodestore
xrpld.app > xrpl.protocol xrpld.app > xrpl.protocol
xrpld.app > xrpl.resource xrpld.app > xrpl.resource
xrpld.app > xrpl.shamap
xrpld.conditions > xrpl.basics xrpld.conditions > xrpl.basics
xrpld.conditions > xrpl.protocol xrpld.conditions > xrpl.protocol
xrpld.consensus > xrpl.basics xrpld.consensus > xrpl.basics
@@ -172,11 +185,6 @@ xrpld.core > xrpl.basics
xrpld.core > xrpl.json xrpld.core > xrpl.json
xrpld.core > xrpl.net xrpld.core > xrpl.net
xrpld.core > xrpl.protocol xrpld.core > xrpl.protocol
xrpld.nodestore > xrpl.basics
xrpld.nodestore > xrpld.core
xrpld.nodestore > xrpld.unity
xrpld.nodestore > xrpl.json
xrpld.nodestore > xrpl.protocol
xrpld.overlay > xrpl.basics xrpld.overlay > xrpl.basics
xrpld.overlay > xrpld.core xrpld.overlay > xrpld.core
xrpld.overlay > xrpld.peerfinder xrpld.overlay > xrpld.peerfinder
@@ -192,13 +200,11 @@ xrpld.perflog > xrpl.basics
xrpld.perflog > xrpl.json xrpld.perflog > xrpl.json
xrpld.rpc > xrpl.basics xrpld.rpc > xrpl.basics
xrpld.rpc > xrpld.core xrpld.rpc > xrpld.core
xrpld.rpc > xrpld.nodestore
xrpld.rpc > xrpl.json xrpld.rpc > xrpl.json
xrpld.rpc > xrpl.ledger xrpld.rpc > xrpl.ledger
xrpld.rpc > xrpl.net xrpld.rpc > xrpl.net
xrpld.rpc > xrpl.nodestore
xrpld.rpc > xrpl.protocol xrpld.rpc > xrpl.protocol
xrpld.rpc > xrpl.resource xrpld.rpc > xrpl.resource
xrpld.rpc > xrpl.server xrpld.rpc > xrpl.server
xrpld.shamap > xrpl.basics xrpld.shamap > xrpl.shamap
xrpld.shamap > xrpld.nodestore
xrpld.shamap > xrpl.protocol

View File

@@ -63,7 +63,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/.github/actions/prepare-runner@638e0dc11ea230f91bd26622fb542116bb5254d5 uses: XRPLF/actions/.github/actions/prepare-runner@99685816bb60a95a66852f212f382580e180df3a
with: with:
disable_ccache: false disable_ccache: false

View File

@@ -100,3 +100,12 @@ jobs:
"$test_file" "$test_file"
fi fi
done done
- name: Debug failure (Linux)
if: ${{ failure() && runner.os == 'Linux' && inputs.run_tests }}
shell: bash
run: |
echo "IPv4 local port range:"
cat /proc/sys/net/ipv4/ip_local_port_range
echo "Netstat:"
netstat -an

View File

@@ -66,7 +66,7 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- name: Prepare runner - name: Prepare runner
uses: XRPLF/actions/.github/actions/prepare-runner@638e0dc11ea230f91bd26622fb542116bb5254d5 uses: XRPLF/actions/.github/actions/prepare-runner@99685816bb60a95a66852f212f382580e180df3a
with: with:
disable_ccache: false disable_ccache: false

View File

@@ -45,7 +45,7 @@ if (static OR APPLE OR MSVC)
set (OPENSSL_USE_STATIC_LIBS ON) set (OPENSSL_USE_STATIC_LIBS ON)
endif () endif ()
set (OPENSSL_MSVC_STATIC_RT ON) set (OPENSSL_MSVC_STATIC_RT ON)
find_dependency (OpenSSL 1.1.1 REQUIRED) find_dependency (OpenSSL REQUIRED)
find_dependency (ZLIB) find_dependency (ZLIB)
find_dependency (date) find_dependency (date)
if (TARGET ZLIB::ZLIB) if (TARGET ZLIB::ZLIB)

View File

@@ -53,14 +53,15 @@ add_library(xrpl.imports.main INTERFACE)
target_link_libraries(xrpl.imports.main target_link_libraries(xrpl.imports.main
INTERFACE INTERFACE
LibArchive::LibArchive
OpenSSL::Crypto
Ripple::boost
Ripple::opts
Ripple::syslibs
absl::random_random absl::random_random
date::date date::date
ed25519::ed25519 ed25519::ed25519
LibArchive::LibArchive
OpenSSL::Crypto
Ripple::boost
Ripple::libs
Ripple::opts
Ripple::syslibs
secp256k1::secp256k1 secp256k1::secp256k1
xrpl.libpb xrpl.libpb
xxHash::xxhash xxHash::xxhash
@@ -111,6 +112,21 @@ target_link_libraries(xrpl.libxrpl.net PUBLIC
add_module(xrpl server) add_module(xrpl server)
target_link_libraries(xrpl.libxrpl.server PUBLIC xrpl.libxrpl.protocol) target_link_libraries(xrpl.libxrpl.server PUBLIC xrpl.libxrpl.protocol)
add_module(xrpl nodestore)
target_link_libraries(xrpl.libxrpl.nodestore PUBLIC
xrpl.libxrpl.basics
xrpl.libxrpl.json
xrpl.libxrpl.protocol
)
add_module(xrpl shamap)
target_link_libraries(xrpl.libxrpl.shamap PUBLIC
xrpl.libxrpl.basics
xrpl.libxrpl.crypto
xrpl.libxrpl.protocol
xrpl.libxrpl.nodestore
)
add_module(xrpl ledger) add_module(xrpl ledger)
target_link_libraries(xrpl.libxrpl.ledger PUBLIC target_link_libraries(xrpl.libxrpl.ledger PUBLIC
xrpl.libxrpl.basics xrpl.libxrpl.basics
@@ -136,6 +152,8 @@ target_link_modules(xrpl PUBLIC
protocol protocol
resource resource
server server
nodestore
shamap
net net
ledger ledger
) )

View File

@@ -8,20 +8,23 @@ install (
TARGETS TARGETS
common common
opts opts
ripple_syslibs
ripple_boost ripple_boost
ripple_libs
ripple_syslibs
xrpl.imports.main xrpl.imports.main
xrpl.libpb xrpl.libpb
xrpl.libxrpl
xrpl.libxrpl.basics xrpl.libxrpl.basics
xrpl.libxrpl.beast xrpl.libxrpl.beast
xrpl.libxrpl.crypto xrpl.libxrpl.crypto
xrpl.libxrpl.json xrpl.libxrpl.json
xrpl.libxrpl.ledger
xrpl.libxrpl.net
xrpl.libxrpl.nodestore
xrpl.libxrpl.protocol xrpl.libxrpl.protocol
xrpl.libxrpl.resource xrpl.libxrpl.resource
xrpl.libxrpl.ledger
xrpl.libxrpl.server xrpl.libxrpl.server
xrpl.libxrpl.net xrpl.libxrpl.shamap
xrpl.libxrpl
antithesis-sdk-cpp antithesis-sdk-cpp
EXPORT RippleExports EXPORT RippleExports
LIBRARY DESTINATION lib LIBRARY DESTINATION lib

View File

@@ -58,8 +58,6 @@ public:
explicit Number(rep mantissa, int exponent); explicit Number(rep mantissa, int exponent);
explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept; explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept;
static Number const zero;
constexpr rep constexpr rep
mantissa() const noexcept; mantissa() const noexcept;
constexpr int constexpr int

View File

@@ -170,9 +170,6 @@ public:
bool bool
retrieve(key_type const& key, T& data); retrieve(key_type const& key, T& data);
mutex_type&
peekMutex();
std::vector<key_type> std::vector<key_type>
getKeys() const; getKeys() const;

View File

@@ -668,29 +668,6 @@ TaggedCache<
return true; return true;
} }
template <
class Key,
class T,
bool IsKeyCache,
class SharedWeakUnionPointer,
class SharedPointerType,
class Hash,
class KeyEqual,
class Mutex>
inline auto
TaggedCache<
Key,
T,
IsKeyCache,
SharedWeakUnionPointer,
SharedPointerType,
Hash,
KeyEqual,
Mutex>::peekMutex() -> mutex_type&
{
return m_mutex;
}
template < template <
class Key, class Key,
class T, class T,

View File

@@ -32,7 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// The duplication is because Visual Studio 2019 cannot compile that header // The duplication is because Visual Studio 2019 cannot compile that header
// even with the option -Zc:__cplusplus added. // even with the option -Zc:__cplusplus added.
#define ALWAYS(cond, message, ...) assert((message) && (cond)) #define ALWAYS(cond, message, ...) assert((message) && (cond))
#define ALWAYS_OR_UNREACHABLE(cond, message) assert((message) && (cond)) #define ALWAYS_OR_UNREACHABLE(cond, message, ...) assert((message) && (cond))
#define SOMETIMES(cond, message, ...) #define SOMETIMES(cond, message, ...)
#define REACHABLE(message, ...) #define REACHABLE(message, ...)
#define UNREACHABLE(message, ...) assert((message) && false) #define UNREACHABLE(message, ...) assert((message) && false)

View File

@@ -395,9 +395,6 @@ public:
/// Return true if the object has a member named key. /// Return true if the object has a member named key.
bool bool
isMember(std::string const& key) const; isMember(std::string const& key) const;
/// Return true if the object has a member named key.
bool
isMember(StaticString const& key) const;
/// \brief Return a list of the member names. /// \brief Return a list of the member names.
/// ///

View File

@@ -387,45 +387,6 @@ public:
emptyDirDelete(Keylet const& directory); emptyDirDelete(Keylet const& directory);
}; };
namespace directory {
/** Helper functions for managing low-level directory operations.
These are not part of the ApplyView interface.
Don't use them unless you really, really know what you're doing.
Instead use dirAdd, dirInsert, etc.
*/
std::uint64_t
createRoot(
ApplyView& view,
Keylet const& directory,
uint256 const& key,
std::function<void(std::shared_ptr<SLE> const&)> const& describe);
auto
findPreviousPage(ApplyView& view, Keylet const& directory, SLE::ref start);
std::uint64_t
insertKey(
ApplyView& view,
SLE::ref node,
std::uint64_t page,
bool preserveOrder,
STVector256& indexes,
uint256 const& key);
std::optional<std::uint64_t>
insertPage(
ApplyView& view,
std::uint64_t page,
SLE::pointer node,
std::uint64_t nextPage,
SLE::ref next,
uint256 const& key,
Keylet const& directory,
std::function<void(std::shared_ptr<SLE> const&)> const& describe);
} // namespace directory
} // namespace ripple } // namespace ripple
#endif #endif

View File

@@ -0,0 +1,138 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_APP_LEDGER_INDEX_MAP_H_INCLUDED
#define RIPPLE_APP_LEDGER_INDEX_MAP_H_INCLUDED
#include <algorithm>
#include <mutex>
#include <unordered_map>
namespace ripple {
template <class Key, class Mapped>
class LedgerIndexMap
{
public:
LedgerIndexMap() = default;
explicit LedgerIndexMap(std::size_t reserve_capacity)
{
data_.reserve(reserve_capacity);
}
LedgerIndexMap(LedgerIndexMap const&) = delete;
LedgerIndexMap&
operator=(LedgerIndexMap const&) = delete;
LedgerIndexMap(LedgerIndexMap&&) = delete;
LedgerIndexMap&
operator=(LedgerIndexMap&&) = delete;
Mapped&
operator[](Key const& k)
{
std::lock_guard lock(mutex_);
return data_[k];
}
Mapped&
operator[](Key&& k)
{
std::lock_guard lock(mutex_);
return data_[std::move(k)];
}
[[nodiscard]] Mapped*
get(Key const& k)
{
std::lock_guard lock(mutex_);
auto it = data_.find(k);
return it == data_.end() ? nullptr : &it->second;
}
[[nodiscard]] Mapped const*
get(Key const& k) const
{
std::lock_guard lock(mutex_);
auto it = data_.find(k);
return it == data_.end() ? nullptr : &it->second;
}
template <class... Args>
Mapped&
put(Key const& k, Args&&... args)
{
std::lock_guard lock(mutex_);
auto [it, inserted] = data_.try_emplace(k, std::forward<Args>(args)...);
if (!inserted)
it->second = Mapped(std::forward<Args>(args)...);
return it->second;
}
bool
contains(Key const& k) const
{
std::lock_guard lock(mutex_);
return data_.find(k) != data_.end();
}
std::size_t
size() const noexcept
{
std::lock_guard lock(mutex_);
return data_.size();
}
bool
empty() const noexcept
{
std::lock_guard lock(mutex_);
return data_.empty();
}
void
reserve(std::size_t n)
{
std::lock_guard lock(mutex_);
data_.reserve(n);
}
void
rehash(std::size_t n)
{
std::lock_guard lock(mutex_);
data_.rehash(n);
}
std::size_t
eraseBefore(Key const& cutoff)
{
std::lock_guard lock(mutex_);
auto const before = data_.size();
std::erase_if(data_, [&](auto const& kv) { return kv.first < cutoff; });
return before - data_.size();
}
private:
std::unordered_map<Key, Mapped> data_;
mutable std::mutex mutex_;
};
} // namespace ripple
#endif // RIPPLE_APP_LEDGER_INDEX_MAP_H_INCLUDED

View File

@@ -242,80 +242,6 @@ isDeepFrozen(
Currency const& currency, Currency const& currency,
AccountID const& issuer); AccountID const& issuer);
[[nodiscard]] inline bool
isDeepFrozen(
ReadView const& view,
AccountID const& account,
Issue const& issue,
int = 0 /*ignored*/)
{
return isDeepFrozen(view, account, issue.currency, issue.account);
}
[[nodiscard]] inline bool
isDeepFrozen(
ReadView const& view,
AccountID const& account,
MPTIssue const& mptIssue,
int depth = 0)
{
// Unlike IOUs, frozen / locked MPTs are not allowed to send or receive
// funds, so checking "deep frozen" is the same as checking "frozen".
return isFrozen(view, account, mptIssue, depth);
}
/**
* isFrozen check is recursive for MPT shares in a vault, descending to
* assets in the vault, up to maxAssetCheckDepth recursion depth. This is
* purely defensive, as we currently do not allow such vaults to be created.
*/
[[nodiscard]] inline bool
isDeepFrozen(
ReadView const& view,
AccountID const& account,
Asset const& asset,
int depth = 0)
{
return std::visit(
[&](auto const& issue) {
return isDeepFrozen(view, account, issue, depth);
},
asset.value());
}
[[nodiscard]] inline TER
checkDeepFrozen(
ReadView const& view,
AccountID const& account,
Issue const& issue)
{
return isDeepFrozen(view, account, issue) ? (TER)tecFROZEN
: (TER)tesSUCCESS;
}
[[nodiscard]] inline TER
checkDeepFrozen(
ReadView const& view,
AccountID const& account,
MPTIssue const& mptIssue)
{
return isDeepFrozen(view, account, mptIssue) ? (TER)tecLOCKED
: (TER)tesSUCCESS;
}
[[nodiscard]] inline TER
checkDeepFrozen(
ReadView const& view,
AccountID const& account,
Asset const& asset)
{
return std::visit(
[&](auto const& issue) {
return checkDeepFrozen(view, account, issue);
},
asset.value());
}
[[nodiscard]] bool [[nodiscard]] bool
isLPTokenFrozen( isLPTokenFrozen(
ReadView const& view, ReadView const& view,
@@ -361,49 +287,6 @@ accountHolds(
AuthHandling zeroIfUnauthorized, AuthHandling zeroIfUnauthorized,
beast::Journal j); beast::Journal j);
// Returns the amount an account can spend total.
//
// These functions use accountHolds, but unlike accountHolds:
// * The account can go into debt.
// * If the account is the asset issuer the only limit is defined by the asset /
// issuance.
//
// <-- saAmount: amount of currency held by account. May be negative.
[[nodiscard]] STAmount
accountCanSend(
ReadView const& view,
AccountID const& account,
Currency const& currency,
AccountID const& issuer,
FreezeHandling zeroIfFrozen,
beast::Journal j);
[[nodiscard]] STAmount
accountCanSend(
ReadView const& view,
AccountID const& account,
Issue const& issue,
FreezeHandling zeroIfFrozen,
beast::Journal j);
[[nodiscard]] STAmount
accountCanSend(
ReadView const& view,
AccountID const& account,
MPTIssue const& mptIssue,
FreezeHandling zeroIfFrozen,
AuthHandling zeroIfUnauthorized,
beast::Journal j);
[[nodiscard]] STAmount
accountCanSend(
ReadView const& view,
AccountID const& account,
Asset const& asset,
FreezeHandling zeroIfFrozen,
AuthHandling zeroIfUnauthorized,
beast::Journal j);
// Returns the amount an account can spend of the currency type saDefault, or // Returns the amount an account can spend of the currency type saDefault, or
// returns saDefault if this account is the issuer of the currency in // returns saDefault if this account is the issuer of the currency in
// question. Should be used in favor of accountHolds when questioning how much // question. Should be used in favor of accountHolds when questioning how much
@@ -650,11 +533,7 @@ dirNext(
describeOwnerDir(AccountID const& account); describeOwnerDir(AccountID const& account);
[[nodiscard]] TER [[nodiscard]] TER
dirLink( dirLink(ApplyView& view, AccountID const& owner, std::shared_ptr<SLE>& object);
ApplyView& view,
AccountID const& owner,
std::shared_ptr<SLE>& object,
SF_UINT64 const& node = sfOwnerNode);
AccountID AccountID
pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey); pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey);
@@ -694,7 +573,7 @@ isPseudoAccount(std::shared_ptr<SLE const> sleAcct);
getPseudoAccountFields(); getPseudoAccountFields();
[[nodiscard]] inline bool [[nodiscard]] inline bool
isPseudoAccount(ReadView const& view, AccountID const& accountId) isPseudoAccount(ReadView const& view, AccountID accountId)
{ {
return isPseudoAccount(view.read(keylet::account(accountId))); return isPseudoAccount(view.read(keylet::account(accountId)));
} }
@@ -702,68 +581,6 @@ isPseudoAccount(ReadView const& view, AccountID const& accountId)
[[nodiscard]] TER [[nodiscard]] TER
canAddHolding(ReadView const& view, Asset const& asset); canAddHolding(ReadView const& view, Asset const& asset);
/** Validates that the destination SLE and tag are valid
- Checks that the SLE is not null.
- If the SLE requires a destination tag, checks that there is a tag.
*/
[[nodiscard]] TER
checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag);
/** Checks that can withdraw funds from an object to itself or a destination.
*
* The receiver may be either the submitting account (sfAccount) or a different
* destination account (sfDestination).
*
* - Checks that the receiver account exists.
* - If the receiver requires a destination tag, check that one exists, even
* if withdrawing to self.
* - If withdrawing to self, succeed.
* - If not, checks if the receiver requires deposit authorization, and if
* the sender has it.
*/
[[nodiscard]] TER
canWithdraw(
AccountID const& from,
ReadView const& view,
AccountID const& to,
SLE::const_ref toSle,
bool hasDestinationTag);
/** Checks that can withdraw funds from an object to itself or a destination.
*
* The receiver may be either the submitting account (sfAccount) or a different
* destination account (sfDestination).
*
* - Checks that the receiver account exists.
* - If the receiver requires a destination tag, check that one exists, even
* if withdrawing to self.
* - If withdrawing to self, succeed.
* - If not, checks if the receiver requires deposit authorization, and if
* the sender has it.
*/
[[nodiscard]] TER
canWithdraw(
AccountID const& from,
ReadView const& view,
AccountID const& to,
bool hasDestinationTag);
/** Checks that can withdraw funds from an object to itself or a destination.
*
* The receiver may be either the submitting account (sfAccount) or a different
* destination account (sfDestination).
*
* - Checks that the receiver account exists.
* - If the receiver requires a destination tag, check that one exists, even
* if withdrawing to self.
* - If withdrawing to self, succeed.
* - If not, checks if the receiver requires deposit authorization, and if
* the sender has it.
*/
[[nodiscard]] TER
canWithdraw(ReadView const& view, STTx const& tx);
/// Any transactors that call addEmptyHolding() in doApply must call /// Any transactors that call addEmptyHolding() in doApply must call
/// canAddHolding() in preflight with the same View and Asset /// canAddHolding() in preflight with the same View and Asset
[[nodiscard]] TER [[nodiscard]] TER
@@ -933,22 +750,6 @@ accountSend(
beast::Journal j, beast::Journal j,
WaiveTransferFee waiveFee = WaiveTransferFee::No); WaiveTransferFee waiveFee = WaiveTransferFee::No);
using MultiplePaymentDestinations = std::vector<std::pair<AccountID, Number>>;
/** Like accountSend, except one account is sending multiple payments (with the
* same asset!) simultaneously
*
* Calls static accountSendMultiIOU if saAmount represents Issue.
* Calls static accountSendMultiMPT if saAmount represents MPTIssue.
*/
[[nodiscard]] TER
accountSendMulti(
ApplyView& view,
AccountID const& senderID,
Asset const& asset,
MultiplePaymentDestinations const& receivers,
beast::Journal j,
WaiveTransferFee waiveFee = WaiveTransferFee::No);
[[nodiscard]] TER [[nodiscard]] TER
issueIOU( issueIOU(
ApplyView& view, ApplyView& view,

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_NODESTORE_BACKEND_H_INCLUDED #ifndef RIPPLE_NODESTORE_BACKEND_H_INCLUDED
#define RIPPLE_NODESTORE_BACKEND_H_INCLUDED #define RIPPLE_NODESTORE_BACKEND_H_INCLUDED
#include <xrpld/nodestore/Types.h> #include <xrpl/nodestore/Types.h>
#include <cstdint> #include <cstdint>

View File

@@ -20,13 +20,12 @@
#ifndef RIPPLE_NODESTORE_DATABASE_H_INCLUDED #ifndef RIPPLE_NODESTORE_DATABASE_H_INCLUDED
#define RIPPLE_NODESTORE_DATABASE_H_INCLUDED #define RIPPLE_NODESTORE_DATABASE_H_INCLUDED
#include <xrpld/nodestore/Backend.h>
#include <xrpld/nodestore/NodeObject.h>
#include <xrpld/nodestore/Scheduler.h>
#include <xrpl/basics/BasicConfig.h> #include <xrpl/basics/BasicConfig.h>
#include <xrpl/basics/Log.h> #include <xrpl/basics/Log.h>
#include <xrpl/basics/TaggedCache.ipp> #include <xrpl/basics/TaggedCache.ipp>
#include <xrpl/nodestore/Backend.h>
#include <xrpl/nodestore/NodeObject.h>
#include <xrpl/nodestore/Scheduler.h>
#include <xrpl/protocol/SystemParameters.h> #include <xrpl/protocol/SystemParameters.h>
#include <condition_variable> #include <condition_variable>

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_NODESTORE_DATABASEROTATING_H_INCLUDED #ifndef RIPPLE_NODESTORE_DATABASEROTATING_H_INCLUDED
#define RIPPLE_NODESTORE_DATABASEROTATING_H_INCLUDED #define RIPPLE_NODESTORE_DATABASEROTATING_H_INCLUDED
#include <xrpld/nodestore/Database.h> #include <xrpl/nodestore/Database.h>
namespace ripple { namespace ripple {
namespace NodeStore { namespace NodeStore {

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_NODESTORE_DUMMYSCHEDULER_H_INCLUDED #ifndef RIPPLE_NODESTORE_DUMMYSCHEDULER_H_INCLUDED
#define RIPPLE_NODESTORE_DUMMYSCHEDULER_H_INCLUDED #define RIPPLE_NODESTORE_DUMMYSCHEDULER_H_INCLUDED
#include <xrpld/nodestore/Scheduler.h> #include <xrpl/nodestore/Scheduler.h>
namespace ripple { namespace ripple {
namespace NodeStore { namespace NodeStore {

View File

@@ -20,11 +20,10 @@
#ifndef RIPPLE_NODESTORE_FACTORY_H_INCLUDED #ifndef RIPPLE_NODESTORE_FACTORY_H_INCLUDED
#define RIPPLE_NODESTORE_FACTORY_H_INCLUDED #define RIPPLE_NODESTORE_FACTORY_H_INCLUDED
#include <xrpld/nodestore/Backend.h>
#include <xrpld/nodestore/Scheduler.h>
#include <xrpl/basics/BasicConfig.h> #include <xrpl/basics/BasicConfig.h>
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <xrpl/nodestore/Backend.h>
#include <xrpl/nodestore/Scheduler.h>
#include <nudb/store.hpp> #include <nudb/store.hpp>

View File

@@ -20,8 +20,8 @@
#ifndef RIPPLE_NODESTORE_MANAGER_H_INCLUDED #ifndef RIPPLE_NODESTORE_MANAGER_H_INCLUDED
#define RIPPLE_NODESTORE_MANAGER_H_INCLUDED #define RIPPLE_NODESTORE_MANAGER_H_INCLUDED
#include <xrpld/nodestore/DatabaseRotating.h> #include <xrpl/nodestore/DatabaseRotating.h>
#include <xrpld/nodestore/Factory.h> #include <xrpl/nodestore/Factory.h>
namespace ripple { namespace ripple {

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_NODESTORE_SCHEDULER_H_INCLUDED #ifndef RIPPLE_NODESTORE_SCHEDULER_H_INCLUDED
#define RIPPLE_NODESTORE_SCHEDULER_H_INCLUDED #define RIPPLE_NODESTORE_SCHEDULER_H_INCLUDED
#include <xrpld/nodestore/Task.h> #include <xrpl/nodestore/Task.h>
#include <chrono> #include <chrono>

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_NODESTORE_TYPES_H_INCLUDED #ifndef RIPPLE_NODESTORE_TYPES_H_INCLUDED
#define RIPPLE_NODESTORE_TYPES_H_INCLUDED #define RIPPLE_NODESTORE_TYPES_H_INCLUDED
#include <xrpld/nodestore/NodeObject.h> #include <xrpl/nodestore/NodeObject.h>
#include <vector> #include <vector>

View File

@@ -20,9 +20,9 @@
#ifndef RIPPLE_NODESTORE_BATCHWRITER_H_INCLUDED #ifndef RIPPLE_NODESTORE_BATCHWRITER_H_INCLUDED
#define RIPPLE_NODESTORE_BATCHWRITER_H_INCLUDED #define RIPPLE_NODESTORE_BATCHWRITER_H_INCLUDED
#include <xrpld/nodestore/Scheduler.h> #include <xrpl/nodestore/Scheduler.h>
#include <xrpld/nodestore/Task.h> #include <xrpl/nodestore/Task.h>
#include <xrpld/nodestore/Types.h> #include <xrpl/nodestore/Types.h>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>

View File

@@ -20,10 +20,9 @@
#ifndef RIPPLE_NODESTORE_DATABASENODEIMP_H_INCLUDED #ifndef RIPPLE_NODESTORE_DATABASENODEIMP_H_INCLUDED
#define RIPPLE_NODESTORE_DATABASENODEIMP_H_INCLUDED #define RIPPLE_NODESTORE_DATABASENODEIMP_H_INCLUDED
#include <xrpld/nodestore/Database.h>
#include <xrpl/basics/TaggedCache.h> #include <xrpl/basics/TaggedCache.h>
#include <xrpl/basics/chrono.h> #include <xrpl/basics/chrono.h>
#include <xrpl/nodestore/Database.h>
namespace ripple { namespace ripple {
namespace NodeStore { namespace NodeStore {

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_NODESTORE_DATABASEROTATINGIMP_H_INCLUDED #ifndef RIPPLE_NODESTORE_DATABASEROTATINGIMP_H_INCLUDED
#define RIPPLE_NODESTORE_DATABASEROTATINGIMP_H_INCLUDED #define RIPPLE_NODESTORE_DATABASEROTATINGIMP_H_INCLUDED
#include <xrpld/nodestore/DatabaseRotating.h> #include <xrpl/nodestore/DatabaseRotating.h>
#include <mutex> #include <mutex>

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_NODESTORE_DECODEDBLOB_H_INCLUDED #ifndef RIPPLE_NODESTORE_DECODEDBLOB_H_INCLUDED
#define RIPPLE_NODESTORE_DECODEDBLOB_H_INCLUDED #define RIPPLE_NODESTORE_DECODEDBLOB_H_INCLUDED
#include <xrpld/nodestore/NodeObject.h> #include <xrpl/nodestore/NodeObject.h>
namespace ripple { namespace ripple {
namespace NodeStore { namespace NodeStore {

View File

@@ -20,9 +20,8 @@
#ifndef RIPPLE_NODESTORE_ENCODEDBLOB_H_INCLUDED #ifndef RIPPLE_NODESTORE_ENCODEDBLOB_H_INCLUDED
#define RIPPLE_NODESTORE_ENCODEDBLOB_H_INCLUDED #define RIPPLE_NODESTORE_ENCODEDBLOB_H_INCLUDED
#include <xrpld/nodestore/NodeObject.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/nodestore/NodeObject.h>
#include <boost/align/align_up.hpp> #include <boost/align/align_up.hpp>

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_NODESTORE_MANAGERIMP_H_INCLUDED #ifndef RIPPLE_NODESTORE_MANAGERIMP_H_INCLUDED
#define RIPPLE_NODESTORE_MANAGERIMP_H_INCLUDED #define RIPPLE_NODESTORE_MANAGERIMP_H_INCLUDED
#include <xrpld/nodestore/Manager.h> #include <xrpl/nodestore/Manager.h>
namespace ripple { namespace ripple {
@@ -39,7 +39,7 @@ public:
static void static void
missing_backend(); missing_backend();
ManagerImp() = default; ManagerImp();
~ManagerImp() = default; ~ManagerImp() = default;

View File

@@ -23,11 +23,10 @@
// Disable lz4 deprecation warning due to incompatibility with clang attributes // Disable lz4 deprecation warning due to incompatibility with clang attributes
#define LZ4_DISABLE_DEPRECATE_WARNINGS #define LZ4_DISABLE_DEPRECATE_WARNINGS
#include <xrpld/nodestore/NodeObject.h>
#include <xrpld/nodestore/detail/varint.h>
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#include <xrpl/basics/safe_cast.h> #include <xrpl/basics/safe_cast.h>
#include <xrpl/nodestore/NodeObject.h>
#include <xrpl/nodestore/detail/varint.h>
#include <xrpl/protocol/HashPrefix.h> #include <xrpl/protocol/HashPrefix.h>
#include <nudb/detail/field.hpp> #include <nudb/detail/field.hpp>

View File

@@ -103,12 +103,6 @@ public:
return holds<Issue>() && get<Issue>().native(); return holds<Issue>() && get<Issue>().native();
} }
bool
integral() const
{
return !holds<Issue>() || get<Issue>().native();
}
friend constexpr bool friend constexpr bool
operator==(Asset const& lhs, Asset const& rhs); operator==(Asset const& lhs, Asset const& rhs);

View File

@@ -346,24 +346,6 @@ vault(uint256 const& vaultKey)
return {ltVAULT, vaultKey}; return {ltVAULT, vaultKey};
} }
Keylet
loanbroker(AccountID const& owner, std::uint32_t seq) noexcept;
inline Keylet
loanbroker(uint256 const& key)
{
return {ltLOAN_BROKER, key};
}
Keylet
loan(uint256 const& loanBrokerID, std::uint32_t loanSeq) noexcept;
inline Keylet
loan(uint256 const& key)
{
return {ltLOAN, key};
}
Keylet Keylet
permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept; permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept;

View File

@@ -205,11 +205,6 @@ enum LedgerSpecificFlags {
// ltVAULT // ltVAULT
lsfVaultPrivate = 0x00010000, lsfVaultPrivate = 0x00010000,
// ltLOAN
lsfLoanDefault = 0x00010000,
lsfLoanImpaired = 0x00020000,
lsfLoanOverpayment = 0x00040000, // True, loan allows overpayments
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -22,7 +22,6 @@
#include <xrpl/basics/ByteUtilities.h> #include <xrpl/basics/ByteUtilities.h>
#include <xrpl/basics/base_uint.h> #include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/Units.h>
#include <cstdint> #include <cstdint>
@@ -56,7 +55,10 @@ std::size_t constexpr oversizeMetaDataCap = 5200;
/** The maximum number of entries per directory page */ /** The maximum number of entries per directory page */
std::size_t constexpr dirNodeMaxEntries = 32; std::size_t constexpr dirNodeMaxEntries = 32;
/** The maximum number of pages allowed in a directory */ /** The maximum number of pages allowed in a directory
Made obsolete by fixDirectoryLimit amendment.
*/
std::uint64_t constexpr dirNodeMaxPages = 262144; std::uint64_t constexpr dirNodeMaxPages = 262144;
/** The maximum number of items in an NFT page */ /** The maximum number of items in an NFT page */
@@ -82,136 +84,6 @@ std::size_t constexpr maxDeletableTokenOfferEntries = 500;
*/ */
std::uint16_t constexpr maxTransferFee = 50000; std::uint16_t constexpr maxTransferFee = 50000;
/** There are 10,000 basis points (bips) in 100%.
*
* Basis points represent 0.01%.
*
* Given a value X, to find the amount for B bps,
* use X * B / bipsPerUnity
*
* Example: If a loan broker has 999 XRP of debt, and must maintain 1,000 bps of
* that debt as cover (10%), then the minimum cover amount is 999,000,000 drops
* * 1000 / bipsPerUnity = 99,900,00 drops or 99.9 XRP.
*
* Given a percentage P, to find the number of bps that percentage represents,
* use P * bipsPerUnity.
*
* Example: 50% is 0.50 * bipsPerUnity = 5,000 bps.
*/
Bips32 constexpr bipsPerUnity(100 * 100);
TenthBips32 constexpr tenthBipsPerUnity(bipsPerUnity.value() * 10);
constexpr Bips32
percentageToBips(std::uint32_t percentage)
{
return Bips32(percentage * bipsPerUnity.value() / 100);
}
constexpr TenthBips32
percentageToTenthBips(std::uint32_t percentage)
{
return TenthBips32(percentage * tenthBipsPerUnity.value() / 100);
}
template <typename T, class TBips>
constexpr T
bipsOfValue(T value, Bips<TBips> bips)
{
return value * bips.value() / bipsPerUnity.value();
}
template <typename T, class TBips>
constexpr T
tenthBipsOfValue(T value, TenthBips<TBips> bips)
{
return value * bips.value() / tenthBipsPerUnity.value();
}
/** The maximum management fee rate allowed by a loan broker in 1/10 bips.
Valid values are between 0 and 10% inclusive.
*/
TenthBips16 constexpr maxManagementFeeRate(
unsafe_cast<std::uint16_t>(percentageToTenthBips(10).value()));
static_assert(maxManagementFeeRate == TenthBips16(std::uint16_t(10'000u)));
/** The maximum coverage rate required of a loan broker in 1/10 bips.
Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxCoverRate = percentageToTenthBips(100);
static_assert(maxCoverRate == TenthBips32(100'000u));
/** The maximum overpayment fee on a loan in 1/10 bips.
*
Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxOverpaymentFee = percentageToTenthBips(100);
static_assert(maxOverpaymentFee == TenthBips32(100'000u));
/** Annualized interest rate of the Loan in 1/10 bips.
*
* Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxInterestRate = percentageToTenthBips(100);
static_assert(maxInterestRate == TenthBips32(100'000u));
/** The maximum premium added to the interest rate for late payments on a loan
* in 1/10 bips.
*
* Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxLateInterestRate = percentageToTenthBips(100);
static_assert(maxLateInterestRate == TenthBips32(100'000u));
/** The maximum close interest rate charged for repaying a loan early in 1/10
* bips.
*
* Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxCloseInterestRate = percentageToTenthBips(100);
static_assert(maxCloseInterestRate == TenthBips32(100'000u));
/** The maximum overpayment interest rate charged on loan overpayments in 1/10
* bips.
*
* Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxOverpaymentInterestRate = percentageToTenthBips(100);
static_assert(maxOverpaymentInterestRate == TenthBips32(100'000u));
/** LoanPay transaction cost will be one base fee per X combined payments
*
* The number of payments is estimated based on the Amount paid and the Loan's
* Fixed Payment size. Overpayments (indicated with the tfLoanOverpayment flag)
* count as one more payment.
*
* This number was chosen arbitrarily, but should not be changed once released
* without an amendment
*/
static constexpr int loanPaymentsPerFeeIncrement = 5;
/** Maximum number of combined payments that a LoanPay transaction will process
*
* This limit is enforced during the loan payment process, and thus is not
* estimated. If the limit is hit, no further payments or overpayments will be
* processed, no matter how much of the transation Amount is left, but the
* transaction will succeed with the payments that have been processed up to
* that point.
*
* This limit is independent of loanPaymentsPerFeeIncrement, so a transaction
* could potentially be charged for many more payments than actually get
* processed. Users should take care not to submit a transaction paying more
* than loanMaximumPaymentsPerTransaction * Loan.PeriodicPayment. Because
* overpayments are charged as a payment, if submitting
* loanMaximumPaymentsPerTransaction * Loan.PeriodicPayment, users should not
* set the tfLoanOverpayment flag.
*
* Even though they're independent, loanMaximumPaymentsPerTransaction should be
* a multiple of loanPaymentsPerFeeIncrement.
*
* This number was chosen arbitrarily, but should not be changed once released
* without an amendment
*/
static constexpr int loanMaximumPaymentsPerTransaction = 100;
/** The maximum length of a URI inside an NFT */ /** The maximum length of a URI inside an NFT */
std::size_t constexpr maxTokenURILength = 256; std::size_t constexpr maxTokenURILength = 256;

View File

@@ -139,8 +139,8 @@ field_code(int id, int index)
SFields are created at compile time. SFields are created at compile time.
Each SField, once constructed, lives until program termination, and there Each SField, once constructed, lives until program termination, and there
is only one instance per fieldType/fieldValue pair which serves the is only one instance per fieldType/fieldValue pair which serves the entire
entire application. application.
*/ */
class SField class SField
{ {

View File

@@ -66,15 +66,15 @@ public:
static int const cMaxOffset = 80; static int const cMaxOffset = 80;
// Maximum native value supported by the code // Maximum native value supported by the code
static std::uint64_t const cMinValue = 1'000'000'000'000'000ull; static std::uint64_t const cMinValue = 1000000000000000ull;
static std::uint64_t const cMaxValue = 9'999'999'999'999'999ull; static std::uint64_t const cMaxValue = 9999999999999999ull;
static std::uint64_t const cMaxNative = 9'000'000'000'000'000'000ull; static std::uint64_t const cMaxNative = 9000000000000000000ull;
// Max native value on network. // Max native value on network.
static std::uint64_t const cMaxNativeN = 100'000'000'000'000'000ull; static std::uint64_t const cMaxNativeN = 100000000000000000ull;
static std::uint64_t const cIssuedCurrency = 0x8'000'000'000'000'000ull; static std::uint64_t const cIssuedCurrency = 0x8000000000000000ull;
static std::uint64_t const cPositive = 0x4'000'000'000'000'000ull; static std::uint64_t const cPositive = 0x4000000000000000ull;
static std::uint64_t const cMPToken = 0x2'000'000'000'000'000ull; static std::uint64_t const cMPToken = 0x2000000000000000ull;
static std::uint64_t const cValueMask = ~(cPositive | cMPToken); static std::uint64_t const cValueMask = ~(cPositive | cMPToken);
static std::uint64_t const uRateOne; static std::uint64_t const uRateOne;
@@ -174,9 +174,6 @@ public:
int int
exponent() const noexcept; exponent() const noexcept;
bool
integral() const noexcept;
bool bool
native() const noexcept; native() const noexcept;
@@ -457,12 +454,6 @@ STAmount::exponent() const noexcept
return mOffset; return mOffset;
} }
inline bool
STAmount::integral() const noexcept
{
return mAsset.integral();
}
inline bool inline bool
STAmount::native() const noexcept STAmount::native() const noexcept
{ {
@@ -704,53 +695,6 @@ divRoundStrict(
std::uint64_t std::uint64_t
getRate(STAmount const& offerOut, STAmount const& offerIn); getRate(STAmount const& offerOut, STAmount const& offerIn);
/** Round an arbitrary precision Amount to the precision of an STAmount that has
* a given exponent.
*
* This is used to ensure that calculations involving IOU amounts do not collect
* dust beyond the precision of the reference value.
*
* @param value The value to be rounded
* @param scale An exponent value to establish the precision limit of
* `value`. Should be larger than `value.exponent()`.
* @param rounding Optional Number rounding mode
*
*/
STAmount
roundToScale(
STAmount value,
std::int32_t scale,
Number::rounding_mode rounding = Number::getround());
/** Round an arbitrary precision Number to the precision of a given Asset.
*
* This is used to ensure that calculations do not collect dust beyond the
* precision of the reference value for IOUs, or fractional amounts for the
* integral types XRP and MPT.
*
* @param asset The relevant asset
* @param value The value to be rounded
* @param scale Only relevant to IOU assets. An exponent value to establish the
* precision limit of `value`. Should be larger than `value.exponent()`.
* @param rounding Optional Number rounding mode
*/
template <AssetType A>
Number
roundToAsset(
A const& asset,
Number const& value,
std::int32_t scale,
Number::rounding_mode rounding = Number::getround())
{
NumberRoundModeGuard mg(rounding);
STAmount const ret{asset, value};
if (ret.integral())
return ret;
// Not that the ctor will round integral types (XRP, MPT) via canonicalize,
// so no extra work is needed for those.
return roundToScale(ret, scale);
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
inline bool inline bool

View File

@@ -524,26 +524,7 @@ protected:
// Constraint += and -= ValueProxy operators // Constraint += and -= ValueProxy operators
// to value types that support arithmetic operations // to value types that support arithmetic operations
template <typename U> template <typename U>
concept IsArithmeticNumber = std::is_arithmetic_v<U> || concept IsArithmetic = std::is_arithmetic_v<U> || std::is_same_v<U, STAmount>;
std::is_same_v<U, Number> || std::is_same_v<U, STAmount>;
template <
typename U,
typename Value = typename U::value_type,
typename Unit = typename U::unit_type>
concept IsArithmeticValueUnit =
std::is_same_v<U, unit::ValueUnit<Unit, Value>> &&
IsArithmeticNumber<Value> && std::is_class_v<Unit>;
template <typename U, typename Value = typename U::value_type>
concept IsArithmeticST = !IsArithmeticValueUnit<U> && IsArithmeticNumber<Value>;
template <typename U>
concept IsArithmetic =
IsArithmeticNumber<U> || IsArithmeticST<U> || IsArithmeticValueUnit<U>;
template <class T, class U>
concept Addable = requires(T t, U u) { t = t + u; };
template <typename T, typename U>
concept IsArithmeticCompatible =
IsArithmetic<typename T::value_type> && Addable<typename T::value_type, U>;
template <class T> template <class T>
class STObject::ValueProxy : public Proxy<T> class STObject::ValueProxy : public Proxy<T>
@@ -563,12 +544,10 @@ public:
// Convenience operators for value types supporting // Convenience operators for value types supporting
// arithmetic operations // arithmetic operations
template <IsArithmetic U> template <IsArithmetic U>
requires IsArithmeticCompatible<T, U>
ValueProxy& ValueProxy&
operator+=(U const& u); operator+=(U const& u);
template <IsArithmetic U> template <IsArithmetic U>
requires IsArithmeticCompatible<T, U>
ValueProxy& ValueProxy&
operator-=(U const& u); operator-=(U const& u);
@@ -804,7 +783,6 @@ STObject::ValueProxy<T>::operator=(U&& u)
template <typename T> template <typename T>
template <IsArithmetic U> template <IsArithmetic U>
requires IsArithmeticCompatible<T, U>
STObject::ValueProxy<T>& STObject::ValueProxy<T>&
STObject::ValueProxy<T>::operator+=(U const& u) STObject::ValueProxy<T>::operator+=(U const& u)
{ {
@@ -814,7 +792,6 @@ STObject::ValueProxy<T>::operator+=(U const& u)
template <class T> template <class T>
template <IsArithmetic U> template <IsArithmetic U>
requires IsArithmeticCompatible<T, U>
STObject::ValueProxy<T>& STObject::ValueProxy<T>&
STObject::ValueProxy<T>::operator-=(U const& u) STObject::ValueProxy<T>::operator-=(U const& u)
{ {

View File

@@ -73,14 +73,8 @@ static constexpr std::uint32_t XRP_LEDGER_EARLIEST_SEQ{32570u};
* used in asserts and tests. */ * used in asserts and tests. */
static constexpr std::uint32_t XRP_LEDGER_EARLIEST_FEES{562177u}; static constexpr std::uint32_t XRP_LEDGER_EARLIEST_FEES{562177u};
/** The minimum amount of support an amendment should have. /** The minimum amount of support an amendment should have. */
constexpr std::ratio<80, 100> amendmentMajorityCalcThreshold;
@note This value is used by legacy code and will become obsolete
once the fixAmendmentMajorityCalc amendment activates.
*/
constexpr std::ratio<204, 256> preFixAmendmentMajorityCalcThreshold;
constexpr std::ratio<80, 100> postFixAmendmentMajorityCalcThreshold;
/** The minimum amount of time an amendment must hold a majority */ /** The minimum amount of time an amendment must hold a majority */
constexpr std::chrono::seconds const defaultAmendmentMajorityTime = weeks{2}; constexpr std::chrono::seconds const defaultAmendmentMajorityTime = weeks{2};

View File

@@ -225,8 +225,9 @@ enum TERcodes : TERUnderlyingType {
terQUEUED, // Transaction is being held in TxQ until fee drops terQUEUED, // Transaction is being held in TxQ until fee drops
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
terNO_AMM, // AMM doesn't exist for the asset pair terNO_AMM, // AMM doesn't exist for the asset pair
terADDRESS_COLLISION, // Failed to allocate AccountID when trying to terADDRESS_COLLISION, // Failed to allocate AccountID when trying to
// create a pseudo-account // create a pseudo-account
terNO_DELEGATE_PERMISSION, // Delegate does not have permission
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -361,6 +362,9 @@ enum TECcodes : TERUnderlyingType {
tecLIMIT_EXCEEDED = 195, tecLIMIT_EXCEEDED = 195,
tecPSEUDO_ACCOUNT = 196, tecPSEUDO_ACCOUNT = 196,
tecPRECISION_LOSS = 197, tecPRECISION_LOSS = 197,
// DEPRECATED: This error code tecNO_DELEGATE_PERMISSION is reserved for
// backward compatibility with historical data on non-prod networks, can be
// reclaimed after those networks reset.
tecNO_DELEGATE_PERMISSION = 198, tecNO_DELEGATE_PERMISSION = 198,
}; };

View File

@@ -285,25 +285,6 @@ constexpr std::uint32_t tfIndependent = 0x00080000;
constexpr std::uint32_t const tfBatchMask = constexpr std::uint32_t const tfBatchMask =
~(tfUniversal | tfAllOrNothing | tfOnlyOne | tfUntilFailure | tfIndependent) | tfInnerBatchTxn; ~(tfUniversal | tfAllOrNothing | tfOnlyOne | tfUntilFailure | tfIndependent) | tfInnerBatchTxn;
// LoanSet and LoanPay flags:
// LoanSet: True, indicates the loan supports overpayments
// LoanPay: True, indicates any excess in this payment can be used
// as an overpayment. False, no overpayments will be taken.
constexpr std::uint32_t const tfLoanOverpayment = 0x00010000;
// LoanPay exclusive flags:
// tfLoanFullPayment: True, indicates that the payment is
constexpr std::uint32_t const tfLoanFullPayment = 0x00020000;
constexpr std::uint32_t const tfLoanSetMask = ~(tfUniversal |
tfLoanOverpayment);
constexpr std::uint32_t const tfLoanPayMask = ~(tfUniversal |
tfLoanOverpayment | tfLoanFullPayment);
// LoanManage flags:
constexpr std::uint32_t const tfLoanDefault = 0x00010000;
constexpr std::uint32_t const tfLoanImpair = 0x00020000;
constexpr std::uint32_t const tfLoanUnimpair = 0x00040000;
constexpr std::uint32_t const tfLoanManageMask = ~(tfUniversal | tfLoanDefault | tfLoanImpair | tfLoanUnimpair);
// clang-format on // clang-format on
} // namespace ripple } // namespace ripple

View File

@@ -33,51 +33,35 @@ namespace ripple {
class TxMeta class TxMeta
{ {
private:
struct CtorHelper
{
explicit CtorHelper() = default;
};
template <class T>
TxMeta(
uint256 const& txID,
std::uint32_t ledger,
T const& data,
CtorHelper);
public: public:
TxMeta( TxMeta(uint256 const& transactionID, std::uint32_t ledger);
uint256 const& transactionID,
std::uint32_t ledger,
std::optional<uint256> parentBatchId = std::nullopt);
TxMeta(uint256 const& txID, std::uint32_t ledger, Blob const&); TxMeta(uint256 const& txID, std::uint32_t ledger, Blob const&);
TxMeta(uint256 const& txID, std::uint32_t ledger, std::string const&);
TxMeta(uint256 const& txID, std::uint32_t ledger, STObject const&); TxMeta(uint256 const& txID, std::uint32_t ledger, STObject const&);
uint256 const& uint256 const&
getTxID() const getTxID() const
{ {
return mTransactionID; return transactionID_;
} }
std::uint32_t std::uint32_t
getLgrSeq() const getLgrSeq() const
{ {
return mLedger; return ledgerSeq_;
} }
int int
getResult() const getResult() const
{ {
return mResult; return result_;
} }
TER TER
getResultTER() const getResultTER() const
{ {
return TER::fromInt(mResult); return TER::fromInt(result_);
} }
std::uint32_t std::uint32_t
getIndex() const getIndex() const
{ {
return mIndex; return index_;
} }
void void
@@ -104,66 +88,52 @@ public:
STArray& STArray&
getNodes() getNodes()
{ {
return (mNodes); return nodes_;
} }
STArray const& STArray const&
getNodes() const getNodes() const
{ {
return (mNodes); return nodes_;
} }
void void
setDeliveredAmount(STAmount const& delivered) setAdditionalFields(STObject const& obj)
{ {
mDelivered = delivered; if (obj.isFieldPresent(sfDeliveredAmount))
deliveredAmount_ = obj.getFieldAmount(sfDeliveredAmount);
if (obj.isFieldPresent(sfParentBatchID))
parentBatchID_ = obj.getFieldH256(sfParentBatchID);
} }
STAmount std::optional<STAmount> const&
getDeliveredAmount() const getDeliveredAmount() const
{ {
XRPL_ASSERT( return deliveredAmount_;
hasDeliveredAmount(),
"ripple::TxMeta::getDeliveredAmount : non-null delivered amount");
return *mDelivered;
}
bool
hasDeliveredAmount() const
{
return static_cast<bool>(mDelivered);
} }
void void
setParentBatchId(uint256 const& parentBatchId) setDeliveredAmount(std::optional<STAmount> const& amount)
{ {
mParentBatchId = parentBatchId; deliveredAmount_ = amount;
} }
uint256 void
getParentBatchId() const setParentBatchID(std::optional<uint256> const& id)
{ {
XRPL_ASSERT( parentBatchID_ = id;
hasParentBatchId(),
"ripple::TxMeta::getParentBatchId : non-null batch id");
return *mParentBatchId;
}
bool
hasParentBatchId() const
{
return static_cast<bool>(mParentBatchId);
} }
private: private:
uint256 mTransactionID; uint256 transactionID_;
std::uint32_t mLedger; std::uint32_t ledgerSeq_;
std::uint32_t mIndex; std::uint32_t index_;
int mResult; int result_;
std::optional<STAmount> mDelivered; std::optional<STAmount> deliveredAmount_;
std::optional<uint256> mParentBatchId; std::optional<uint256> parentBatchID_;
STArray mNodes; STArray nodes_;
}; };
} // namespace ripple } // namespace ripple

View File

@@ -27,16 +27,14 @@
#error "undefined macro: XRPL_RETIRE" #error "undefined macro: XRPL_RETIRE"
#endif #endif
// clang-format off
// Add new amendments to the top of this list. // Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order. // Keep it sorted in reverse chronological order.
XRPL_FEATURE(LendingProtocol, Supported::no, VoteBehavior::DefaultNo) XRPL_FEATURE(PermissionDelegationV1_1, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (DirectoryLimit, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (IncludeKeyletFields, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (IncludeKeyletFields, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(DynamicMPT, Supported::no, VoteBehavior::DefaultNo) XRPL_FEATURE(DynamicMPT, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (TokenEscrowV1, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (TokenEscrowV1, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (DelegateV1_1, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (PriceOracleOrder, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (PriceOracleOrder, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (MPTDeliveredAmount, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (MPTDeliveredAmount, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (AMMClawbackRounding, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (AMMClawbackRounding, Supported::yes, VoteBehavior::DefaultNo)
@@ -46,7 +44,6 @@ XRPL_FIX (AMMv1_3, Supported::yes, VoteBehavior::DefaultNo
XRPL_FEATURE(PermissionedDEX, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(PermissionedDEX, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(Batch, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(Batch, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(SingleAssetVault, Supported::no, VoteBehavior::DefaultNo) XRPL_FEATURE(SingleAssetVault, Supported::no, VoteBehavior::DefaultNo)
XRPL_FEATURE(PermissionDelegation, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo)
// Check flags in Credential transactions // Check flags in Credential transactions
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo)
@@ -80,7 +77,6 @@ XRPL_FIX (DisallowIncomingV1, Supported::yes, VoteBehavior::DefaultNo
XRPL_FEATURE(XChainBridge, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(XChainBridge, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(AMM, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(AMM, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(Clawback, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(Clawback, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (ReducedOffersV1, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (NFTokenRemint, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (NFTokenRemint, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (NonFungibleTokensV1_2, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (NonFungibleTokensV1_2, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (UniversalNumber, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (UniversalNumber, Supported::yes, VoteBehavior::DefaultNo)
@@ -95,17 +91,12 @@ XRPL_FEATURE(CheckCashMakesTrustLine, Supported::yes, VoteBehavior::DefaultNo
XRPL_FEATURE(FlowSortStrands, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(FlowSortStrands, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(TicketBatch, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(TicketBatch, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(NegativeUNL, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(NegativeUNL, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (AmendmentMajorityCalc, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(HardenedValidations, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(HardenedValidations, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(RequireFullyCanonicalSig, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(RequireFullyCanonicalSig, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (QualityUpperBound, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(DeletableAccounts, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(DeletableAccounts, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (PayChanRecipientOwnerDir, Supported::yes, VoteBehavior::DefaultYes) XRPL_FIX (PayChanRecipientOwnerDir, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (MasterKeyAsRegularKey, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (TakerDryOfferRemoval, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(MultiSignReserve, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(MultiSignReserve, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(DepositPreauth, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(DepositPreauth, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (1623, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(Checks, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(Checks, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(DepositAuth, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(DepositAuth, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes)
@@ -128,8 +119,10 @@ XRPL_FEATURE(CryptoConditionsSuite, Supported::yes, VoteBehavior::Obsolete)
// The following amendments have been active for at least two years. Their // The following amendments have been active for at least two years. Their
// pre-amendment code has been removed and the identifiers are deprecated. // pre-amendment code has been removed and the identifiers are deprecated.
// All known amendments and amendments that may appear in a validated // All known amendments and amendments that may appear in a validated ledger
// ledger must be registered either here or above with the "active" amendments // must be registered either here or above with the "active" amendments
//
// Please keep this list sorted alphabetically for convenience.
XRPL_RETIRE(fix1201) XRPL_RETIRE(fix1201)
XRPL_RETIRE(fix1368) XRPL_RETIRE(fix1368)
XRPL_RETIRE(fix1373) XRPL_RETIRE(fix1373)
@@ -141,10 +134,16 @@ XRPL_RETIRE(fix1528)
XRPL_RETIRE(fix1543) XRPL_RETIRE(fix1543)
XRPL_RETIRE(fix1571) XRPL_RETIRE(fix1571)
XRPL_RETIRE(fix1578) XRPL_RETIRE(fix1578)
XRPL_RETIRE(fix1623)
XRPL_RETIRE(fix1781) XRPL_RETIRE(fix1781)
XRPL_RETIRE(fixAmendmentMajorityCalc)
XRPL_RETIRE(fixCheckThreading) XRPL_RETIRE(fixCheckThreading)
XRPL_RETIRE(fixMasterKeyAsRegularKey)
XRPL_RETIRE(fixQualityUpperBound)
XRPL_RETIRE(fixReducedOffersV1)
XRPL_RETIRE(fixRmSmallIncreasedQOffers) XRPL_RETIRE(fixRmSmallIncreasedQOffers)
XRPL_RETIRE(fixSTAmountCanonicalize) XRPL_RETIRE(fixSTAmountCanonicalize)
XRPL_RETIRE(fixTakerDryOfferRemoval)
XRPL_RETIRE(CryptoConditions) XRPL_RETIRE(CryptoConditions)
XRPL_RETIRE(Escrow) XRPL_RETIRE(Escrow)
XRPL_RETIRE(EnforceInvariants) XRPL_RETIRE(EnforceInvariants)
@@ -155,5 +154,3 @@ XRPL_RETIRE(PayChan)
XRPL_RETIRE(SortedDirectories) XRPL_RETIRE(SortedDirectories)
XRPL_RETIRE(TickSize) XRPL_RETIRE(TickSize)
XRPL_RETIRE(TrustSetAuth) XRPL_RETIRE(TrustSetAuth)
// clang-format on

View File

@@ -168,7 +168,6 @@ LEDGER_ENTRY(ltACCOUNT_ROOT, 0x0061, AccountRoot, account, ({
{sfFirstNFTokenSequence, soeOPTIONAL}, {sfFirstNFTokenSequence, soeOPTIONAL},
{sfAMMID, soeOPTIONAL}, // pseudo-account designator {sfAMMID, soeOPTIONAL}, // pseudo-account designator
{sfVaultID, soeOPTIONAL}, // pseudo-account designator {sfVaultID, soeOPTIONAL}, // pseudo-account designator
{sfLoanBrokerID, soeOPTIONAL}, // pseudo-account designator
})) }))
/** A ledger object which contains a list of object identifiers. /** A ledger object which contains a list of object identifiers.
@@ -458,7 +457,7 @@ LEDGER_ENTRY(ltCREDENTIAL, 0x0081, Credential, credential, ({
{sfExpiration, soeOPTIONAL}, {sfExpiration, soeOPTIONAL},
{sfURI, soeOPTIONAL}, {sfURI, soeOPTIONAL},
{sfIssuerNode, soeREQUIRED}, {sfIssuerNode, soeREQUIRED},
{sfSubjectNode, soeREQUIRED}, {sfSubjectNode, soeOPTIONAL},
{sfPreviousTxnID, soeREQUIRED}, {sfPreviousTxnID, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED}, {sfPreviousTxnLgrSeq, soeREQUIRED},
})) }))
@@ -510,117 +509,5 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
// no PermissionedDomainID ever (use MPTIssuance.sfDomainID) // no PermissionedDomainID ever (use MPTIssuance.sfDomainID)
})) }))
/** Reserve 0x0084-0x0087 for future Vault-related objects. */
/** A ledger object representing a loan broker
\sa keylet::loanbroker
*/
LEDGER_ENTRY(ltLOAN_BROKER, 0x0088, LoanBroker, loan_broker, ({
{sfPreviousTxnID, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED},
{sfSequence, soeREQUIRED},
{sfOwnerNode, soeREQUIRED},
{sfVaultNode, soeREQUIRED},
{sfVaultID, soeREQUIRED},
{sfAccount, soeREQUIRED},
{sfOwner, soeREQUIRED},
{sfLoanSequence, soeREQUIRED},
{sfData, soeDEFAULT},
{sfManagementFeeRate, soeDEFAULT},
{sfOwnerCount, soeDEFAULT},
{sfDebtTotal, soeDEFAULT},
{sfDebtMaximum, soeDEFAULT},
{sfCoverAvailable, soeDEFAULT},
{sfCoverRateMinimum, soeDEFAULT},
{sfCoverRateLiquidation, soeDEFAULT},
}))
/** A ledger object representing a loan between a Borrower and a Loan Broker
\sa keylet::loan
*/
LEDGER_ENTRY(ltLOAN, 0x0089, Loan, loan, ({
{sfPreviousTxnID, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED},
{sfOwnerNode, soeREQUIRED},
{sfLoanBrokerNode, soeREQUIRED},
{sfLoanBrokerID, soeREQUIRED},
{sfLoanSequence, soeREQUIRED},
{sfBorrower, soeREQUIRED},
{sfLoanOriginationFee, soeDEFAULT},
{sfLoanServiceFee, soeDEFAULT},
{sfLatePaymentFee, soeDEFAULT},
{sfClosePaymentFee, soeDEFAULT},
{sfOverpaymentFee, soeDEFAULT},
{sfInterestRate, soeDEFAULT},
{sfLateInterestRate, soeDEFAULT},
{sfCloseInterestRate, soeDEFAULT},
{sfOverpaymentInterestRate, soeDEFAULT},
{sfStartDate, soeREQUIRED},
{sfPaymentInterval, soeREQUIRED},
{sfGracePeriod, soeREQUIRED},
{sfPreviousPaymentDate, soeDEFAULT},
{sfNextPaymentDueDate, soeOPTIONAL},
// The loan object tracks these values:
//
// - PaymentRemaining: The number of payments left in the loan. When it
// reaches 0, the loan is paid off, and all other relevant values
// must also be 0.
//
// - PeriodicPayment: The fixed, unrounded amount to be paid each
// interval. Stored with as much precision as possible.
// Payment transactions must round this value *UP*.
//
// - TotalValueOutstanding: The rounded total amount owed by the
// borrower to the lender / vault.
//
// - PrincipalOutstanding: The rounded portion of the
// TotalValueOutstanding that is from the principal borrowed.
//
// - ManagementFeeOutstanding: The rounded portion of the
// TotalValueOutstanding that represents management fees
// specifically owed to the broker based on the initial
// loan parameters.
//
// There are additional values that can be computed from these:
//
// - InterestOutstanding = TotalValueOutstanding - PrincipalOutstanding
// The total amount of interest still pending on the loan,
// independent of management fees.
//
// - InterestOwedToVault = InterestOutstanding - ManagementFeeOutstanding
// The amount of the total interest that is owed to the vault, and
// will be sent to as part of a payment.
//
// - TrueTotalLoanValue = PaymentRemaining * PeriodicPayment
// The unrounded true total value of the loan.
//
// - TrueTotalPrincialOutstanding can be computed using the algorithm
// in the ripple::detail::loanPrincipalFromPeriodicPayment function.
//
// - TrueTotalInterestOutstanding = TrueTotalLoanValue -
// TrueTotalPrincipalOutstanding
// The unrounded true total interest remaining.
//
// - TrueTotalManagementFeeOutstanding = TrueTotalInterestOutstanding *
// LoanBroker.ManagementFeeRate
// The unrounded true total fee still owed to the broker.
//
// Note the the "True" values may differ significantly from the tracked
// rounded values.
{sfPaymentRemaining, soeDEFAULT},
{sfPeriodicPayment, soeREQUIRED},
{sfPrincipalOutstanding, soeDEFAULT},
{sfTotalValueOutstanding, soeDEFAULT},
{sfManagementFeeOutstanding, soeDEFAULT},
// Based on the computed total value at creation, used for
// rounding calculated values so they are all on a
// consistent scale - that is, they all have the same
// number of digits after the decimal point (excluding
// trailing zeros).
{sfLoanScale, soeDEFAULT},
}))
#undef EXPAND #undef EXPAND
#undef LEDGER_ENTRY_DUPLICATE #undef LEDGER_ENTRY_DUPLICATE

View File

@@ -24,8 +24,6 @@
#error "undefined macro: TYPED_SFIELD" #error "undefined macro: TYPED_SFIELD"
#endif #endif
// clang-format off
// untyped // untyped
UNTYPED_SFIELD(sfLedgerEntry, LEDGERENTRY, 257) UNTYPED_SFIELD(sfLedgerEntry, LEDGERENTRY, 257)
UNTYPED_SFIELD(sfTransaction, TRANSACTION, 257) UNTYPED_SFIELD(sfTransaction, TRANSACTION, 257)
@@ -61,7 +59,6 @@ TYPED_SFIELD(sfHookEmitCount, UINT16, 18)
TYPED_SFIELD(sfHookExecutionIndex, UINT16, 19) TYPED_SFIELD(sfHookExecutionIndex, UINT16, 19)
TYPED_SFIELD(sfHookApiVersion, UINT16, 20) TYPED_SFIELD(sfHookApiVersion, UINT16, 20)
TYPED_SFIELD(sfLedgerFixType, UINT16, 21) TYPED_SFIELD(sfLedgerFixType, UINT16, 21)
TYPED_SFIELD(sfManagementFeeRate, UINT16, 22) // 1/10 basis points (bips)
// 32-bit integers (common) // 32-bit integers (common)
TYPED_SFIELD(sfNetworkID, UINT32, 1) TYPED_SFIELD(sfNetworkID, UINT32, 1)
@@ -118,21 +115,6 @@ TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50)
TYPED_SFIELD(sfOracleDocumentID, UINT32, 51) TYPED_SFIELD(sfOracleDocumentID, UINT32, 51)
TYPED_SFIELD(sfPermissionValue, UINT32, 52) TYPED_SFIELD(sfPermissionValue, UINT32, 52)
TYPED_SFIELD(sfMutableFlags, UINT32, 53) TYPED_SFIELD(sfMutableFlags, UINT32, 53)
TYPED_SFIELD(sfStartDate, UINT32, 54)
TYPED_SFIELD(sfPaymentInterval, UINT32, 55)
TYPED_SFIELD(sfGracePeriod, UINT32, 56)
TYPED_SFIELD(sfPreviousPaymentDate, UINT32, 57)
TYPED_SFIELD(sfNextPaymentDueDate, UINT32, 58)
TYPED_SFIELD(sfPaymentRemaining, UINT32, 59)
TYPED_SFIELD(sfPaymentTotal, UINT32, 60)
TYPED_SFIELD(sfLoanSequence, UINT32, 61)
TYPED_SFIELD(sfCoverRateMinimum, UINT32, 62) // 1/10 basis points (bips)
TYPED_SFIELD(sfCoverRateLiquidation, UINT32, 63) // 1/10 basis points (bips)
TYPED_SFIELD(sfOverpaymentFee, UINT32, 64) // 1/10 basis points (bips)
TYPED_SFIELD(sfInterestRate, UINT32, 65) // 1/10 basis points (bips)
TYPED_SFIELD(sfLateInterestRate, UINT32, 66) // 1/10 basis points (bips)
TYPED_SFIELD(sfCloseInterestRate, UINT32, 67) // 1/10 basis points (bips)
TYPED_SFIELD(sfOverpaymentInterestRate, UINT32, 68) // 1/10 basis points (bips)
// 64-bit integers (common) // 64-bit integers (common)
TYPED_SFIELD(sfIndexNext, UINT64, 1) TYPED_SFIELD(sfIndexNext, UINT64, 1)
@@ -164,8 +146,6 @@ TYPED_SFIELD(sfMPTAmount, UINT64, 26, SField::sMD_BaseTen|SFie
TYPED_SFIELD(sfIssuerNode, UINT64, 27) TYPED_SFIELD(sfIssuerNode, UINT64, 27)
TYPED_SFIELD(sfSubjectNode, UINT64, 28) TYPED_SFIELD(sfSubjectNode, UINT64, 28)
TYPED_SFIELD(sfLockedAmount, UINT64, 29, SField::sMD_BaseTen|SField::sMD_Default) TYPED_SFIELD(sfLockedAmount, UINT64, 29, SField::sMD_BaseTen|SField::sMD_Default)
TYPED_SFIELD(sfVaultNode, UINT64, 30)
TYPED_SFIELD(sfLoanBrokerNode, UINT64, 31)
// 128-bit // 128-bit
TYPED_SFIELD(sfEmailHash, UINT128, 1) TYPED_SFIELD(sfEmailHash, UINT128, 1)
@@ -220,9 +200,6 @@ TYPED_SFIELD(sfDomainID, UINT256, 34)
TYPED_SFIELD(sfVaultID, UINT256, 35, TYPED_SFIELD(sfVaultID, UINT256, 35,
SField::sMD_PseudoAccount | SField::sMD_Default) SField::sMD_PseudoAccount | SField::sMD_Default)
TYPED_SFIELD(sfParentBatchID, UINT256, 36) TYPED_SFIELD(sfParentBatchID, UINT256, 36)
TYPED_SFIELD(sfLoanBrokerID, UINT256, 37,
SField::sMD_PseudoAccount | SField::sMD_Default)
TYPED_SFIELD(sfLoanID, UINT256, 38)
// number (common) // number (common)
TYPED_SFIELD(sfNumber, NUMBER, 1) TYPED_SFIELD(sfNumber, NUMBER, 1)
@@ -230,21 +207,12 @@ TYPED_SFIELD(sfAssetsAvailable, NUMBER, 2)
TYPED_SFIELD(sfAssetsMaximum, NUMBER, 3) TYPED_SFIELD(sfAssetsMaximum, NUMBER, 3)
TYPED_SFIELD(sfAssetsTotal, NUMBER, 4) TYPED_SFIELD(sfAssetsTotal, NUMBER, 4)
TYPED_SFIELD(sfLossUnrealized, NUMBER, 5) TYPED_SFIELD(sfLossUnrealized, NUMBER, 5)
TYPED_SFIELD(sfDebtTotal, NUMBER, 6)
TYPED_SFIELD(sfDebtMaximum, NUMBER, 7)
TYPED_SFIELD(sfCoverAvailable, NUMBER, 8)
TYPED_SFIELD(sfLoanOriginationFee, NUMBER, 9)
TYPED_SFIELD(sfLoanServiceFee, NUMBER, 10)
TYPED_SFIELD(sfLatePaymentFee, NUMBER, 11)
TYPED_SFIELD(sfClosePaymentFee, NUMBER, 12)
TYPED_SFIELD(sfPrincipalOutstanding, NUMBER, 13)
TYPED_SFIELD(sfPrincipalRequested, NUMBER, 14)
TYPED_SFIELD(sfTotalValueOutstanding, NUMBER, 15)
TYPED_SFIELD(sfPeriodicPayment, NUMBER, 16)
TYPED_SFIELD(sfManagementFeeOutstanding, NUMBER, 17)
// int32 // int32
TYPED_SFIELD(sfLoanScale, INT32, 1) // NOTE: Do not use `sfDummyInt32`. It's so far the only use of INT32
// in this file and has been defined here for test only.
// TODO: Replace `sfDummyInt32` with actually useful field.
TYPED_SFIELD(sfDummyInt32, INT32, 1) // for tests only
// currency amount (common) // currency amount (common)
TYPED_SFIELD(sfAmount, AMOUNT, 1) TYPED_SFIELD(sfAmount, AMOUNT, 1)
@@ -340,8 +308,6 @@ TYPED_SFIELD(sfAttestationRewardAccount, ACCOUNT, 21)
TYPED_SFIELD(sfLockingChainDoor, ACCOUNT, 22) TYPED_SFIELD(sfLockingChainDoor, ACCOUNT, 22)
TYPED_SFIELD(sfIssuingChainDoor, ACCOUNT, 23) TYPED_SFIELD(sfIssuingChainDoor, ACCOUNT, 23)
TYPED_SFIELD(sfSubject, ACCOUNT, 24) TYPED_SFIELD(sfSubject, ACCOUNT, 24)
TYPED_SFIELD(sfBorrower, ACCOUNT, 25)
TYPED_SFIELD(sfCounterparty, ACCOUNT, 26)
// vector of 256-bit // vector of 256-bit
TYPED_SFIELD(sfIndexes, VECTOR256, 1, SField::sMD_Never) TYPED_SFIELD(sfIndexes, VECTOR256, 1, SField::sMD_Never)
@@ -405,7 +371,6 @@ UNTYPED_SFIELD(sfCredential, OBJECT, 33)
UNTYPED_SFIELD(sfRawTransaction, OBJECT, 34) UNTYPED_SFIELD(sfRawTransaction, OBJECT, 34)
UNTYPED_SFIELD(sfBatchSigner, OBJECT, 35) UNTYPED_SFIELD(sfBatchSigner, OBJECT, 35)
UNTYPED_SFIELD(sfBook, OBJECT, 36) UNTYPED_SFIELD(sfBook, OBJECT, 36)
UNTYPED_SFIELD(sfCounterpartySignature, OBJECT, 37, SField::sMD_Default, SField::notSigning)
// array of objects (common) // array of objects (common)
// ARRAY/1 is reserved for end of array // ARRAY/1 is reserved for end of array
@@ -440,5 +405,3 @@ UNTYPED_SFIELD(sfAcceptedCredentials, ARRAY, 28)
UNTYPED_SFIELD(sfPermissions, ARRAY, 29) UNTYPED_SFIELD(sfPermissions, ARRAY, 29)
UNTYPED_SFIELD(sfRawTransactions, ARRAY, 30) UNTYPED_SFIELD(sfRawTransactions, ARRAY, 30)
UNTYPED_SFIELD(sfBatchSigners, ARRAY, 31, SField::sMD_Default, SField::notSigning) UNTYPED_SFIELD(sfBatchSigners, ARRAY, 31, SField::sMD_Default, SField::notSigning)
// clang-format on

View File

@@ -316,7 +316,7 @@ TRANSACTION(ttTRUST_SET, 20, TrustSet,
#endif #endif
TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete,
Delegation::notDelegatable, Delegation::notDelegatable,
uint256{}, featureDeletableAccounts,
mustDeleteAcct, mustDeleteAcct,
({ ({
{sfDestination, soeREQUIRED}, {sfDestination, soeREQUIRED},
@@ -837,7 +837,7 @@ TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete,
#endif #endif
TRANSACTION(ttDELEGATE_SET, 64, DelegateSet, TRANSACTION(ttDELEGATE_SET, 64, DelegateSet,
Delegation::notDelegatable, Delegation::notDelegatable,
featurePermissionDelegation, featurePermissionDelegationV1_1,
noPriv, noPriv,
({ ({
{sfAuthorize, soeREQUIRED}, {sfAuthorize, soeREQUIRED},
@@ -944,139 +944,6 @@ TRANSACTION(ttBATCH, 71, Batch,
{sfBatchSigners, soeOPTIONAL}, {sfBatchSigners, soeOPTIONAL},
})) }))
/** Reserve 72-73 for future Vault-related transactions */
/** This transaction creates and updates a Loan Broker */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanBrokerSet.h>
#endif
TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
Delegation::delegatable,
featureLendingProtocol,
createPseudoAcct | mayAuthorizeMPT, ({
{sfVaultID, soeREQUIRED},
{sfLoanBrokerID, soeOPTIONAL},
{sfData, soeOPTIONAL},
{sfManagementFeeRate, soeOPTIONAL},
{sfDebtMaximum, soeOPTIONAL},
{sfCoverRateMinimum, soeOPTIONAL},
{sfCoverRateLiquidation, soeOPTIONAL},
}))
/** This transaction deletes a Loan Broker */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanBrokerDelete.h>
#endif
TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete,
Delegation::delegatable,
featureLendingProtocol,
mustDeleteAcct | mayAuthorizeMPT, ({
{sfLoanBrokerID, soeREQUIRED},
}))
/** This transaction deposits First Loss Capital into a Loan Broker */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanBrokerCoverDeposit.h>
#endif
TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit,
Delegation::delegatable,
featureLendingProtocol,
noPriv, ({
{sfLoanBrokerID, soeREQUIRED},
{sfAmount, soeREQUIRED, soeMPTSupported},
}))
/** This transaction withdraws First Loss Capital from a Loan Broker */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanBrokerCoverWithdraw.h>
#endif
TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw,
Delegation::delegatable,
featureLendingProtocol,
mayAuthorizeMPT, ({
{sfLoanBrokerID, soeREQUIRED},
{sfAmount, soeREQUIRED, soeMPTSupported},
{sfDestination, soeOPTIONAL},
{sfDestinationTag, soeOPTIONAL},
}))
/** This transaction claws back First Loss Capital from a Loan Broker to
the issuer of the capital */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanBrokerCoverClawback.h>
#endif
TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback,
Delegation::delegatable,
featureLendingProtocol,
noPriv, ({
{sfLoanBrokerID, soeOPTIONAL},
{sfAmount, soeOPTIONAL, soeMPTSupported},
}))
/** This transaction creates a Loan */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanSet.h>
#endif
TRANSACTION(ttLOAN_SET, 80, LoanSet,
Delegation::delegatable,
featureLendingProtocol,
mayAuthorizeMPT | mustModifyVault, ({
{sfLoanBrokerID, soeREQUIRED},
{sfData, soeOPTIONAL},
{sfCounterparty, soeOPTIONAL},
{sfCounterpartySignature, soeOPTIONAL},
{sfLoanOriginationFee, soeOPTIONAL},
{sfLoanServiceFee, soeOPTIONAL},
{sfLatePaymentFee, soeOPTIONAL},
{sfClosePaymentFee, soeOPTIONAL},
{sfOverpaymentFee, soeOPTIONAL},
{sfInterestRate, soeOPTIONAL},
{sfLateInterestRate, soeOPTIONAL},
{sfCloseInterestRate, soeOPTIONAL},
{sfOverpaymentInterestRate, soeOPTIONAL},
{sfPrincipalRequested, soeREQUIRED},
{sfPaymentTotal, soeOPTIONAL},
{sfPaymentInterval, soeOPTIONAL},
{sfGracePeriod, soeOPTIONAL},
}))
/** This transaction deletes an existing Loan */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanDelete.h>
#endif
TRANSACTION(ttLOAN_DELETE, 81, LoanDelete,
Delegation::delegatable,
featureLendingProtocol,
noPriv, ({
{sfLoanID, soeREQUIRED},
}))
/** This transaction is used to change the delinquency status of an existing Loan */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanManage.h>
#endif
TRANSACTION(ttLOAN_MANAGE, 82, LoanManage,
Delegation::delegatable,
featureLendingProtocol,
// All of the LoanManage options will modify the vault, but the
// transaction can succeed without options, essentially making it
// a noop.
mayModifyVault, ({
{sfLoanID, soeREQUIRED},
}))
/** The Borrower uses this transaction to make a Payment on the Loan. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanPay.h>
#endif
TRANSACTION(ttLOAN_PAY, 84, LoanPay,
Delegation::delegatable,
featureLendingProtocol,
mayAuthorizeMPT | mustModifyVault, ({
{sfLoanID, soeREQUIRED},
{sfAmount, soeREQUIRED, soeMPTSupported},
}))
/** This system-generated transaction type is used to update the status of the various amendments. /** This system-generated transaction type is used to update the status of the various amendments.
For details, see: https://xrpl.org/amendments.html For details, see: https://xrpl.org/amendments.html

View File

@@ -59,8 +59,6 @@ JSS(BaseAsset); // in: Oracle
JSS(BidMax); // in: AMM Bid JSS(BidMax); // in: AMM Bid
JSS(BidMin); // in: AMM Bid JSS(BidMin); // in: AMM Bid
JSS(ClearFlag); // field. JSS(ClearFlag); // field.
JSS(Counterparty); // field.
JSS(CounterpartySignature);// field.
JSS(DeliverMax); // out: alias to Amount JSS(DeliverMax); // out: alias to Amount
JSS(DeliverMin); // in: TransactionSign JSS(DeliverMin); // in: TransactionSign
JSS(Destination); // in: TransactionSign; field. JSS(Destination); // in: TransactionSign; field.
@@ -394,8 +392,6 @@ JSS(load_factor_local); // out: NetworkOPs
JSS(load_factor_net); // out: NetworkOPs JSS(load_factor_net); // out: NetworkOPs
JSS(load_factor_server); // out: NetworkOPs JSS(load_factor_server); // out: NetworkOPs
JSS(load_fee); // out: LoadFeeTrackImp, NetworkOPs JSS(load_fee); // out: LoadFeeTrackImp, NetworkOPs
JSS(loan_broker_id); // in: LedgerEntry
JSS(loan_seq); // in: LedgerEntry
JSS(local); // out: resource/Logic.h JSS(local); // out: resource/Logic.h
JSS(local_txs); // out: GetCounts JSS(local_txs); // out: GetCounts
JSS(local_static_keys); // out: ValidatorList JSS(local_static_keys); // out: ValidatorList
@@ -508,7 +504,6 @@ JSS(propose_seq); // out: LedgerPropose
JSS(proposers); // out: NetworkOPs, LedgerConsensus JSS(proposers); // out: NetworkOPs, LedgerConsensus
JSS(protocol); // out: NetworkOPs, PeerImp JSS(protocol); // out: NetworkOPs, PeerImp
JSS(proxied); // out: RPC ping JSS(proxied); // out: RPC ping
JSS(pseudo_account); // out: AccountInfo
JSS(pubkey_node); // out: NetworkOPs JSS(pubkey_node); // out: NetworkOPs
JSS(pubkey_publisher); // out: ValidatorList JSS(pubkey_publisher); // out: ValidatorList
JSS(pubkey_validator); // out: NetworkOPs, ValidatorList JSS(pubkey_validator); // out: NetworkOPs, ValidatorList

View File

@@ -20,11 +20,10 @@
#ifndef RIPPLE_SHAMAP_FAMILY_H_INCLUDED #ifndef RIPPLE_SHAMAP_FAMILY_H_INCLUDED
#define RIPPLE_SHAMAP_FAMILY_H_INCLUDED #define RIPPLE_SHAMAP_FAMILY_H_INCLUDED
#include <xrpld/nodestore/Database.h>
#include <xrpld/shamap/FullBelowCache.h>
#include <xrpld/shamap/TreeNodeCache.h>
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <xrpl/nodestore/Database.h>
#include <xrpl/shamap/FullBelowCache.h>
#include <xrpl/shamap/TreeNodeCache.h>
#include <cstdint> #include <cstdint>

View File

@@ -20,21 +20,19 @@
#ifndef RIPPLE_SHAMAP_SHAMAP_H_INCLUDED #ifndef RIPPLE_SHAMAP_SHAMAP_H_INCLUDED
#define RIPPLE_SHAMAP_SHAMAP_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAP_H_INCLUDED
#include <xrpld/nodestore/Database.h>
#include <xrpld/nodestore/NodeObject.h>
#include <xrpld/shamap/Family.h>
#include <xrpld/shamap/SHAMapAddNode.h>
#include <xrpld/shamap/SHAMapInnerNode.h>
#include <xrpld/shamap/SHAMapItem.h>
#include <xrpld/shamap/SHAMapLeafNode.h>
#include <xrpld/shamap/SHAMapMissingNode.h>
#include <xrpld/shamap/SHAMapTreeNode.h>
#include <xrpld/shamap/TreeNodeCache.h>
#include <xrpl/basics/IntrusivePointer.h> #include <xrpl/basics/IntrusivePointer.h>
#include <xrpl/basics/UnorderedContainers.h> #include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/nodestore/Database.h>
#include <xrpl/nodestore/NodeObject.h>
#include <xrpl/shamap/Family.h>
#include <xrpl/shamap/SHAMapAddNode.h>
#include <xrpl/shamap/SHAMapInnerNode.h>
#include <xrpl/shamap/SHAMapItem.h>
#include <xrpl/shamap/SHAMapLeafNode.h>
#include <xrpl/shamap/SHAMapMissingNode.h>
#include <xrpl/shamap/SHAMapTreeNode.h>
#include <set> #include <set>
#include <stack> #include <stack>

View File

@@ -20,12 +20,11 @@
#ifndef RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED #ifndef RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED
#define RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED
#include <xrpld/shamap/SHAMapItem.h>
#include <xrpld/shamap/SHAMapLeafNode.h>
#include <xrpl/basics/CountedObject.h> #include <xrpl/basics/CountedObject.h>
#include <xrpl/protocol/HashPrefix.h> #include <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/digest.h> #include <xrpl/protocol/digest.h>
#include <xrpl/shamap/SHAMapItem.h>
#include <xrpl/shamap/SHAMapLeafNode.h>
namespace ripple { namespace ripple {

View File

@@ -20,10 +20,9 @@
#ifndef RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED #ifndef RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED
#define RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED
#include <xrpld/shamap/SHAMapNodeID.h>
#include <xrpld/shamap/detail/TaggedPointer.h>
#include <xrpl/basics/IntrusivePointer.h> #include <xrpl/basics/IntrusivePointer.h>
#include <xrpl/shamap/SHAMapNodeID.h>
#include <xrpl/shamap/detail/TaggedPointer.h>
#include <atomic> #include <atomic>
#include <cstdint> #include <cstdint>

View File

@@ -20,8 +20,8 @@
#ifndef RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED #ifndef RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED
#define RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED
#include <xrpld/shamap/SHAMapItem.h> #include <xrpl/shamap/SHAMapItem.h>
#include <xrpld/shamap/SHAMapTreeNode.h> #include <xrpl/shamap/SHAMapTreeNode.h>
#include <cstdint> #include <cstdint>

View File

@@ -20,9 +20,8 @@
#ifndef RIPPLE_SHAMAP_SHAMAPMISSINGNODE_H_INCLUDED #ifndef RIPPLE_SHAMAP_SHAMAPMISSINGNODE_H_INCLUDED
#define RIPPLE_SHAMAP_SHAMAPMISSINGNODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPMISSINGNODE_H_INCLUDED
#include <xrpld/shamap/SHAMapTreeNode.h>
#include <xrpl/basics/base_uint.h> #include <xrpl/basics/base_uint.h>
#include <xrpl/shamap/SHAMapTreeNode.h>
#include <iosfwd> #include <iosfwd>
#include <stdexcept> #include <stdexcept>

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_SHAMAP_SHAMAPSYNCFILTER_H_INCLUDED #ifndef RIPPLE_SHAMAP_SHAMAPSYNCFILTER_H_INCLUDED
#define RIPPLE_SHAMAP_SHAMAPSYNCFILTER_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPSYNCFILTER_H_INCLUDED
#include <xrpld/shamap/SHAMapTreeNode.h> #include <xrpl/shamap/SHAMapTreeNode.h>
#include <optional> #include <optional>

View File

@@ -20,13 +20,12 @@
#ifndef RIPPLE_SHAMAP_SHAMAPTREENODE_H_INCLUDED #ifndef RIPPLE_SHAMAP_SHAMAPTREENODE_H_INCLUDED
#define RIPPLE_SHAMAP_SHAMAPTREENODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPTREENODE_H_INCLUDED
#include <xrpld/shamap/SHAMapItem.h>
#include <xrpld/shamap/SHAMapNodeID.h>
#include <xrpl/basics/IntrusivePointer.h> #include <xrpl/basics/IntrusivePointer.h>
#include <xrpl/basics/IntrusiveRefCounts.h> #include <xrpl/basics/IntrusiveRefCounts.h>
#include <xrpl/basics/SHAMapHash.h> #include <xrpl/basics/SHAMapHash.h>
#include <xrpl/protocol/Serializer.h> #include <xrpl/protocol/Serializer.h>
#include <xrpl/shamap/SHAMapItem.h>
#include <xrpl/shamap/SHAMapNodeID.h>
#include <cstdint> #include <cstdint>
#include <string> #include <string>

View File

@@ -20,12 +20,11 @@
#ifndef RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED #ifndef RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED
#define RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED
#include <xrpld/shamap/SHAMapItem.h>
#include <xrpld/shamap/SHAMapLeafNode.h>
#include <xrpl/basics/CountedObject.h> #include <xrpl/basics/CountedObject.h>
#include <xrpl/protocol/HashPrefix.h> #include <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/digest.h> #include <xrpl/protocol/digest.h>
#include <xrpl/shamap/SHAMapItem.h>
#include <xrpl/shamap/SHAMapLeafNode.h>
namespace ripple { namespace ripple {

View File

@@ -20,12 +20,11 @@
#ifndef RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED #ifndef RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED
#define RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED
#include <xrpld/shamap/SHAMapItem.h>
#include <xrpld/shamap/SHAMapLeafNode.h>
#include <xrpl/basics/CountedObject.h> #include <xrpl/basics/CountedObject.h>
#include <xrpl/protocol/HashPrefix.h> #include <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/digest.h> #include <xrpl/protocol/digest.h>
#include <xrpl/shamap/SHAMapItem.h>
#include <xrpl/shamap/SHAMapLeafNode.h>
namespace ripple { namespace ripple {

View File

@@ -20,10 +20,9 @@
#ifndef RIPPLE_SHAMAP_TREENODECACHE_H_INCLUDED #ifndef RIPPLE_SHAMAP_TREENODECACHE_H_INCLUDED
#define RIPPLE_SHAMAP_TREENODECACHE_H_INCLUDED #define RIPPLE_SHAMAP_TREENODECACHE_H_INCLUDED
#include <xrpld/shamap/SHAMapTreeNode.h>
#include <xrpl/basics/IntrusivePointer.h> #include <xrpl/basics/IntrusivePointer.h>
#include <xrpl/basics/TaggedCache.h> #include <xrpl/basics/TaggedCache.h>
#include <xrpl/shamap/SHAMapTreeNode.h>
namespace ripple { namespace ripple {

View File

@@ -20,9 +20,8 @@
#ifndef RIPPLE_SHAMAP_TAGGEDPOINTER_H_INCLUDED #ifndef RIPPLE_SHAMAP_TAGGEDPOINTER_H_INCLUDED
#define RIPPLE_SHAMAP_TAGGEDPOINTER_H_INCLUDED #define RIPPLE_SHAMAP_TAGGEDPOINTER_H_INCLUDED
#include <xrpld/shamap/SHAMapTreeNode.h>
#include <xrpl/basics/IntrusivePointer.h> #include <xrpl/basics/IntrusivePointer.h>
#include <xrpl/shamap/SHAMapTreeNode.h>
#include <array> #include <array>
#include <cstdint> #include <cstdint>

View File

@@ -17,10 +17,9 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/shamap/SHAMapInnerNode.h>
#include <xrpld/shamap/detail/TaggedPointer.h>
#include <xrpl/basics/ByteUtilities.h> #include <xrpl/basics/ByteUtilities.h>
#include <xrpl/shamap/SHAMapInnerNode.h>
#include <xrpl/shamap/detail/TaggedPointer.h>
#include <boost/pool/pool_alloc.hpp> #include <boost/pool/pool_alloc.hpp>

View File

@@ -43,8 +43,6 @@ namespace ripple {
thread_local Number::rounding_mode Number::mode_ = Number::to_nearest; thread_local Number::rounding_mode Number::mode_ = Number::to_nearest;
Number const Number::zero{};
Number::rounding_mode Number::rounding_mode
Number::getround() Number::getround()
{ {
@@ -95,18 +93,6 @@ public:
// tie, round towards even. // tie, round towards even.
int int
round() noexcept; round() noexcept;
// Modify the result to the correctly rounded value
void
doRoundUp(rep& mantissa, int& exponent, std::string location);
// Modify the result to the correctly rounded value
void
doRoundDown(rep& mantissa, int& exponent);
// Modify the result to the correctly rounded value
void
doRound(rep& drops);
}; };
inline void inline void
@@ -184,61 +170,6 @@ Number::Guard::round() noexcept
return 0; return 0;
} }
void
Number::Guard::doRoundUp(rep& mantissa, int& exponent, std::string location)
{
auto r = round();
if (r == 1 || (r == 0 && (mantissa & 1) == 1))
{
++mantissa;
if (mantissa > maxMantissa)
{
mantissa /= 10;
++exponent;
}
}
if (exponent < minExponent)
{
mantissa = 0;
exponent = Number{}.exponent_;
}
if (exponent > maxExponent)
throw std::overflow_error(location);
}
void
Number::Guard::doRoundDown(rep& mantissa, int& exponent)
{
auto r = round();
if (r == 1 || (r == 0 && (mantissa & 1) == 1))
{
--mantissa;
if (mantissa < minMantissa)
{
mantissa *= 10;
--exponent;
}
}
if (exponent < minExponent)
{
mantissa = 0;
exponent = Number{}.exponent_;
}
}
// Modify the result to the correctly rounded value
void
Number::Guard::doRound(rep& drops)
{
auto r = round();
if (r == 1 || (r == 0 && (drops & 1) == 1))
{
++drops;
}
if (is_negative())
drops = -drops;
}
// Number // Number
constexpr Number one{1000000000000000, -15, Number::unchecked{}}; constexpr Number one{1000000000000000, -15, Number::unchecked{}};
@@ -278,7 +209,18 @@ Number::normalize()
return; return;
} }
g.doRoundUp(mantissa_, exponent_, "Number::normalize 2"); auto r = g.round();
if (r == 1 || (r == 0 && (mantissa_ & 1) == 1))
{
++mantissa_;
if (mantissa_ > maxMantissa)
{
mantissa_ /= 10;
++exponent_;
}
}
if (exponent_ > maxExponent)
throw std::overflow_error("Number::normalize 2");
if (negative) if (negative)
mantissa_ = -mantissa_; mantissa_ = -mantissa_;
@@ -350,7 +292,18 @@ Number::operator+=(Number const& y)
xm /= 10; xm /= 10;
++xe; ++xe;
} }
g.doRoundUp(xm, xe, "Number::addition overflow"); auto r = g.round();
if (r == 1 || (r == 0 && (xm & 1) == 1))
{
++xm;
if (xm > maxMantissa)
{
xm /= 10;
++xe;
}
}
if (xe > maxExponent)
throw std::overflow_error("Number::addition overflow");
} }
else else
{ {
@@ -370,7 +323,21 @@ Number::operator+=(Number const& y)
xm -= g.pop(); xm -= g.pop();
--xe; --xe;
} }
g.doRoundDown(xm, xe); auto r = g.round();
if (r == 1 || (r == 0 && (xm & 1) == 1))
{
--xm;
if (xm < minMantissa)
{
xm *= 10;
--xe;
}
}
if (xe < minExponent)
{
xm = 0;
xe = Number{}.exponent_;
}
} }
mantissa_ = xm * xn; mantissa_ = xm * xn;
exponent_ = xe; exponent_ = xe;
@@ -450,10 +417,25 @@ Number::operator*=(Number const& y)
} }
xm = static_cast<rep>(zm); xm = static_cast<rep>(zm);
xe = ze; xe = ze;
g.doRoundUp( auto r = g.round();
xm, if (r == 1 || (r == 0 && (xm & 1) == 1))
xe, {
"Number::multiplication overflow : exponent is " + std::to_string(xe)); ++xm;
if (xm > maxMantissa)
{
xm /= 10;
++xe;
}
}
if (xe < minExponent)
{
xm = 0;
xe = Number{}.exponent_;
}
if (xe > maxExponent)
throw std::overflow_error(
"Number::multiplication overflow : exponent is " +
std::to_string(xe));
mantissa_ = xm * zn; mantissa_ = xm * zn;
exponent_ = xe; exponent_ = xe;
XRPL_ASSERT( XRPL_ASSERT(
@@ -518,7 +500,13 @@ Number::operator rep() const
throw std::overflow_error("Number::operator rep() overflow"); throw std::overflow_error("Number::operator rep() overflow");
drops *= 10; drops *= 10;
} }
g.doRound(drops); auto r = g.round();
if (r == 1 || (r == 0 && (drops & 1) == 1))
{
++drops;
}
if (g.is_negative())
drops = -drops;
} }
return drops; return drops;
} }

View File

@@ -1001,12 +1001,6 @@ Value::isMember(std::string const& key) const
return isMember(key.c_str()); return isMember(key.c_str());
} }
bool
Value::isMember(StaticString const& key) const
{
return isMember(key.c_str());
}
Value::Members Value::Members
Value::getMemberNames() const Value::getMemberNames() const
{ {

View File

@@ -126,10 +126,10 @@ ApplyStateTable::apply(
std::optional<TxMeta> metadata; std::optional<TxMeta> metadata;
if (!to.open() || isDryRun) if (!to.open() || isDryRun)
{ {
TxMeta meta(tx.getTransactionID(), to.seq(), parentBatchId); TxMeta meta(tx.getTransactionID(), to.seq());
if (deliver) meta.setDeliveredAmount(deliver);
meta.setDeliveredAmount(*deliver); meta.setParentBatchID(parentBatchId);
Mods newMod; Mods newMod;
for (auto& item : items_) for (auto& item : items_)

View File

@@ -22,130 +22,11 @@
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/protocol/Protocol.h> #include <xrpl/protocol/Protocol.h>
#include <limits>
#include <type_traits>
namespace ripple { namespace ripple {
namespace directory {
std::uint64_t
createRoot(
ApplyView& view,
Keylet const& directory,
uint256 const& key,
std::function<void(std::shared_ptr<SLE> const&)> const& describe)
{
auto newRoot = std::make_shared<SLE>(directory);
newRoot->setFieldH256(sfRootIndex, directory.key);
describe(newRoot);
STVector256 v;
v.push_back(key);
newRoot->setFieldV256(sfIndexes, v);
view.insert(newRoot);
return std::uint64_t{0};
}
auto
findPreviousPage(ApplyView& view, Keylet const& directory, SLE::ref start)
{
std::uint64_t page = start->getFieldU64(sfIndexPrevious);
auto node = start;
if (page)
{
node = view.peek(keylet::page(directory, page));
if (!node)
LogicError("Directory chain: root back-pointer broken.");
}
auto indexes = node->getFieldV256(sfIndexes);
return std::make_tuple(page, node, indexes);
}
std::uint64_t
insertKey(
ApplyView& view,
SLE::ref node,
std::uint64_t page,
bool preserveOrder,
STVector256& indexes,
uint256 const& key)
{
if (preserveOrder)
{
if (std::find(indexes.begin(), indexes.end(), key) != indexes.end())
LogicError("dirInsert: double insertion");
indexes.push_back(key);
}
else
{
// We can't be sure if this page is already sorted because
// it may be a legacy page we haven't yet touched. Take
// the time to sort it.
std::sort(indexes.begin(), indexes.end());
auto pos = std::lower_bound(indexes.begin(), indexes.end(), key);
if (pos != indexes.end() && key == *pos)
LogicError("dirInsert: double insertion");
indexes.insert(pos, key);
}
node->setFieldV256(sfIndexes, indexes);
view.update(node);
return page;
}
std::optional<std::uint64_t>
insertPage(
ApplyView& view,
std::uint64_t page,
SLE::pointer node,
std::uint64_t nextPage,
SLE::ref next,
uint256 const& key,
Keylet const& directory,
std::function<void(std::shared_ptr<SLE> const&)> const& describe)
{
// Check whether we're out of pages.
if (++page >= dirNodeMaxPages)
{
return std::nullopt;
}
// We are about to create a new node; we'll link it to
// the chain first:
node->setFieldU64(sfIndexNext, page);
view.update(node);
next->setFieldU64(sfIndexPrevious, page);
view.update(next);
// Insert the new key:
STVector256 indexes;
indexes.push_back(key);
node = std::make_shared<SLE>(keylet::page(directory, page));
node->setFieldH256(sfRootIndex, directory.key);
node->setFieldV256(sfIndexes, indexes);
// Save some space by not specifying the value 0 since
// it's the default.
if (page != 1)
node->setFieldU64(sfIndexPrevious, page - 1);
if (nextPage)
node->setFieldU64(sfIndexNext, nextPage);
describe(node);
view.insert(node);
return page;
}
} // namespace directory
std::optional<std::uint64_t> std::optional<std::uint64_t>
ApplyView::dirAdd( ApplyView::dirAdd(
bool preserveOrder, bool preserveOrder,
@@ -158,21 +39,102 @@ ApplyView::dirAdd(
if (!root) if (!root)
{ {
// No root, make it. // No root, make it.
return directory::createRoot(*this, directory, key, describe); root = std::make_shared<SLE>(directory);
root->setFieldH256(sfRootIndex, directory.key);
describe(root);
STVector256 v;
v.push_back(key);
root->setFieldV256(sfIndexes, v);
insert(root);
return std::uint64_t{0};
} }
auto [page, node, indexes] = std::uint64_t page = root->getFieldU64(sfIndexPrevious);
directory::findPreviousPage(*this, directory, root);
auto node = root;
if (page)
{
node = peek(keylet::page(directory, page));
if (!node)
LogicError("Directory chain: root back-pointer broken.");
}
auto indexes = node->getFieldV256(sfIndexes);
// If there's space, we use it: // If there's space, we use it:
if (indexes.size() < dirNodeMaxEntries) if (indexes.size() < dirNodeMaxEntries)
{ {
return directory::insertKey( if (preserveOrder)
*this, node, page, preserveOrder, indexes, key); {
if (std::find(indexes.begin(), indexes.end(), key) != indexes.end())
LogicError("dirInsert: double insertion");
indexes.push_back(key);
}
else
{
// We can't be sure if this page is already sorted because
// it may be a legacy page we haven't yet touched. Take
// the time to sort it.
std::sort(indexes.begin(), indexes.end());
auto pos = std::lower_bound(indexes.begin(), indexes.end(), key);
if (pos != indexes.end() && key == *pos)
LogicError("dirInsert: double insertion");
indexes.insert(pos, key);
}
node->setFieldV256(sfIndexes, indexes);
update(node);
return page;
} }
return directory::insertPage( // We rely on modulo arithmetic of unsigned integers (guaranteed in
*this, page, node, 0, root, key, directory, describe); // [basic.fundamental] paragraph 2) to detect page representation overflow.
// For signed integers this would be UB, hence static_assert here.
static_assert(std::is_unsigned_v<decltype(page)>);
// Defensive check against breaking changes in compiler.
static_assert([]<typename T>(std::type_identity<T>) constexpr -> T {
T tmp = std::numeric_limits<T>::max();
return ++tmp;
}(std::type_identity<decltype(page)>{}) == 0);
++page;
// Check whether we're out of pages.
if (page == 0)
return std::nullopt;
if (!rules().enabled(fixDirectoryLimit) &&
page >= dirNodeMaxPages) // Old pages limit
return std::nullopt;
// We are about to create a new node; we'll link it to
// the chain first:
node->setFieldU64(sfIndexNext, page);
update(node);
root->setFieldU64(sfIndexPrevious, page);
update(root);
// Insert the new key:
indexes.clear();
indexes.push_back(key);
node = std::make_shared<SLE>(keylet::page(directory, page));
node->setFieldH256(sfRootIndex, directory.key);
node->setFieldV256(sfIndexes, indexes);
// Save some space by not specifying the value 0 since
// it's the default.
if (page != 1)
node->setFieldU64(sfIndexPrevious, page - 1);
describe(node);
insert(node);
return page;
} }
bool bool

View File

@@ -383,99 +383,6 @@ isLPTokenFrozen(
isFrozen(view, account, asset2.currency, asset2.account); isFrozen(view, account, asset2.currency, asset2.account);
} }
static SLE::const_pointer
getLineIfUsable(
ReadView const& view,
AccountID const& account,
Currency const& currency,
AccountID const& issuer,
FreezeHandling zeroIfFrozen,
beast::Journal j)
{
auto const sle = view.read(keylet::line(account, issuer, currency));
if (!sle)
{
return nullptr;
}
if (zeroIfFrozen == fhZERO_IF_FROZEN)
{
if (isFrozen(view, account, currency, issuer) ||
isDeepFrozen(view, account, currency, issuer))
{
return nullptr;
}
// when fixFrozenLPTokenTransfer is enabled, if currency is lptoken,
// we need to check if the associated assets have been frozen
if (view.rules().enabled(fixFrozenLPTokenTransfer))
{
auto const sleIssuer = view.read(keylet::account(issuer));
if (!sleIssuer)
{
return nullptr; // LCOV_EXCL_LINE
}
else if (sleIssuer->isFieldPresent(sfAMMID))
{
auto const sleAmm =
view.read(keylet::amm((*sleIssuer)[sfAMMID]));
if (!sleAmm ||
isLPTokenFrozen(
view,
account,
(*sleAmm)[sfAsset].get<Issue>(),
(*sleAmm)[sfAsset2].get<Issue>()))
{
return nullptr;
}
}
}
}
return sle;
}
static STAmount
getTrustLineBalance(
ReadView const& view,
SLE::const_ref sle,
AccountID const& account,
Currency const& currency,
AccountID const& issuer,
bool includeOppositeLimit,
beast::Journal j)
{
STAmount amount;
if (sle)
{
amount = sle->getFieldAmount(sfBalance);
bool const accountHigh = account > issuer;
auto const& oppositeField = accountHigh ? sfLowLimit : sfHighLimit;
if (accountHigh)
{
// Put balance in account terms.
amount.negate();
}
if (includeOppositeLimit)
{
amount += sle->getFieldAmount(oppositeField);
}
amount.setIssuer(issuer);
}
else
{
amount.clear(Issue{currency, issuer});
}
JLOG(j.trace()) << "getTrustLineBalance:"
<< " account=" << to_string(account)
<< " amount=" << amount.getFullText();
return view.balanceHook(account, issuer, amount);
}
STAmount STAmount
accountHolds( accountHolds(
ReadView const& view, ReadView const& view,
@@ -492,10 +399,71 @@ accountHolds(
} }
// IOU: Return balance on trust line modulo freeze // IOU: Return balance on trust line modulo freeze
SLE::const_pointer const sle = auto const sle = view.read(keylet::line(account, issuer, currency));
getLineIfUsable(view, account, currency, issuer, zeroIfFrozen, j); auto const allowBalance = [&]() {
if (!sle)
{
return false;
}
return getTrustLineBalance(view, sle, account, currency, issuer, false, j); if (zeroIfFrozen == fhZERO_IF_FROZEN)
{
if (isFrozen(view, account, currency, issuer) ||
isDeepFrozen(view, account, currency, issuer))
{
return false;
}
// when fixFrozenLPTokenTransfer is enabled, if currency is lptoken,
// we need to check if the associated assets have been frozen
if (view.rules().enabled(fixFrozenLPTokenTransfer))
{
auto const sleIssuer = view.read(keylet::account(issuer));
if (!sleIssuer)
{
return false; // LCOV_EXCL_LINE
}
else if (sleIssuer->isFieldPresent(sfAMMID))
{
auto const sleAmm =
view.read(keylet::amm((*sleIssuer)[sfAMMID]));
if (!sleAmm ||
isLPTokenFrozen(
view,
account,
(*sleAmm)[sfAsset].get<Issue>(),
(*sleAmm)[sfAsset2].get<Issue>()))
{
return false;
}
}
}
}
return true;
}();
if (allowBalance)
{
amount = sle->getFieldAmount(sfBalance);
if (account > issuer)
{
// Put balance in account terms.
amount.negate();
}
amount.setIssuer(issuer);
}
else
{
amount.clear(Issue{currency, issuer});
}
JLOG(j.trace()) << "accountHolds:"
<< " account=" << to_string(account)
<< " amount=" << amount.getFullText();
return view.balanceHook(account, issuer, amount);
} }
STAmount STAmount
@@ -582,96 +550,6 @@ accountHolds(
asset.value()); asset.value());
} }
STAmount
accountCanSend(
ReadView const& view,
AccountID const& account,
Currency const& currency,
AccountID const& issuer,
FreezeHandling zeroIfFrozen,
beast::Journal j)
{
if (isXRP(currency))
return accountHolds(view, account, currency, issuer, zeroIfFrozen, j);
if (account == issuer)
// If the account is the issuer, then their limit is effectively
// infinite
return STAmount{
Issue{currency, issuer}, STAmount::cMaxValue, STAmount::cMaxOffset};
// IOU: Return balance on trust line modulo freeze
SLE::const_pointer const sle =
getLineIfUsable(view, account, currency, issuer, zeroIfFrozen, j);
return getTrustLineBalance(view, sle, account, currency, issuer, true, j);
}
STAmount
accountCanSend(
ReadView const& view,
AccountID const& account,
Issue const& issue,
FreezeHandling zeroIfFrozen,
beast::Journal j)
{
return accountCanSend(
view, account, issue.currency, issue.account, zeroIfFrozen, j);
}
STAmount
accountCanSend(
ReadView const& view,
AccountID const& account,
MPTIssue const& mptIssue,
FreezeHandling zeroIfFrozen,
AuthHandling zeroIfUnauthorized,
beast::Journal j)
{
if (account == mptIssue.getIssuer())
{
// if the account is the issuer, and the issuance exists, their limit is
// the issuance limit minus the outstanding value
auto const issuance =
view.read(keylet::mptIssuance(mptIssue.getMptID()));
if (!issuance)
{
return STAmount{mptIssue};
}
return STAmount{
mptIssue,
issuance->at(~sfMaximumAmount).value_or(maxMPTokenAmount) -
issuance->at(sfOutstandingAmount)};
}
return accountHolds(
view, account, mptIssue, zeroIfFrozen, zeroIfUnauthorized, j);
}
[[nodiscard]] STAmount
accountCanSend(
ReadView const& view,
AccountID const& account,
Asset const& asset,
FreezeHandling zeroIfFrozen,
AuthHandling zeroIfUnauthorized,
beast::Journal j)
{
return std::visit(
[&](auto const& value) {
if constexpr (std::is_same_v<
std::remove_cvref_t<decltype(value)>,
Issue>)
{
return accountCanSend(view, account, value, zeroIfFrozen, j);
}
return accountCanSend(
view, account, value, zeroIfFrozen, zeroIfUnauthorized, j);
},
asset.value());
}
STAmount STAmount
accountFunds( accountFunds(
ReadView const& view, ReadView const& view,
@@ -1177,17 +1055,13 @@ describeOwnerDir(AccountID const& account)
} }
TER TER
dirLink( dirLink(ApplyView& view, AccountID const& owner, std::shared_ptr<SLE>& object)
ApplyView& view,
AccountID const& owner,
std::shared_ptr<SLE>& object,
SF_UINT64 const& node)
{ {
auto const page = view.dirInsert( auto const page = view.dirInsert(
keylet::ownerDir(owner), object->key(), describeOwnerDir(owner)); keylet::ownerDir(owner), object->key(), describeOwnerDir(owner));
if (!page) if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE return tecDIR_FULL; // LCOV_EXCL_LINE
object->setFieldU64(node, *page); object->setFieldU64(sfOwnerNode, *page);
return tesSUCCESS; return tesSUCCESS;
} }
@@ -1260,8 +1134,7 @@ createPseudoAccount(
uint256 const& pseudoOwnerKey, uint256 const& pseudoOwnerKey,
SField const& ownerField) SField const& ownerField)
{ {
[[maybe_unused]] [[maybe_unused]] auto const& fields = getPseudoAccountFields();
auto const& fields = getPseudoAccountFields();
XRPL_ASSERT( XRPL_ASSERT(
std::count_if( std::count_if(
fields.begin(), fields.begin(),
@@ -1283,10 +1156,9 @@ createPseudoAccount(
// Pseudo-accounts can't submit transactions, so set the sequence number // Pseudo-accounts can't submit transactions, so set the sequence number
// to 0 to make them easier to spot and verify, and add an extra level // to 0 to make them easier to spot and verify, and add an extra level
// of protection. // of protection.
std::uint32_t const seqno = // std::uint32_t const seqno = //
view.rules().enabled(featureSingleAssetVault) || // view.rules().enabled(featureSingleAssetVault) //
view.rules().enabled(featureLendingProtocol) // ? 0 //
? 0 //
: view.seq(); : view.seq();
account->setFieldU32(sfSequence, seqno); account->setFieldU32(sfSequence, seqno);
// Ignore reserves requirement, disable the master key, allow default // Ignore reserves requirement, disable the master key, allow default
@@ -1340,64 +1212,6 @@ canAddHolding(ReadView const& view, Asset const& asset)
asset.value()); asset.value());
} }
[[nodiscard]] TER
checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag)
{
if (toSle == nullptr)
return tecNO_DST;
// The tag is basically account-specific information we don't
// understand, but we can require someone to fill it in.
if (toSle->isFlag(lsfRequireDestTag) && !hasDestinationTag)
return tecDST_TAG_NEEDED; // Cannot send without a tag
return tesSUCCESS;
}
[[nodiscard]] TER
canWithdraw(
AccountID const& from,
ReadView const& view,
AccountID const& to,
SLE::const_ref toSle,
bool hasDestinationTag)
{
if (auto const ret = checkDestinationAndTag(toSle, hasDestinationTag))
return ret;
if (from == to)
return tesSUCCESS;
if (toSle->isFlag(lsfDepositAuth))
{
if (!view.exists(keylet::depositPreauth(to, from)))
return tecNO_PERMISSION;
}
return tesSUCCESS;
}
[[nodiscard]] TER
canWithdraw(
AccountID const& from,
ReadView const& view,
AccountID const& to,
bool hasDestinationTag)
{
auto const toSle = view.read(keylet::account(to));
return canWithdraw(from, view, to, toSle, hasDestinationTag);
}
[[nodiscard]] TER
canWithdraw(ReadView const& view, STTx const& tx)
{
auto const from = tx[sfAccount];
auto const to = tx[~sfDestination].value_or(from);
return canWithdraw(from, view, to, tx.isFieldPresent(sfDestinationTag));
}
[[nodiscard]] TER [[nodiscard]] TER
addEmptyHolding( addEmptyHolding(
ApplyView& view, ApplyView& view,
@@ -1406,8 +1220,8 @@ addEmptyHolding(
Issue const& issue, Issue const& issue,
beast::Journal journal) beast::Journal journal)
{ {
// Every account can hold XRP. An issuer can issue directly. // Every account can hold XRP.
if (issue.native() || accountID == issue.getIssuer()) if (issue.native())
return tesSUCCESS; return tesSUCCESS;
auto const& issuerId = issue.getIssuer(); auto const& issuerId = issue.getIssuer();
@@ -1468,8 +1282,6 @@ addEmptyHolding(
return tefINTERNAL; // LCOV_EXCL_LINE return tefINTERNAL; // LCOV_EXCL_LINE
if (view.peek(keylet::mptoken(mptID, accountID))) if (view.peek(keylet::mptoken(mptID, accountID)))
return tecDUPLICATE; return tecDUPLICATE;
if (accountID == mptIssue.getIssuer())
return tesSUCCESS;
return authorizeMPToken(view, priorBalance, mptID, accountID, journal); return authorizeMPToken(view, priorBalance, mptID, accountID, journal);
} }
@@ -1533,18 +1345,6 @@ authorizeMPToken(
if (priorBalance < reserveCreate) if (priorBalance < reserveCreate)
return tecINSUFFICIENT_RESERVE; return tecINSUFFICIENT_RESERVE;
// Defensive check before we attempt to create MPToken for the issuer
auto const mpt = view.read(keylet::mptIssuance(mptIssuanceID));
if (!mpt || mpt->getAccountID(sfIssuer) == account)
{
// LCOV_EXCL_START
UNREACHABLE(
"ripple::authorizeMPToken : invalid issuance or issuers token");
if (view.rules().enabled(featureLendingProtocol))
return tecINTERNAL;
// LCOV_EXCL_STOP
}
auto const mptokenKey = keylet::mptoken(mptIssuanceID, account); auto const mptokenKey = keylet::mptoken(mptIssuanceID, account);
auto mptoken = std::make_shared<SLE>(mptokenKey); auto mptoken = std::make_shared<SLE>(mptokenKey);
if (auto ter = dirLink(view, account, mptoken)) if (auto ter = dirLink(view, account, mptoken))
@@ -1620,14 +1420,6 @@ trustCreate(
auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID; auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID;
auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID; auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID;
if (uLowAccountID == uHighAccountID)
{
// LCOV_EXCL_START
UNREACHABLE("ripple::trustCreate : trust line to self");
if (view.rules().enabled(featureLendingProtocol))
return tecINTERNAL;
// LCOV_EXCL_STOP
}
auto const sleRippleState = std::make_shared<SLE>(ltRIPPLE_STATE, uIndex); auto const sleRippleState = std::make_shared<SLE>(ltRIPPLE_STATE, uIndex);
view.insert(sleRippleState); view.insert(sleRippleState);
@@ -2118,87 +1910,6 @@ rippleSendIOU(
return terResult; return terResult;
} }
// Send regardless of limits.
// --> receivers: Amount/currency/issuer to deliver to receivers.
// <-- saActual: Amount actually cost to sender. Sender pays fees.
static TER
rippleSendMultiIOU(
ApplyView& view,
AccountID const& senderID,
Asset const& asset,
MultiplePaymentDestinations const& receivers,
STAmount& actual,
beast::Journal j,
WaiveTransferFee waiveFee)
{
auto const issuer = asset.getIssuer();
XRPL_ASSERT(
!isXRP(senderID), "ripple::rippleSendMultiIOU : sender is not XRP");
// These may diverge
STAmount takeFromSender{asset};
actual = takeFromSender;
// Failures return immediately.
for (auto const& r : receivers)
{
auto const& receiverID = r.first;
STAmount amount{asset, r.second};
/* If we aren't sending anything or if the sender is the same as the
* receiver then we don't need to do anything.
*/
if (!amount || (senderID == receiverID))
continue;
XRPL_ASSERT(
!isXRP(receiverID),
"ripple::rippleSendMultiIOU : receiver is not XRP");
if (senderID == issuer || receiverID == issuer || issuer == noAccount())
{
// Direct send: redeeming IOUs and/or sending own IOUs.
if (auto const ter = rippleCreditIOU(
view, senderID, receiverID, amount, false, j))
return ter;
actual += amount;
// Do not add amount to takeFromSender, because rippleCreditIOU took
// it.
continue;
}
// Sending 3rd party IOUs: transit.
// Calculate the amount to transfer accounting
// for any transfer fees if the fee is not waived:
STAmount actualSend = (waiveFee == WaiveTransferFee::Yes)
? amount
: multiply(amount, transferRate(view, issuer));
actual += actualSend;
takeFromSender += actualSend;
JLOG(j.debug()) << "rippleSendMultiIOU> " << to_string(senderID)
<< " - > " << to_string(receiverID)
<< " : deliver=" << amount.getFullText()
<< " cost=" << actual.getFullText();
if (TER const terResult =
rippleCreditIOU(view, issuer, receiverID, amount, true, j))
return terResult;
}
if (senderID != issuer && takeFromSender)
{
if (TER const terResult = rippleCreditIOU(
view, senderID, issuer, takeFromSender, true, j))
return terResult;
}
return tesSUCCESS;
}
static TER static TER
accountSendIOU( accountSendIOU(
ApplyView& view, ApplyView& view,
@@ -2323,165 +2034,6 @@ accountSendIOU(
return terResult; return terResult;
} }
static TER
accountSendMultiIOU(
ApplyView& view,
AccountID const& senderID,
Asset const& asset,
MultiplePaymentDestinations const& receivers,
beast::Journal j,
WaiveTransferFee waiveFee)
{
XRPL_ASSERT_PARTS(
receivers.size() > 1,
"ripple::accountSendMultiIOU",
"multiple recipients provided");
if (view.rules().enabled(fixAMMv1_1))
{
if (asset.holds<MPTIssue>())
{
return tecINTERNAL;
}
}
else
{
XRPL_ASSERT(
!asset.holds<MPTIssue>(), "ripple::accountSendMultiIOU : not MPT");
}
if (!asset.native())
{
STAmount actual;
JLOG(j.trace()) << "accountSendMultiIOU: " << to_string(senderID)
<< " sending " << receivers.size() << " IOUs";
return rippleSendMultiIOU(
view, senderID, asset, receivers, actual, j, waiveFee);
}
/* XRP send which does not check reserve and can do pure adjustment.
* Note that sender or receiver may be null and this not a mistake; this
* setup could be used during pathfinding and it is carefully controlled to
* ensure that transfers are balanced.
*/
SLE::pointer sender = senderID != beast::zero
? view.peek(keylet::account(senderID))
: SLE::pointer();
if (auto stream = j.trace())
{
std::string sender_bal("-");
if (sender)
sender_bal = sender->getFieldAmount(sfBalance).getFullText();
stream << "accountSendMultiIOU> " << to_string(senderID) << " ("
<< sender_bal << ") -> " << receivers.size() << " receivers.";
}
// Failures return immediately.
STAmount takeFromSender{asset};
for (auto const& r : receivers)
{
auto const& receiverID = r.first;
STAmount amount{asset, r.second};
takeFromSender += amount;
if (view.rules().enabled(fixAMMv1_1))
{
if (amount < beast::zero)
{
return tecINTERNAL;
}
}
else
{
XRPL_ASSERT(
amount >= beast::zero,
"ripple::accountSendMultiIOU : minimum amount");
}
/* If we aren't sending anything or if the sender is the same as the
* receiver then we don't need to do anything.
*/
if (!amount || (senderID == receiverID))
continue;
SLE::pointer receiver = receiverID != beast::zero
? view.peek(keylet::account(receiverID))
: SLE::pointer();
if (auto stream = j.trace())
{
std::string receiver_bal("-");
if (receiver)
receiver_bal =
receiver->getFieldAmount(sfBalance).getFullText();
stream << "accountSendMultiIOU> " << to_string(senderID) << " -> "
<< to_string(receiverID) << " (" << receiver_bal
<< ") : " << amount.getFullText();
}
if (receiver)
{
// Increment XRP balance.
auto const rcvBal = receiver->getFieldAmount(sfBalance);
receiver->setFieldAmount(sfBalance, rcvBal + amount);
view.creditHook(xrpAccount(), receiverID, amount, -rcvBal);
view.update(receiver);
}
if (auto stream = j.trace())
{
std::string receiver_bal("-");
if (receiver)
receiver_bal =
receiver->getFieldAmount(sfBalance).getFullText();
stream << "accountSendMultiIOU< " << to_string(senderID) << " -> "
<< to_string(receiverID) << " (" << receiver_bal
<< ") : " << amount.getFullText();
}
}
if (sender)
{
if (sender->getFieldAmount(sfBalance) < takeFromSender)
{
return TER{tecFAILED_PROCESSING};
}
else
{
auto const sndBal = sender->getFieldAmount(sfBalance);
view.creditHook(senderID, xrpAccount(), takeFromSender, sndBal);
// Decrement XRP balance.
sender->setFieldAmount(sfBalance, sndBal - takeFromSender);
view.update(sender);
}
}
if (auto stream = j.trace())
{
std::string sender_bal("-");
std::string receiver_bal("-");
if (sender)
sender_bal = sender->getFieldAmount(sfBalance).getFullText();
stream << "accountSendMultiIOU< " << to_string(senderID) << " ("
<< sender_bal << ") -> " << receivers.size() << " receivers.";
}
return tesSUCCESS;
}
static TER static TER
rippleCreditMPT( rippleCreditMPT(
ApplyView& view, ApplyView& view,
@@ -2610,102 +2162,6 @@ rippleSendMPT(
return rippleCreditMPT(view, uSenderID, issuer, saActual, j); return rippleCreditMPT(view, uSenderID, issuer, saActual, j);
} }
static TER
rippleSendMultiMPT(
ApplyView& view,
AccountID const& senderID,
Asset const& asset,
MultiplePaymentDestinations const& receivers,
STAmount& actual,
beast::Journal j,
WaiveTransferFee waiveFee)
{
// Safe to get MPT since rippleSendMultiMPT is only called by
// accountSendMultiMPT
auto const issuer = asset.getIssuer();
auto const sle =
view.read(keylet::mptIssuance(asset.get<MPTIssue>().getMptID()));
if (!sle)
return tecOBJECT_NOT_FOUND;
// These may diverge
STAmount takeFromSender{asset};
actual = takeFromSender;
for (auto const& r : receivers)
{
auto const& receiverID = r.first;
STAmount amount{asset, r.second};
XRPL_ASSERT(
senderID != receiverID,
"ripple::rippleSendMultiMPT : sender is not receiver");
XRPL_ASSERT(
amount >= beast::zero,
"ripple::rippleSendMultiMPT : minimum amount ");
/* If we aren't sending anything or if the sender is the same as the
* receiver then we don't need to do anything.
*/
if (!amount || (senderID == receiverID))
continue;
if (senderID == issuer || receiverID == issuer)
{
// if sender is issuer, check that the new OutstandingAmount will
// not exceed MaximumAmount
if (senderID == issuer)
{
auto const sendAmount = amount.mpt().value();
auto const maximumAmount =
sle->at(~sfMaximumAmount).value_or(maxMPTokenAmount);
if (sendAmount > maximumAmount - takeFromSender ||
sle->getFieldU64(sfOutstandingAmount) >
maximumAmount - sendAmount - takeFromSender)
return tecPATH_DRY;
}
// Direct send: redeeming MPTs and/or sending own MPTs.
if (auto const ter =
rippleCreditMPT(view, senderID, receiverID, amount, j))
return ter;
actual += amount;
// Do not add amount to takeFromSender, because rippleCreditMPT took
// it
continue;
}
// Sending 3rd party MPTs: transit.
STAmount actualSend = (waiveFee == WaiveTransferFee::Yes)
? amount
: multiply(
amount,
transferRate(view, amount.get<MPTIssue>().getMptID()));
actual += actualSend;
takeFromSender += actualSend;
JLOG(j.debug()) << "rippleSendMultiMPT> " << to_string(senderID)
<< " - > " << to_string(receiverID)
<< " : deliver=" << amount.getFullText()
<< " cost=" << actualSend.getFullText();
if (auto const terResult =
rippleCreditMPT(view, issuer, receiverID, amount, j))
return terResult;
}
if (senderID != issuer && takeFromSender)
{
if (TER const terResult =
rippleCreditMPT(view, senderID, issuer, takeFromSender, j))
return terResult;
}
return tesSUCCESS;
}
static TER static TER
accountSendMPT( accountSendMPT(
ApplyView& view, ApplyView& view,
@@ -2731,23 +2187,6 @@ accountSendMPT(
view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee); view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee);
} }
static TER
accountSendMultiMPT(
ApplyView& view,
AccountID const& senderID,
Asset const& asset,
MultiplePaymentDestinations const& receivers,
beast::Journal j,
WaiveTransferFee waiveFee)
{
XRPL_ASSERT(asset.holds<MPTIssue>(), "ripple::accountSendMultiMPT : MPT");
STAmount actual;
return rippleSendMultiMPT(
view, senderID, asset, receivers, actual, j, waiveFee);
}
TER TER
accountSend( accountSend(
ApplyView& view, ApplyView& view,
@@ -2769,31 +2208,6 @@ accountSend(
saAmount.asset().value()); saAmount.asset().value());
} }
TER
accountSendMulti(
ApplyView& view,
AccountID const& senderID,
Asset const& asset,
MultiplePaymentDestinations const& receivers,
beast::Journal j,
WaiveTransferFee waiveFee)
{
XRPL_ASSERT_PARTS(
receivers.size() > 1,
"ripple::accountSendMulti",
"multiple recipients provided");
return std::visit(
[&]<ValidIssueType TIss>(TIss const& issue) {
if constexpr (std::is_same_v<TIss, Issue>)
return accountSendMultiIOU(
view, senderID, asset, receivers, j, waiveFee);
else
return accountSendMultiMPT(
view, senderID, asset, receivers, j, waiveFee);
},
asset.value());
}
static bool static bool
updateTrustLine( updateTrustLine(
ApplyView& view, ApplyView& view,

View File

@@ -17,7 +17,7 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/nodestore/detail/BatchWriter.h> #include <xrpl/nodestore/detail/BatchWriter.h>
namespace ripple { namespace ripple {
namespace NodeStore { namespace NodeStore {

View File

@@ -17,11 +17,10 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/nodestore/Database.h>
#include <xrpl/basics/chrono.h> #include <xrpl/basics/chrono.h>
#include <xrpl/beast/core/CurrentThreadName.h> #include <xrpl/beast/core/CurrentThreadName.h>
#include <xrpl/json/json_value.h> #include <xrpl/json/json_value.h>
#include <xrpl/nodestore/Database.h>
#include <xrpl/protocol/HashPrefix.h> #include <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/jss.h> #include <xrpl/protocol/jss.h>

View File

@@ -17,7 +17,7 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/nodestore/detail/DatabaseNodeImp.h> #include <xrpl/nodestore/detail/DatabaseNodeImp.h>
namespace ripple { namespace ripple {
namespace NodeStore { namespace NodeStore {

View File

@@ -17,7 +17,7 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/nodestore/detail/DatabaseRotatingImp.h> #include <xrpl/nodestore/detail/DatabaseRotatingImp.h>
namespace ripple { namespace ripple {
namespace NodeStore { namespace NodeStore {

View File

@@ -17,10 +17,9 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/nodestore/detail/DecodedBlob.h>
#include <xrpl/basics/safe_cast.h> #include <xrpl/basics/safe_cast.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/nodestore/detail/DecodedBlob.h>
#include <algorithm> #include <algorithm>

View File

@@ -17,7 +17,7 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/nodestore/DummyScheduler.h> #include <xrpl/nodestore/DummyScheduler.h>
namespace ripple { namespace ripple {
namespace NodeStore { namespace NodeStore {

View File

@@ -17,8 +17,8 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/nodestore/detail/DatabaseNodeImp.h> #include <xrpl/nodestore/detail/DatabaseNodeImp.h>
#include <xrpld/nodestore/detail/ManagerImp.h> #include <xrpl/nodestore/detail/ManagerImp.h>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
@@ -41,6 +41,27 @@ ManagerImp::missing_backend()
"please see the rippled-example.cfg file!"); "please see the rippled-example.cfg file!");
} }
// We shouldn't rely on global variables for lifetime management because their
// lifetime is not well-defined. ManagerImp may get destroyed before the Factory
// classes, and then, calling Manager::instance().erase() in the destructors of
// the Factory classes is an undefined behaviour.
void
registerNuDBFactory(Manager& manager);
void
registerRocksDBFactory(Manager& manager);
void
registerNullFactory(Manager& manager);
void
registerMemoryFactory(Manager& manager);
ManagerImp::ManagerImp()
{
registerNuDBFactory(*this);
registerRocksDBFactory(*this);
registerNullFactory(*this);
registerMemoryFactory(*this);
}
std::unique_ptr<Backend> std::unique_ptr<Backend>
ManagerImp::make_Backend( ManagerImp::make_Backend(
Section const& parameters, Section const& parameters,

View File

@@ -17,7 +17,7 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/nodestore/NodeObject.h> #include <xrpl/nodestore/NodeObject.h>
#include <memory> #include <memory>

View File

@@ -17,10 +17,9 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/nodestore/Factory.h>
#include <xrpld/nodestore/Manager.h>
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#include <xrpl/nodestore/Factory.h>
#include <xrpl/nodestore/Manager.h>
#include <boost/beast/core/string.hpp> #include <boost/beast/core/string.hpp>
#include <boost/core/ignore_unused.hpp> #include <boost/core/ignore_unused.hpp>
@@ -46,10 +45,10 @@ class MemoryFactory : public Factory
private: private:
std::mutex mutex_; std::mutex mutex_;
std::map<std::string, MemoryDB, boost::beast::iless> map_; std::map<std::string, MemoryDB, boost::beast::iless> map_;
Manager& manager_;
public: public:
MemoryFactory(); explicit MemoryFactory(Manager& manager);
~MemoryFactory() override;
std::string std::string
getName() const override; getName() const override;
@@ -75,7 +74,14 @@ public:
} }
}; };
static MemoryFactory memoryFactory; MemoryFactory* memoryFactory = nullptr;
void
registerMemoryFactory(Manager& manager)
{
static MemoryFactory instance{manager};
memoryFactory = &instance;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -112,9 +118,9 @@ public:
} }
void void
open(bool createIfMissing) override open(bool) override
{ {
db_ = &memoryFactory.open(name_); db_ = &memoryFactory->open(name_);
} }
bool bool
@@ -219,14 +225,9 @@ public:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
MemoryFactory::MemoryFactory() MemoryFactory::MemoryFactory(Manager& manager) : manager_(manager)
{ {
Manager::instance().insert(*this); manager_.insert(*this);
}
MemoryFactory::~MemoryFactory()
{
Manager::instance().erase(*this);
} }
std::string std::string

View File

@@ -17,15 +17,14 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/nodestore/Factory.h>
#include <xrpld/nodestore/Manager.h>
#include <xrpld/nodestore/detail/DecodedBlob.h>
#include <xrpld/nodestore/detail/EncodedBlob.h>
#include <xrpld/nodestore/detail/codec.h>
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#include <xrpl/beast/core/LexicalCast.h> #include <xrpl/beast/core/LexicalCast.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/nodestore/Factory.h>
#include <xrpl/nodestore/Manager.h>
#include <xrpl/nodestore/detail/DecodedBlob.h>
#include <xrpl/nodestore/detail/EncodedBlob.h>
#include <xrpl/nodestore/detail/codec.h>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
@@ -427,15 +426,13 @@ private:
class NuDBFactory : public Factory class NuDBFactory : public Factory
{ {
public: private:
NuDBFactory() Manager& manager_;
{
Manager::instance().insert(*this);
}
~NuDBFactory() override public:
explicit NuDBFactory(Manager& manager) : manager_(manager)
{ {
Manager::instance().erase(*this); manager_.insert(*this);
} }
std::string std::string
@@ -470,7 +467,11 @@ public:
} }
}; };
static NuDBFactory nuDBFactory; void
registerNuDBFactory(Manager& manager)
{
static NuDBFactory instance{manager};
}
} // namespace NodeStore } // namespace NodeStore
} // namespace ripple } // namespace ripple

View File

@@ -17,8 +17,8 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/nodestore/Factory.h> #include <xrpl/nodestore/Factory.h>
#include <xrpld/nodestore/Manager.h> #include <xrpl/nodestore/Manager.h>
#include <memory> #include <memory>
@@ -111,15 +111,13 @@ private:
class NullFactory : public Factory class NullFactory : public Factory
{ {
public: private:
NullFactory() Manager& manager_;
{
Manager::instance().insert(*this);
}
~NullFactory() override public:
explicit NullFactory(Manager& manager) : manager_(manager)
{ {
Manager::instance().erase(*this); manager_.insert(*this);
} }
std::string std::string
@@ -140,7 +138,11 @@ public:
} }
}; };
static NullFactory nullFactory; void
registerNullFactory(Manager& manager)
{
static NullFactory instance{manager};
}
} // namespace NodeStore } // namespace NodeStore
} // namespace ripple } // namespace ripple

View File

@@ -17,20 +17,18 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/unity/rocksdb.h> #include <xrpl/basics/rocksdb.h>
#if RIPPLE_ROCKSDB_AVAILABLE #if RIPPLE_ROCKSDB_AVAILABLE
#include <xrpld/core/Config.h> // VFALCO Bad dependency
#include <xrpld/nodestore/Factory.h>
#include <xrpld/nodestore/Manager.h>
#include <xrpld/nodestore/detail/BatchWriter.h>
#include <xrpld/nodestore/detail/DecodedBlob.h>
#include <xrpld/nodestore/detail/EncodedBlob.h>
#include <xrpl/basics/ByteUtilities.h> #include <xrpl/basics/ByteUtilities.h>
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#include <xrpl/basics/safe_cast.h> #include <xrpl/basics/safe_cast.h>
#include <xrpl/beast/core/CurrentThreadName.h> #include <xrpl/beast/core/CurrentThreadName.h>
#include <xrpl/nodestore/Factory.h>
#include <xrpl/nodestore/Manager.h>
#include <xrpl/nodestore/detail/BatchWriter.h>
#include <xrpl/nodestore/detail/DecodedBlob.h>
#include <xrpl/nodestore/detail/EncodedBlob.h>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
@@ -461,17 +459,15 @@ public:
class RocksDBFactory : public Factory class RocksDBFactory : public Factory
{ {
private:
Manager& manager_;
public: public:
RocksDBEnv m_env; RocksDBEnv m_env;
RocksDBFactory() RocksDBFactory(Manager& manager) : manager_(manager)
{ {
Manager::instance().insert(*this); manager_.insert(*this);
}
~RocksDBFactory() override
{
Manager::instance().erase(*this);
} }
std::string std::string
@@ -493,7 +489,11 @@ public:
} }
}; };
static RocksDBFactory rocksDBFactory; void
registerRocksDBFactory(Manager& manager)
{
static RocksDBFactory instance{manager};
}
} // namespace NodeStore } // namespace NodeStore
} // namespace ripple } // namespace ripple

View File

@@ -96,8 +96,6 @@ enum class LedgerNameSpace : std::uint16_t {
PERMISSIONED_DOMAIN = 'm', PERMISSIONED_DOMAIN = 'm',
DELEGATE = 'E', DELEGATE = 'E',
VAULT = 'V', VAULT = 'V',
LOAN_BROKER = 'l', // lower-case L
LOAN = 'L',
// No longer used or supported. Left here to reserve the space // No longer used or supported. Left here to reserve the space
// to avoid accidental reuse. // to avoid accidental reuse.
@@ -568,18 +566,6 @@ vault(AccountID const& owner, std::uint32_t seq) noexcept
return vault(indexHash(LedgerNameSpace::VAULT, owner, seq)); return vault(indexHash(LedgerNameSpace::VAULT, owner, seq));
} }
Keylet
loanbroker(AccountID const& owner, std::uint32_t seq) noexcept
{
return loanbroker(indexHash(LedgerNameSpace::LOAN_BROKER, owner, seq));
}
Keylet
loan(uint256 const& loanBrokerID, std::uint32_t loanSeq) noexcept
{
return loan(indexHash(LedgerNameSpace::LOAN, loanBrokerID, loanSeq));
}
Keylet Keylet
permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept
{ {

View File

@@ -172,14 +172,6 @@ InnerObjectFormats::InnerObjectFormats()
{sfBookDirectory, soeREQUIRED}, {sfBookDirectory, soeREQUIRED},
{sfBookNode, soeREQUIRED}, {sfBookNode, soeREQUIRED},
}); });
add(sfCounterpartySignature.jsonName,
sfCounterpartySignature.getCode(),
{
{sfSigningPubKey, soeOPTIONAL},
{sfTxnSignature, soeOPTIONAL},
{sfSigners, soeOPTIONAL},
});
} }
InnerObjectFormats const& InnerObjectFormats const&

View File

@@ -174,21 +174,22 @@ Permission::isDelegatable(
auto const txType = permissionToTxType(permissionValue); auto const txType = permissionToTxType(permissionValue);
auto const it = delegatableTx_.find(txType); auto const it = delegatableTx_.find(txType);
if (rules.enabled(fixDelegateV1_1)) if (it == delegatableTx_.end())
{ return false;
if (it == delegatableTx_.end())
return false;
auto const feature = getTxFeature(txType); auto const txFeaturesIt = txFeatureMap_.find(txType);
XRPL_ASSERT(
txFeaturesIt != txFeatureMap_.end(),
"ripple::Permissions::isDelegatable : tx exists in txFeatureMap_");
// fixDelegateV1_1: Delegation is only allowed if the required amendment // Delegation is only allowed if the required amendment for the transaction
// for the transaction is enabled. For transactions that do not require // is enabled. For transactions that do not require an amendment, delegation
// an amendment, delegation is always allowed. // is always allowed.
if (feature && !rules.enabled(*feature)) if (txFeaturesIt->second != uint256{} &&
return false; !rules.enabled(txFeaturesIt->second))
} return false;
if (it != delegatableTx_.end() && it->second == Delegation::notDelegatable) if (it->second == Delegation::notDelegatable)
return false; return false;
return true; return true;

View File

@@ -298,7 +298,7 @@ STAmount::xrp() const
IOUAmount IOUAmount
STAmount::iou() const STAmount::iou() const
{ {
if (integral()) if (native() || !holds<Issue>())
Throw<std::logic_error>("Cannot return non-IOU STAmount as IOUAmount"); Throw<std::logic_error>("Cannot return non-IOU STAmount as IOUAmount");
auto mantissa = static_cast<std::int64_t>(mValue); auto mantissa = static_cast<std::int64_t>(mValue);
@@ -1480,31 +1480,6 @@ canonicalizeRoundStrict(
} }
} }
STAmount
roundToScale(STAmount value, std::int32_t scale, Number::rounding_mode rounding)
{
// Nothing to do for intgral types.
if (value.integral())
return value;
// If the value's exponent is greater than or equal to the scale, then
// rounding will do nothing, and might even lose precision, so just return
// the value.
if (value.exponent() >= scale)
return value;
STAmount referenceValue{
value.asset(), STAmount::cMinValue, scale, value.negative()};
NumberRoundModeGuard mg(rounding);
// With an IOU, the total will be truncated to the precision of the
// larger value: referenceValue
value += referenceValue;
// Remove the reference value, and we're left with the rounded value.
value -= referenceValue;
return value;
}
namespace { namespace {
// We need a class that has an interface similar to NumberRoundModeGuard // We need a class that has an interface similar to NumberRoundModeGuard

View File

@@ -286,6 +286,7 @@ STTx::checkSign(
if (auto const ret = checkSign(requireCanonicalSig, rules, *this); !ret) if (auto const ret = checkSign(requireCanonicalSig, rules, *this); !ret)
return ret; return ret;
/* Placeholder for field that will be added by Lending Protocol
if (isFieldPresent(sfCounterpartySignature)) if (isFieldPresent(sfCounterpartySignature))
{ {
auto const counterSig = getFieldObject(sfCounterpartySignature); auto const counterSig = getFieldObject(sfCounterpartySignature);
@@ -293,6 +294,7 @@ STTx::checkSign(
!ret) !ret)
return Unexpected("Counterparty: " + ret.error()); return Unexpected("Counterparty: " + ret.error());
} }
*/
return {}; return {};
} }

View File

@@ -127,7 +127,6 @@ transResults()
MAKE_ERROR(tecLIMIT_EXCEEDED, "Limit exceeded."), MAKE_ERROR(tecLIMIT_EXCEEDED, "Limit exceeded."),
MAKE_ERROR(tecPSEUDO_ACCOUNT, "This operation is not allowed against a pseudo-account."), MAKE_ERROR(tecPSEUDO_ACCOUNT, "This operation is not allowed against a pseudo-account."),
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."), MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
MAKE_ERROR(tecNO_DELEGATE_PERMISSION, "Delegated account lacks permission to perform this transaction."),
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."), MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."), MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
@@ -235,6 +234,7 @@ transResults()
MAKE_ERROR(terPRE_TICKET, "Ticket is not yet in ledger."), MAKE_ERROR(terPRE_TICKET, "Ticket is not yet in ledger."),
MAKE_ERROR(terNO_AMM, "AMM doesn't exist for the asset pair."), MAKE_ERROR(terNO_AMM, "AMM doesn't exist for the asset pair."),
MAKE_ERROR(terADDRESS_COLLISION, "Failed to allocate an unique account address."), MAKE_ERROR(terADDRESS_COLLISION, "Failed to allocate an unique account address."),
MAKE_ERROR(terNO_DELEGATE_PERMISSION, "Delegated account lacks permission to perform this transaction."),
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."), MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
}; };

View File

@@ -39,35 +39,13 @@
namespace ripple { namespace ripple {
template <class T>
TxMeta::TxMeta(
uint256 const& txid,
std::uint32_t ledger,
T const& data,
CtorHelper)
: mTransactionID(txid), mLedger(ledger), mNodes(sfAffectedNodes, 32)
{
SerialIter sit(makeSlice(data));
STObject obj(sit, sfMetadata);
mResult = obj.getFieldU8(sfTransactionResult);
mIndex = obj.getFieldU32(sfTransactionIndex);
mNodes = *dynamic_cast<STArray*>(&obj.getField(sfAffectedNodes));
if (obj.isFieldPresent(sfDeliveredAmount))
setDeliveredAmount(obj.getFieldAmount(sfDeliveredAmount));
if (obj.isFieldPresent(sfParentBatchID))
setParentBatchId(obj.getFieldH256(sfParentBatchID));
}
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj) TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj)
: mTransactionID(txid) : transactionID_(txid)
, mLedger(ledger) , ledgerSeq_(ledger)
, mNodes(obj.getFieldArray(sfAffectedNodes)) , nodes_(obj.getFieldArray(sfAffectedNodes))
{ {
mResult = obj.getFieldU8(sfTransactionResult); result_ = obj.getFieldU8(sfTransactionResult);
mIndex = obj.getFieldU32(sfTransactionIndex); index_ = obj.getFieldU32(sfTransactionIndex);
auto affectedNodes = auto affectedNodes =
dynamic_cast<STArray const*>(obj.peekAtPField(sfAffectedNodes)); dynamic_cast<STArray const*>(obj.peekAtPField(sfAffectedNodes));
@@ -75,40 +53,32 @@ TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj)
affectedNodes, affectedNodes,
"ripple::TxMeta::TxMeta(STObject) : type cast succeeded"); "ripple::TxMeta::TxMeta(STObject) : type cast succeeded");
if (affectedNodes) if (affectedNodes)
mNodes = *affectedNodes; nodes_ = *affectedNodes;
if (obj.isFieldPresent(sfDeliveredAmount)) setAdditionalFields(obj);
setDeliveredAmount(obj.getFieldAmount(sfDeliveredAmount));
if (obj.isFieldPresent(sfParentBatchID))
setParentBatchId(obj.getFieldH256(sfParentBatchID));
} }
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, Blob const& vec) TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, Blob const& vec)
: TxMeta(txid, ledger, vec, CtorHelper()) : transactionID_(txid), ledgerSeq_(ledger), nodes_(sfAffectedNodes, 32)
{ {
SerialIter sit(makeSlice(vec));
STObject obj(sit, sfMetadata);
result_ = obj.getFieldU8(sfTransactionResult);
index_ = obj.getFieldU32(sfTransactionIndex);
nodes_ = obj.getFieldArray(sfAffectedNodes);
setAdditionalFields(obj);
} }
TxMeta::TxMeta( TxMeta::TxMeta(uint256 const& transactionID, std::uint32_t ledger)
uint256 const& txid, : transactionID_(transactionID)
std::uint32_t ledger, , ledgerSeq_(ledger)
std::string const& data) , index_(std::numeric_limits<std::uint32_t>::max())
: TxMeta(txid, ledger, data, CtorHelper()) , result_(255)
, nodes_(sfAffectedNodes)
{ {
} nodes_.reserve(32);
TxMeta::TxMeta(
uint256 const& transactionID,
std::uint32_t ledger,
std::optional<uint256> parentBatchId)
: mTransactionID(transactionID)
, mLedger(ledger)
, mIndex(static_cast<std::uint32_t>(-1))
, mResult(255)
, mParentBatchId(parentBatchId)
, mNodes(sfAffectedNodes)
{
mNodes.reserve(32);
} }
void void
@@ -118,7 +88,7 @@ TxMeta::setAffectedNode(
std::uint16_t nodeType) std::uint16_t nodeType)
{ {
// make sure the node exists and force its type // make sure the node exists and force its type
for (auto& n : mNodes) for (auto& n : nodes_)
{ {
if (n.getFieldH256(sfLedgerIndex) == node) if (n.getFieldH256(sfLedgerIndex) == node)
{ {
@@ -128,8 +98,8 @@ TxMeta::setAffectedNode(
} }
} }
mNodes.push_back(STObject(type)); nodes_.push_back(STObject(type));
STObject& obj = mNodes.back(); STObject& obj = nodes_.back();
XRPL_ASSERT( XRPL_ASSERT(
obj.getFName() == type, obj.getFName() == type,
@@ -146,14 +116,15 @@ TxMeta::getAffectedAccounts() const
// This code should match the behavior of the JS method: // This code should match the behavior of the JS method:
// Meta#getAffectedAccounts // Meta#getAffectedAccounts
for (auto const& it : mNodes) for (auto const& node : nodes_)
{ {
int index = it.getFieldIndex( int index = node.getFieldIndex(
(it.getFName() == sfCreatedNode) ? sfNewFields : sfFinalFields); (node.getFName() == sfCreatedNode) ? sfNewFields : sfFinalFields);
if (index != -1) if (index != -1)
{ {
auto inner = dynamic_cast<STObject const*>(&it.peekAtIndex(index)); auto const* inner =
dynamic_cast<STObject const*>(&node.peekAtIndex(index));
XRPL_ASSERT( XRPL_ASSERT(
inner, inner,
"ripple::getAffectedAccounts : STObject type cast succeeded"); "ripple::getAffectedAccounts : STObject type cast succeeded");
@@ -213,13 +184,13 @@ STObject&
TxMeta::getAffectedNode(SLE::ref node, SField const& type) TxMeta::getAffectedNode(SLE::ref node, SField const& type)
{ {
uint256 index = node->key(); uint256 index = node->key();
for (auto& n : mNodes) for (auto& n : nodes_)
{ {
if (n.getFieldH256(sfLedgerIndex) == index) if (n.getFieldH256(sfLedgerIndex) == index)
return n; return n;
} }
mNodes.push_back(STObject(type)); nodes_.push_back(STObject(type));
STObject& obj = mNodes.back(); STObject& obj = nodes_.back();
XRPL_ASSERT( XRPL_ASSERT(
obj.getFName() == type, obj.getFName() == type,
@@ -233,7 +204,7 @@ TxMeta::getAffectedNode(SLE::ref node, SField const& type)
STObject& STObject&
TxMeta::getAffectedNode(uint256 const& node) TxMeta::getAffectedNode(uint256 const& node)
{ {
for (auto& n : mNodes) for (auto& n : nodes_)
{ {
if (n.getFieldH256(sfLedgerIndex) == node) if (n.getFieldH256(sfLedgerIndex) == node)
return n; return n;
@@ -241,7 +212,7 @@ TxMeta::getAffectedNode(uint256 const& node)
// LCOV_EXCL_START // LCOV_EXCL_START
UNREACHABLE("ripple::TxMeta::getAffectedNode(uint256) : node not found"); UNREACHABLE("ripple::TxMeta::getAffectedNode(uint256) : node not found");
Throw<std::runtime_error>("Affected node not found"); Throw<std::runtime_error>("Affected node not found");
return *(mNodes.begin()); // Silence compiler warning. return *(nodes_.begin()); // Silence compiler warning.
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
@@ -249,15 +220,15 @@ STObject
TxMeta::getAsObject() const TxMeta::getAsObject() const
{ {
STObject metaData(sfTransactionMetaData); STObject metaData(sfTransactionMetaData);
XRPL_ASSERT(mResult != 255, "ripple::TxMeta::getAsObject : result is set"); XRPL_ASSERT(result_ != 255, "ripple::TxMeta::getAsObject : result_ is set");
metaData.setFieldU8(sfTransactionResult, mResult); metaData.setFieldU8(sfTransactionResult, result_);
metaData.setFieldU32(sfTransactionIndex, mIndex); metaData.setFieldU32(sfTransactionIndex, index_);
metaData.emplace_back(mNodes); metaData.emplace_back(nodes_);
if (hasDeliveredAmount()) if (deliveredAmount_.has_value())
metaData.setFieldAmount(sfDeliveredAmount, getDeliveredAmount()); metaData.setFieldAmount(sfDeliveredAmount, *deliveredAmount_);
if (hasParentBatchId()) if (parentBatchID_.has_value())
metaData.setFieldH256(sfParentBatchID, getParentBatchId()); metaData.setFieldH256(sfParentBatchID, *parentBatchID_);
return metaData; return metaData;
} }
@@ -265,13 +236,13 @@ TxMeta::getAsObject() const
void void
TxMeta::addRaw(Serializer& s, TER result, std::uint32_t index) TxMeta::addRaw(Serializer& s, TER result, std::uint32_t index)
{ {
mResult = TERtoInt(result); result_ = TERtoInt(result);
mIndex = index; index_ = index;
XRPL_ASSERT( XRPL_ASSERT(
(mResult == 0) || ((mResult > 100) && (mResult <= 255)), (result_ == 0) || ((result_ > 100) && (result_ <= 255)),
"ripple::TxMeta::addRaw : valid TER input"); "ripple::TxMeta::addRaw : valid TER input");
mNodes.sort([](STObject const& o1, STObject const& o2) { nodes_.sort([](STObject const& o1, STObject const& o2) {
return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex); return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex);
}); });

View File

@@ -17,15 +17,14 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/shamap/SHAMap.h>
#include <xrpld/shamap/SHAMapAccountStateLeafNode.h>
#include <xrpld/shamap/SHAMapNodeID.h>
#include <xrpld/shamap/SHAMapSyncFilter.h>
#include <xrpld/shamap/SHAMapTxLeafNode.h>
#include <xrpld/shamap/SHAMapTxPlusMetaLeafNode.h>
#include <xrpl/basics/TaggedCache.ipp> #include <xrpl/basics/TaggedCache.ipp>
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#include <xrpl/shamap/SHAMap.h>
#include <xrpl/shamap/SHAMapAccountStateLeafNode.h>
#include <xrpl/shamap/SHAMapNodeID.h>
#include <xrpl/shamap/SHAMapSyncFilter.h>
#include <xrpl/shamap/SHAMapTxLeafNode.h>
#include <xrpl/shamap/SHAMapTxPlusMetaLeafNode.h>
namespace ripple { namespace ripple {

View File

@@ -17,10 +17,9 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/shamap/SHAMap.h>
#include <xrpl/basics/IntrusivePointer.ipp> #include <xrpl/basics/IntrusivePointer.ipp>
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#include <xrpl/shamap/SHAMap.h>
#include <array> #include <array>
#include <stack> #include <stack>

View File

@@ -17,16 +17,15 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/shamap/SHAMapInnerNode.h>
#include <xrpld/shamap/SHAMapTreeNode.h>
#include <xrpld/shamap/detail/TaggedPointer.ipp>
#include <xrpl/basics/IntrusivePointer.ipp> #include <xrpl/basics/IntrusivePointer.ipp>
#include <xrpl/basics/Slice.h> #include <xrpl/basics/Slice.h>
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#include <xrpl/basics/spinlock.h> #include <xrpl/basics/spinlock.h>
#include <xrpl/protocol/HashPrefix.h> #include <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/digest.h> #include <xrpl/protocol/digest.h>
#include <xrpl/shamap/SHAMapInnerNode.h>
#include <xrpl/shamap/SHAMapTreeNode.h>
#include <xrpl/shamap/detail/TaggedPointer.ipp>
namespace ripple { namespace ripple {

View File

@@ -17,7 +17,7 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/shamap/SHAMapLeafNode.h> #include <xrpl/shamap/SHAMapLeafNode.h>
namespace ripple { namespace ripple {

View File

@@ -17,12 +17,11 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/shamap/SHAMap.h>
#include <xrpld/shamap/SHAMapNodeID.h>
#include <xrpl/beast/core/LexicalCast.h> #include <xrpl/beast/core/LexicalCast.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/Serializer.h> #include <xrpl/protocol/Serializer.h>
#include <xrpl/shamap/SHAMap.h>
#include <xrpl/shamap/SHAMapNodeID.h>
namespace ripple { namespace ripple {

View File

@@ -17,10 +17,10 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/shamap/SHAMap.h>
#include <xrpld/shamap/SHAMapSyncFilter.h>
#include <xrpl/basics/random.h> #include <xrpl/basics/random.h>
#include <xrpl/shamap/SHAMap.h>
#include <xrpl/shamap/SHAMapLeafNode.h>
#include <xrpl/shamap/SHAMapSyncFilter.h>
namespace ripple { namespace ripple {
@@ -591,16 +591,16 @@ SHAMap::addKnownNode(
} }
auto const generation = f_.getFullBelowCache()->getGeneration(); auto const generation = f_.getFullBelowCache()->getGeneration();
SHAMapNodeID iNodeID; SHAMapNodeID currNodeID;
auto iNode = root_.get(); auto currNode = root_.get();
while (iNode->isInner() && while (currNode->isInner() &&
!static_cast<SHAMapInnerNode*>(iNode)->isFullBelow(generation) && !static_cast<SHAMapInnerNode*>(currNode)->isFullBelow(generation) &&
(iNodeID.getDepth() < node.getDepth())) (currNodeID.getDepth() < node.getDepth()))
{ {
int branch = selectBranch(iNodeID, node.getNodeID()); int const branch = selectBranch(currNodeID, node.getNodeID());
XRPL_ASSERT(branch >= 0, "ripple::SHAMap::addKnownNode : valid branch"); XRPL_ASSERT(branch >= 0, "ripple::SHAMap::addKnownNode : valid branch");
auto inner = static_cast<SHAMapInnerNode*>(iNode); auto inner = static_cast<SHAMapInnerNode*>(currNode);
if (inner->isEmptyBranch(branch)) if (inner->isEmptyBranch(branch))
{ {
JLOG(journal_.warn()) << "Add known node for empty branch" << node; JLOG(journal_.warn()) << "Add known node for empty branch" << node;
@@ -614,58 +614,84 @@ SHAMap::addKnownNode(
} }
auto prevNode = inner; auto prevNode = inner;
std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter); std::tie(currNode, currNodeID) =
descend(inner, currNodeID, branch, filter);
if (iNode == nullptr) if (currNode != nullptr)
continue;
auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
if (!newNode || childHash != newNode->getHash())
{ {
auto newNode = SHAMapTreeNode::makeFromWire(rawNode); JLOG(journal_.warn()) << "Corrupt node received";
return SHAMapAddNode::invalid();
}
if (!newNode || childHash != newNode->getHash()) // In rare cases, a node can still be corrupt even after hash
// validation. For leaf nodes, we perform an additional check to
// ensure the node's position in the tree is consistent with its
// content to prevent inconsistencies that could
// propagate further down the line.
if (newNode->isLeaf())
{
auto const& actualKey =
static_cast<SHAMapLeafNode const*>(newNode.get())
->peekItem()
->key();
// Validate that this leaf belongs at the target position
auto const expectedNodeID =
SHAMapNodeID::createID(node.getDepth(), actualKey);
if (expectedNodeID.getNodeID() != node.getNodeID())
{ {
JLOG(journal_.warn()) << "Corrupt node received"; JLOG(journal_.debug())
<< "Leaf node position mismatch: "
<< "expected=" << expectedNodeID.getNodeID()
<< ", actual=" << node.getNodeID();
return SHAMapAddNode::invalid(); return SHAMapAddNode::invalid();
} }
}
// Inner nodes must be at a level strictly less than 64 // Inner nodes must be at a level strictly less than 64
// but leaf nodes (while notionally at level 64) can be // but leaf nodes (while notionally at level 64) can be
// at any depth up to and including 64: // at any depth up to and including 64:
if ((iNodeID.getDepth() > leafDepth) || if ((currNodeID.getDepth() > leafDepth) ||
(newNode->isInner() && iNodeID.getDepth() == leafDepth)) (newNode->isInner() && currNodeID.getDepth() == leafDepth))
{ {
// Map is provably invalid // Map is provably invalid
state_ = SHAMapState::Invalid; state_ = SHAMapState::Invalid;
return SHAMapAddNode::useful();
}
if (iNodeID != node)
{
// Either this node is broken or we didn't request it (yet)
JLOG(journal_.warn()) << "unable to hook node " << node;
JLOG(journal_.info()) << " stuck at " << iNodeID;
JLOG(journal_.info()) << "got depth=" << node.getDepth()
<< ", walked to= " << iNodeID.getDepth();
return SHAMapAddNode::useful();
}
if (backed_)
canonicalize(childHash, newNode);
newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
if (filter)
{
Serializer s;
newNode->serializeWithPrefix(s);
filter->gotNode(
false,
childHash,
ledgerSeq_,
std::move(s.modData()),
newNode->getType());
}
return SHAMapAddNode::useful(); return SHAMapAddNode::useful();
} }
if (currNodeID != node)
{
// Either this node is broken or we didn't request it (yet)
JLOG(journal_.warn()) << "unable to hook node " << node;
JLOG(journal_.info()) << " stuck at " << currNodeID;
JLOG(journal_.info()) << "got depth=" << node.getDepth()
<< ", walked to= " << currNodeID.getDepth();
return SHAMapAddNode::useful();
}
if (backed_)
canonicalize(childHash, newNode);
newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
if (filter)
{
Serializer s;
newNode->serializeWithPrefix(s);
filter->gotNode(
false,
childHash,
ledgerSeq_,
std::move(s.modData()),
newNode->getType());
}
return SHAMapAddNode::useful();
} }
JLOG(journal_.trace()) << "got node, already had it (late)"; JLOG(journal_.trace()) << "got node, already had it (late)";

Some files were not shown because too many files have changed in this diff Show More