Compare commits

..

132 Commits

Author SHA1 Message Date
Denis Angell
5e8ecf6ff2 feature 2025-11-11 13:57:10 +01:00
Mayukha Vadari
8d266d3941 remove STInt64 (#5815) 2025-09-29 15:43:10 -04:00
Mayukha Vadari
a865b4da1c Merge branch 'ripple/se/fees' into ripple/smart-escrow 2025-09-26 17:10:10 -04:00
Mayukha Vadari
e59f5f3b01 fix tests 2025-09-26 17:09:53 -04:00
Mayukha Vadari
8729688feb Merge remote-tracking branch 'upstream/ripple/se/fees' into ripple/smart-escrow 2025-09-26 16:56:51 -04:00
Mayukha Vadari
c8b06e7de1 Merge branch 'ripple/wamr-host-functions' into ripple/se/fees 2025-09-26 16:50:34 -04:00
Mayukha Vadari
eaba76f9e6 Merge branch 'ripple/wamr' into ripple/wamr-host-functions 2025-09-26 16:37:25 -04:00
Mayukha Vadari
cb702cc238 Merge branch 'develop' into ripple/wamr 2025-09-26 16:37:04 -04:00
Mayukha Vadari
f1f798bb85 Merge branch 'ripple/se/fees' into ripple/smart-escrow 2025-09-26 15:52:22 -04:00
Mayukha Vadari
c3fd52c177 Merge branch 'ripple/wamr-host-functions' into ripple/se/fees 2025-09-26 15:51:56 -04:00
Mayukha Vadari
b69b4a0a4a Merge branch 'ripple/wamr' into ripple/wamr-host-functions 2025-09-26 15:51:48 -04:00
Mayukha Vadari
50d6072a73 Merge branch 'develop' into ripple/wamr 2025-09-26 15:51:40 -04:00
Olek
d24cd50e61 Switch to own wamr fork (#5808) 2025-09-23 16:39:21 -04:00
Mayukha Vadari
85bff20ae5 Merge branch 'ripple/se/fees' into ripple/smart-escrow 2025-09-23 10:22:30 -04:00
Mayukha Vadari
737fab5471 fix issues 2025-09-22 23:55:57 -04:00
Mayukha Vadari
e6592e93a9 Merge branch 'ripple/se/fees' into ripple/smart-escrow 2025-09-22 18:32:36 -04:00
Mayukha Vadari
5a6c4e8ae0 Merge branch 'ripple/wamr-host-functions' into ripple/se/fees 2025-09-22 18:23:54 -04:00
Mayukha Vadari
9f5875158c Merge branch 'ripple/wamr' into ripple/wamr-host-functions 2025-09-22 18:23:45 -04:00
Mayukha Vadari
c3dc33c861 Merge branch 'develop' into ripple/wamr 2025-09-22 18:23:35 -04:00
Mayukha Vadari
7420f47658 SmartEscrow fee voting changes 2025-09-22 18:22:44 -04:00
Olek
6be8f2124c Latests HF perf test (#5789) 2025-09-18 15:51:39 -04:00
Mayukha Vadari
edfed06001 fix merge issues 2025-09-18 15:39:49 -04:00
Mayukha Vadari
1c646dba91 Merge remote-tracking branch 'upstream/ripple/wamr' into wamr-host-functions 2025-09-18 15:29:02 -04:00
Mayukha Vadari
6781068058 Merge branch 'develop' into ripple/wamr 2025-09-18 15:27:54 -04:00
Mayukha Vadari
cfe57c1dfe Merge branch 'ripple/wamr' into ripple/wamr-host-functions 2025-09-18 14:37:58 -04:00
Mayukha Vadari
c34d09a971 Merge branch 'develop' into ripple/wamr 2025-09-18 14:24:34 -04:00
Mayukha Vadari
ebd90c4742 chore: remove unneeded float stuff (#5729) 2025-09-11 18:41:24 -04:00
Mayukha Vadari
ba52d34828 test: improve codecov in HostFuncWrapper.cpp (#5730) 2025-09-11 18:09:08 -04:00
Mayukha Vadari
2f869b3cfc Merge branch 'develop' into ripple/smart-escrow 2025-09-11 16:41:14 -04:00
Mayukha Vadari
ffa21c27a7 fix test 2025-09-11 16:40:59 -04:00
Mayukha Vadari
1b6312afb3 rearrange files 2025-09-11 16:34:03 -04:00
Mayukha Vadari
bf32dc2e72 add fixtures files 2025-09-11 16:28:11 -04:00
Mayukha Vadari
a15d65f7a2 update tests 2025-09-11 16:20:33 -04:00
Mayukha Vadari
2de8488855 add temBAD_WASM 2025-09-11 16:02:17 -04:00
Mayukha Vadari
129aa4bfaa bring out IOUAmount.h 2025-09-11 13:18:42 -04:00
Mayukha Vadari
b1d70db63b limits 2025-09-10 15:05:06 -04:00
Mayukha Vadari
f03c3aafe4 misc host function files 2025-09-10 15:02:48 -04:00
Mayukha Vadari
51a9f106d1 CODEOWNERS 2025-09-10 14:59:09 -04:00
Mayukha Vadari
bfc048e3fe add tests 2025-09-10 14:57:23 -04:00
Mayukha Vadari
83418644f7 add host functions 2025-09-10 14:56:21 -04:00
Mayukha Vadari
dbc9dd5bfc Add WAMR integration code 2025-09-10 14:56:08 -04:00
Mayukha Vadari
5c480cf883 Merge branch 'develop' into ripple/smart-escrow 2025-09-10 14:51:45 -04:00
Mayukha Vadari
45ab15d4b5 add WAMR dependency 2025-09-10 14:40:48 -04:00
Mayukha Vadari
adc64e7866 Merge branch 'develop' into ripple/smart-escrow 2025-09-10 10:46:51 -04:00
Mayukha Vadari
4d4a1cfe82 Merge branch 'develop' into ripple/smart-escrow 2025-09-09 16:19:27 -04:00
Mayukha Vadari
f2c7da3705 Merge branch 'develop' into ripple/smart-escrow 2025-09-09 14:51:25 -04:00
Mayukha Vadari
3ab0a82cd3 Merge branch 'develop' into ripple/smart-escrow 2025-09-08 15:20:01 -04:00
Mayukha Vadari
a46d772147 fix build and tests (#5768)
* fix conan.lock

* add conan.lock to triggers

* update on-trigger.yml too

* fix tests

* roll back unrelated changes
2025-09-04 17:05:39 -04:00
Mayukha Vadari
f3c50318e8 Merge branch 'develop' into ripple/smart-escrow 2025-09-04 13:42:59 -04:00
Mayukha Vadari
e7aa924c0e Merge branch 'develop' into ripple/smart-escrow 2025-09-03 15:54:57 -04:00
Mayukha Vadari
5266f04970 chore: rollback unrelated changes (#5737) 2025-09-02 18:26:01 -04:00
Mayukha Vadari
db957cf191 Merge branch 'develop' into ripple/smart-escrow 2025-08-29 16:54:17 -04:00
Mayukha Vadari
8ac514363d get new fees and reserves working (#5714) 2025-08-29 10:58:52 -04:00
Mayukha Vadari
c2ea68cca4 Merge branch 'develop' into ripple/smart-escrow 2025-08-28 14:02:10 -04:00
Mayukha Vadari
3d86881ce7 Merge branch 'develop' into ripple/smart-escrow 2025-08-27 13:58:38 -04:00
Mayukha Vadari
697d1470f4 change: adjust the function signatures for get_ledger_sqn and get_parent_ledger_time (#5733) 2025-08-27 13:58:27 -04:00
Mayukha Vadari
0b5f8f4051 Merge remote-tracking branch 'upstream/develop' into ripple/smart-escrow 2025-08-26 17:59:43 -04:00
Mayukha Vadari
0fed78fbcc Merge branch 'develop' into ripple/smart-escrow 2025-08-26 15:04:33 -04:00
Mayukha Vadari
8c38ef726b chore: exclude a bunch of code that doesn't need to be tested from codecov (#5721)
* exclude the bulk of HostFunc.h from codecov

* fix codecov (maybe)

* adjust

* more codecov excl
2025-08-26 15:04:27 -04:00
Mayukha Vadari
2399d90334 Merge branch 'develop' into ripple/smart-escrow 2025-08-25 10:42:48 -04:00
Mayukha Vadari
6367d68d1e Merge branch 'develop' into ripple/smart-escrow 2025-08-22 14:02:12 -04:00
Mayukha Vadari
155a84c8a3 Merge branch 'develop' into ripple/smart-escrow 2025-08-22 13:24:43 -04:00
Mayukha Vadari
10558c9eff Merge remote-tracking branch 'upstream/develop' into develop5.5 2025-08-22 10:38:10 -04:00
Mayukha Vadari
dd30d811e6 feat: last set of host functions (#5674) 2025-08-15 16:51:30 -04:00
Mayukha Vadari
293d8e4ddb test: store Rust source code in rippled, instead of just opaque hex strings (#5653) 2025-08-15 15:32:36 -04:00
Mayukha Vadari
77875c9133 fix: actually return int instead of bool (#5651) 2025-08-15 13:58:38 -04:00
Olek
647b47567e Fix float point binary format (#5688) 2025-08-15 09:51:40 -04:00
Olek
b0a1ad3b06 Disable float point instructions (#5679) 2025-08-14 14:59:55 -04:00
Mayukha Vadari
1d141bf2e8 chore: move WASM files to separate folder (#5666) 2025-08-14 11:46:10 -04:00
Olek
0d0e279ae2 Float point Hostfunctions unit tests (#5656)
* Added direct unittests for float hostfunctions
2025-08-14 10:21:21 -04:00
Mayukha Vadari
5dc0cee28a cache data instead of setting it in updateData (#5642)
Co-authored-by: Oleksandr <115580134+oleks-rip@users.noreply.github.com>
2025-08-11 15:52:21 -04:00
Mayukha Vadari
c15947da56 fix CI 2025-08-06 12:41:12 -04:00
Mayukha Vadari
9bc04244e7 Merge remote-tracking branch 'upstream/ripple/smart-escrow' into develop5 2025-08-06 12:36:25 -04:00
Mayukha Vadari
38c7a27010 clean up WASM functions a bit (#5628) 2025-08-05 18:06:34 -04:00
Mayukha Vadari
58741d2791 feat: return an int instead of boolean from finish, display in metadata (#5641)
* create STInt32 and STInt64, use it for sfWasmReturnCode in metadata

* get it actually working

* add tests

* update comment

* change type

* respond to comments
2025-08-04 09:25:47 -04:00
Mayukha Vadari
8426470506 feat: add other misc host functions (#5574) 2025-07-31 18:39:21 -04:00
Olek
ccc3280b1a Update wamr to 2.4.1 (#5640) 2025-07-31 13:42:53 -04:00
Mayukha Vadari
2847075705 fix: ensure GasUsed shows up in the metadata even on tecWASM_REJECTED (#5633)
* always set gas used

* fix

* add tests

* clean up
2025-07-31 10:57:56 -04:00
Olek
3108ca0549 Float point HF (#5611)
- added support for 8-byte  float point
2025-07-30 14:38:03 +00:00
Mayukha Vadari
3b849ff497 Add unit tests for host functions (#5578) 2025-07-29 17:54:48 -04:00
Mayukha Vadari
66776b6a85 test: codecov for WasmHostFuncWrapper.cpp (#5601) 2025-07-29 16:06:21 -04:00
Mayukha Vadari
c8c241b50d Merge remote-tracking branch 'upstream/develop' into develop4.6 2025-07-29 11:34:44 -04:00
Bronek Kozicki
44cb588371 Build options cleanup (#5581)
As we no longer support old compiler versions, we are bringing back some warnings by removing no longer relevant `-Wno-...` options.
2025-07-28 13:02:41 -04:00
Oleksandr
6f91b8f8d1 Fix windows 2025-07-28 12:29:39 -04:00
Mayukha Vadari
3d93379132 add header 2025-07-25 15:10:47 -04:00
Mayukha Vadari
84fd7d0126 Merge remote-tracking branch 'upstream/develop' into develop4.6 2025-07-25 14:56:36 -04:00
Mayukha Vadari
7f52287aae rename variables (#5609)
* rename variables

* instanceWrapper -> runtime

* size -> srcSize

* begin -> ptr
2025-07-25 11:54:31 -04:00
Mayukha Vadari
98b8986868 fix merge issues (mostly with Conan2 upgrade) 2025-07-23 15:52:03 -04:00
Mayukha Vadari
250f2842ee Merge remote-tracking branch 'upstream/develop' into develop4.5 2025-07-23 13:43:47 -04:00
Olek
9eca1a3a0c MPT and IOU support for amount and issue (#5573)
* MPT and IOU support for ammount and issue

* Fix tests
Update wasm code to the latest version
Remove deprecated tests
Remove deprecated wasm
2025-07-22 17:43:21 +00:00
Mayukha Vadari
24b7a03224 feat: add more keylet host functions (#5522) 2025-07-17 12:37:41 -04:00
Mayukha Vadari
9007097d24 Simplify host function boilerplate (#5534)
* enum for HF errors

* switch getData functions to be templates

* getData<SField> working

* Slice -> Bytes in host functions

* RET -> helper function instead of macro

* get template function working

* more organization/cleanup

* fix failures

* more cleanup

* Bytes -> Slice

* SFieldParam macro -> type alias

* fix return type

* fix bugs

* replace std::make_index_sequence

* remove `failed` from output

* remove complex function

* more uniformity

* respond to comments

* enum class HostFunctionError

* rename variable

* respond to comments

* remove templating

* [WIP] basic getData tests

* weird linker error

* fix issue
2025-07-15 04:28:59 +05:30
Olek
bc445ec6a2 Add hostfunctions schedule table
Remove opcode schedule table from wamr
2025-07-11 18:08:36 -04:00
Mayukha Vadari
4fa0ae521e disallow a computation allowance of 0 (#5541) 2025-07-09 00:34:17 +05:30
Olek
7bdf5fa8b8 Fix build.md wamr version (#5535) 2025-07-04 00:48:03 +05:30
Olek
65b0b976d9 Sync error codes (#5527)
* Sync error codes
2025-07-02 17:33:39 -04:00
Elliot.
a0d275feec chore: Clear CODEOWNERS (#5528) 2025-07-02 10:39:57 -07:00
Mayukha Vadari
ece3a8d7be Merge branch 'develop' into develop4 2025-06-30 21:33:30 +05:30
Olek
463acf51b5 preflight checks for wasm (#5517) 2025-06-30 09:34:38 -04:00
Olek
1cd16fab87 Host-functions perf test fixes (#5514) 2025-06-27 09:59:28 -04:00
Olek
add55c4f33 Host functions gas cost for wasm_runtime interface (#5500) 2025-06-25 14:04:04 +00:00
Olek
51a9c0ff59 Host function gas cost (#5488)
* Update Wamr to 2.3.1
* Add gas cost per host-function
* Fix windows build
* Fix wasm test
* Add no import test
2025-06-12 15:54:49 -04:00
Mayukha Vadari
6e8a5f0f4e fix: make host function traces easier to use, fix get_NFT bug (#5466)
Co-authored-by: Olek <115580134+oleks-rip@users.noreply.github.com>
2025-06-05 14:24:13 -04:00
Mayukha Vadari
8a33702f26 fix merge issues 2025-06-05 12:38:26 -04:00
Mayukha Vadari
a072d49802 Merge remote-tracking branch 'upstream/ripple/smart-escrow' into develop3.5 2025-06-05 11:51:53 -04:00
Mayukha Vadari
a0aeeb8e07 Merge remote-tracking branch 'upstream/develop' into develop3.5 2025-06-05 11:50:38 -04:00
Olek
383b225690 Fix processing nonexistent field (#5467) 2025-06-04 17:32:11 -04:00
Mayukha Vadari
ace2247800 Merge remote-tracking branch 'upstream/ripple/smart-escrow' into develop3.5 2025-06-04 14:15:17 -04:00
Olek
6a6fed5dce More hostfunctions (#5451)
* Bug fixes:
- Fix bugs found during schedule table tests
- Add more tests
- Add parameters passing for runEscrowWasm function

* Add new host-functions
 fix wamr logging
 add runtime passing through HF
 fix runEscrowWasm interface

* Improve logs

* Fix logging bug

* Set 4k limit for update_data HF

* allHF wasm module fixes
2025-05-30 19:01:27 -04:00
Mayukha Vadari
1f8aece8cd feat: add a GasUsed parameter to the metadata (#5456) 2025-05-29 16:36:55 -04:00
Mayukha Vadari
6c6f8cd4f9 Merge remote-tracking branch 'upstream/develop' into develop3 2025-05-29 13:05:11 -04:00
Mayukha Vadari
fb1311e013 uncomment???? 2025-05-28 14:00:50 -04:00
Mayukha Vadari
ce31acf030 debug comments 2025-05-28 13:48:38 -04:00
Mayukha Vadari
31ad5ac63b Merge remote-tracking branch 'upstream/ripple/smart-escrow' into develop3 2025-05-27 18:29:41 -04:00
Mayukha Vadari
1ede0bdec4 fix: fix fixtures (#5445) 2025-05-23 17:37:14 -04:00
Mayukha Vadari
aef32ead2c better WASM logging to match rippled (#5395)
* basic logging

* pass in Journal

* log level based on journal level

* clean up

* attempt at adding WAMR logging properly

* improve logline

* maybe_unused

* fix

* fix

* fix segfault

* add test
2025-05-23 10:31:02 -04:00
Mayukha Vadari
5b43ec7f73 refactor: switch function name from ready to finish (#5430) 2025-05-20 16:12:19 -04:00
Olek
1e9ff88a00 Fix CI build issues
* Mac build fix
* Windows build fix
* Windows instruction counter fix
2025-05-08 12:39:37 -04:00
Mayukha Vadari
bb9bb5f5c5 Merge branch 'ripple/smart-escrow' into develop2 2025-05-01 18:44:06 -04:00
Mayukha Vadari
c533abd8b6 Update size and compute cap defaults (#5417) 2025-05-01 18:41:51 -04:00
Olek
bb9bc764bc Switch to WAMR (#5416)
* Switch to WAMR
2025-05-01 18:02:06 -04:00
Mayukha Vadari
b4b53a6cb7 Merge branch 'ripple/smart-escrow' into develop2 2025-04-29 15:25:54 -04:00
Mayukha Vadari
9c0204906c fix reference fee tests 2025-04-29 15:25:00 -04:00
Mayukha Vadari
4670b373c1 try to fix tests 2025-04-29 14:10:27 -04:00
Mayukha Vadari
f03b5883bd More host functions (#5411)
* getNFT

* escrow keylet

* account keylet

* credential keylet

* oracle keylet

* hook everything in

* fix stuff
2025-04-29 12:39:12 -04:00
Mayukha Vadari
f8b2fe4dd5 fix imports 2025-04-28 17:43:15 -04:00
Mayukha Vadari
be4a0c9c2b Merge remote-tracking branch 'upstream/ripple/smart-escrow' into develop2 2025-04-28 17:14:28 -04:00
Mayukha Vadari
f37d52d8e9 Set up fees for WASM processing (#5393)
* set up fields

* throw error if allowance is too high

* votable gas price

* fix comments

* hook everything together

* make test less flaky (hopefully)

* fix other tests

* fix some tests

* fix tests

* clean up

* add more tests

* uncomment other tests

* respond to comments

* fix build

* respond to comments
2025-04-24 08:47:13 -04:00
Mayukha Vadari
177cdaf550 Connect votable gas limit into VM (#5360)
* [WIP] add gas limit

* [WIP] host function escrow tests

* finish test

* uncomment out tests
2025-03-25 10:55:33 -04:00
pwang200
1573a443b7 smart escrow devnet 1 host functions (#5353)
* devnet 1 host functions

* clang-format

* fix build issues
2025-03-24 17:07:17 -04:00
Mayukha Vadari
911c0466c0 Merge develop into ripple/smart-escrow (#5357)
* Set version to 2.4.0

* refactor: Remove unused and add missing includes (#5293)

The codebase is filled with includes that are unused, and which thus can be removed. At the same time, the files often do not include all headers that contain the definitions used in those files. This change uses clang-format and clang-tidy to clean up the includes, with minor manual intervention to ensure the code compiles on all platforms.

* refactor: Calculate numFeatures automatically (#5324)

Requiring manual updates of numFeatures is an annoying manual process that is easily forgotten, and leads to frequent merge conflicts. This change takes advantage of the `XRPL_FEATURE` and `XRPL_FIX` macros, and adds a new `XRPL_RETIRE` macro to automatically set `numFeatures`.

* refactor: Improve ordering of headers with clang-format (#5343)

Removes all manual header groupings from source and header files by leveraging clang-format options.

* Rename "deadlock" to "stall" in `LoadManager` (#5341)

What the LoadManager class does is stall detection, which is not the same as deadlock detection. In the condition of severe CPU starvation, LoadManager will currently intentionally crash rippled reporting `LogicError: Deadlock detected`. This error message is misleading as the condition being detected is not a deadlock. This change fixes and refactors the code in response.

* Adds hub.xrpl-commons.org as a new Bootstrap Cluster (#5263)

* fix: Error message for ledger_entry rpc (#5344)

Changes the error to `malformedAddress` for `permissioned_domain` in the `ledger_entry` rpc, when the account is not a string. This change makes it more clear to a user what is wrong with their request.

* fix: Handle invalid marker parameter in grpc call (#5317)

The `end_marker` is used to limit the range of ledger entries to fetch. If `end_marker` is less than `marker`, a crash can occur. This change adds an additional check.

* fix: trust line RPC no ripple flag (#5345)

The Trustline RPC `no_ripple` flag gets set depending on `lsfDefaultRipple` flag, which is not a flag of a trustline but of the account root. The `lsfDefaultRipple` flag does not provide any insight if this particular trust line has `lsfLowNoRipple` or `lsfHighNoRipple` flag set, so it should not be used here at all. This change simplifies the logic.

* refactor: Updates Conan dependencies: RocksDB (#5335)

Updates RocksDB to version 9.7.3, the latest version supported in Conan 1.x. A patch for 9.7.4 that fixes a memory leak is included.

* fix: Remove null pointer deref, just do abort (#5338)

This change removes the existing undefined behavior from `LogicError`, so we can be certain that there will be always a stacktrace.

De-referencing a null pointer is an old trick to generate `SIGSEGV`, which would typically also create a stacktrace. However it is also an undefined behaviour and compilers can do something else. A more robust way to create a stacktrace while crashing the program is to use `std::abort`, which we have also used in this location for a long time. If we combine the two, we might not get the expected behaviour - namely, the nullpointer deref followed by `std::abort`, as handled in certain compiler versions may not immediately cause a crash. We have observed stacktrace being wiped instead, and thread put in indeterminate state, then stacktrace created without any useful information.

* chore: Add PR number to payload (#5310)

This PR adds one more payload field to the libXRPL compatibility check workflow - the PR number itself.

* chore: Update link to ripple-binary-codec (#5355)

The link to ripple-binary-codec's definitions.json appears to be outdated. The updated link is also documented here: https://xrpl.org/docs/references/protocol/binary-format#definitions-file

* Prevent consensus from getting stuck in the establish phase (#5277)

- Detects if the consensus process is "stalled". If it is, then we can declare a 
  consensus and end successfully even if we do not have 80% agreement on
  our proposal.
  - "Stalled" is defined as:
    - We have a close time consensus
    - Each disputed transaction is individually stalled:
      - It has been in the final "stuck" 95% requirement for at least 2
        (avMIN_ROUNDS) "inner rounds" of phaseEstablish,
      - and either all of the other trusted proposers or this validator, if proposing,
        have had the same vote(s) for at least 4 (avSTALLED_ROUNDS) "inner
        rounds", and at least 80% of the validators (including this one, if
        appropriate) agree about the vote (whether yes or no).
- If we have been in the establish phase for more than 10x the previous
  consensus establish phase's time, then consensus is considered "expired",
  and we will leave the round, which sends a partial validation (indicating
  that the node is moving on without validating). Two restrictions avoid
  prematurely exiting, or having an extended exit in extreme situations.
  - The 10x time is clamped to be within a range of 15s
    (ledgerMAX_CONSENSUS) to 120s (ledgerABANDON_CONSENSUS).
  - If consensus has not had an opportunity to walk through all avalanche
    states (defined as not going through 8 "inner rounds" of phaseEstablish),
    then ConsensusState::Expired is treated as ConsensusState::No.
- When enough nodes leave the round, any remaining nodes will see they've
  fallen behind, and move on, too, generally before hitting the timeout. Any
  validations or partial validations sent during this time will help the
  consensus process bring the nodes back together.

---------

Co-authored-by: Michael Legleux <mlegleux@ripple.com>
Co-authored-by: Bart <bthomee@users.noreply.github.com>
Co-authored-by: Ed Hennis <ed@ripple.com>
Co-authored-by: Bronek Kozicki <brok@incorrekt.com>
Co-authored-by: Darius Tumas <Tokeiito@users.noreply.github.com>
Co-authored-by: Sergey Kuznetsov <skuznetsov@ripple.com>
Co-authored-by: cyan317 <120398799+cindyyan317@users.noreply.github.com>
Co-authored-by: Vlad <129996061+vvysokikh1@users.noreply.github.com>
Co-authored-by: Alex Kremer <akremer@ripple.com>
2025-03-20 16:47:14 -04:00
Mayukha Vadari
b6a95f9970 PoC Smart Escrows (#5340)
* wasmedge in unittest

* add WashVM.h and cpp

* accountID comparison (vector<u8>) working

* json decode tx and ledger object with two buffers working

* wasm return a buffer working

* add a failure test case to P2P3

* host function return ledger sqn

* instruction gas and host function gas

* basics

* add scaffold

* add amendment check

* working PoC

* get test working

* fix clang-format

* prototype #2

* p2p3

* [WIP] P4

* P5

* add calculateBaseFee

* add FinishFunction preflight checks (+ tests)

* additional reserve for sfFinishFunction

* higher fees for EscrowFinish

* rename amendment to SmartEscrow

* make fee voting changes, add basic tests

* clean up

* clean up

* clean up

* more cleanup

* add subscribe tests

* add more tests

* undo formatting

* undo formatting

* remove bad comment

* more debugging statements

* fix clang-format

* fix rebase issues

* fix more rebase issues

* more rebase fixes

* add source code for wasm

* respond to comments

* add const

---------

Co-authored-by: Peng Wang <pwang200@gmail.com>
2025-03-20 14:08:06 -04:00
506 changed files with 55527 additions and 29581 deletions

6
.github/CODEOWNERS vendored
View File

@@ -1,8 +1,2 @@
# Allow anyone to review any change by default. # Allow anyone to review any change by default.
* *
# Require the rpc-reviewers team to review changes to the rpc code.
include/xrpl/protocol/ @xrplf/rpc-reviewers
src/libxrpl/protocol/ @xrplf/rpc-reviewers
src/xrpld/rpc/ @xrplf/rpc-reviewers
src/xrpld/app/misc/ @xrplf/rpc-reviewers

View File

@@ -10,40 +10,24 @@ inputs:
build_type: build_type:
description: 'The build type to use ("Debug", "Release").' description: 'The build type to use ("Debug", "Release").'
required: true required: true
build_nproc:
description: "The number of processors to use for building."
required: true
force_build: force_build:
description: 'Force building of all dependencies ("true", "false").' description: 'Force building of all dependencies ("true", "false").'
required: false required: false
default: "false" default: "false"
log_verbosity:
description: "The logging verbosity."
required: false
default: "verbose"
runs: runs:
using: composite using: composite
steps: steps:
- name: Install Conan dependencies - name: Install Conan dependencies
shell: bash shell: bash
env:
BUILD_DIR: ${{ inputs.build_dir }}
BUILD_NPROC: ${{ inputs.build_nproc }}
BUILD_OPTION: ${{ inputs.force_build == 'true' && '*' || 'missing' }}
BUILD_TYPE: ${{ inputs.build_type }}
LOG_VERBOSITY: ${{ inputs.log_verbosity }}
run: | run: |
echo 'Installing dependencies.' echo 'Installing dependencies.'
mkdir -p "${BUILD_DIR}" mkdir -p ${{ inputs.build_dir }}
cd "${BUILD_DIR}" cd ${{ inputs.build_dir }}
conan install \ conan install \
--output-folder . \ --output-folder . \
--build="${BUILD_OPTION}" \ --build ${{ inputs.force_build == 'true' && '"*"' || 'missing' }} \
--options:host='&:tests=True' \ --options:host '&:tests=True' \
--options:host='&:xrpld=True' \ --options:host '&:xrpld=True' \
--settings:all build_type="${BUILD_TYPE}" \ --settings:all build_type=${{ inputs.build_type }} \
--conf:all tools.build:jobs=${BUILD_NPROC} \
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \
.. ..

96
.github/actions/build-test/action.yml vendored Normal file
View File

@@ -0,0 +1,96 @@
# This action build and tests the binary. The Conan dependencies must have
# already been installed (see the build-deps action).
name: Build and Test
description: "Build and test the binary."
# Note that actions do not support 'type' and all inputs are strings, see
# https://docs.github.com/en/actions/reference/workflows-and-actions/metadata-syntax#inputs.
inputs:
build_dir:
description: "The directory where to build."
required: true
build_only:
description: 'Whether to only build or to build and test the code ("true", "false").'
required: false
default: "false"
build_type:
description: 'The build type to use ("Debug", "Release").'
required: true
cmake_args:
description: "Additional arguments to pass to CMake."
required: false
default: ""
cmake_target:
description: "The CMake target to build."
required: true
codecov_token:
description: "The Codecov token to use for uploading coverage reports."
required: false
default: ""
os:
description: 'The operating system to use for the build ("linux", "macos", "windows").'
required: true
runs:
using: composite
steps:
- name: Configure CMake
shell: bash
working-directory: ${{ inputs.build_dir }}
run: |
echo 'Configuring CMake.'
cmake \
-G '${{ inputs.os == 'windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \
${{ inputs.cmake_args }} \
..
- name: Build the binary
shell: bash
working-directory: ${{ inputs.build_dir }}
run: |
echo 'Building binary.'
cmake \
--build . \
--config ${{ inputs.build_type }} \
--parallel $(nproc) \
--target ${{ inputs.cmake_target }}
- name: Check linking
if: ${{ inputs.os == 'linux' }}
shell: bash
working-directory: ${{ inputs.build_dir }}
run: |
echo 'Checking linking.'
ldd ./rippled
if [ "$(ldd ./rippled | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then
echo 'The binary is statically linked.'
else
echo 'The binary is dynamically linked.'
exit 1
fi
- name: Verify voidstar
if: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }}
shell: bash
working-directory: ${{ inputs.build_dir }}
run: |
echo 'Verifying presence of instrumentation.'
./rippled --version | grep libvoidstar
- name: Test the binary
if: ${{ inputs.build_only == 'false' }}
shell: bash
working-directory: ${{ inputs.build_dir }}/${{ inputs.os == 'windows' && inputs.build_type || '' }}
run: |
echo 'Testing binary.'
./rippled --unittest --unittest-jobs $(nproc)
ctest -j $(nproc) --output-on-failure
- name: Upload coverage report
if: ${{ inputs.cmake_target == 'coverage' }}
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
with:
disable_search: true
disable_telem: true
fail_ci_if_error: true
files: ${{ inputs.build_dir }}/coverage.xml
plugins: noop
token: ${{ inputs.codecov_token }}
verbose: true

View File

@@ -1,43 +0,0 @@
name: Print build environment
description: "Print environment and some tooling versions"
runs:
using: composite
steps:
- name: Check configuration (Windows)
if: ${{ runner.os == 'Windows' }}
shell: bash
run: |
echo 'Checking environment variables.'
set
echo 'Checking CMake version.'
cmake --version
echo 'Checking Conan version.'
conan --version
- name: Check configuration (Linux and macOS)
if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }}
shell: bash
run: |
echo 'Checking path.'
echo ${PATH} | tr ':' '\n'
echo 'Checking environment variables.'
env | sort
echo 'Checking CMake version.'
cmake --version
echo 'Checking compiler version.'
${{ runner.os == 'Linux' && '${CC}' || 'clang' }} --version
echo 'Checking Conan version.'
conan --version
echo 'Checking Ninja version.'
ninja --version
echo 'Checking nproc version.'
nproc --version

View File

@@ -35,12 +35,9 @@ runs:
- name: Set up Conan remote - name: Set up Conan remote
shell: bash shell: bash
env:
CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }}
CONAN_REMOTE_URL: ${{ inputs.conan_remote_url }}
run: | run: |
echo "Adding Conan remote '${CONAN_REMOTE_NAME}' at '${CONAN_REMOTE_URL}'." echo "Adding Conan remote '${{ inputs.conan_remote_name }}' at ${{ inputs.conan_remote_url }}."
conan remote add --index 0 --force "${CONAN_REMOTE_NAME}" "${CONAN_REMOTE_URL}" conan remote add --index 0 --force ${{ inputs.conan_remote_name }} ${{ inputs.conan_remote_url }}
echo 'Listing Conan remotes.' echo 'Listing Conan remotes.'
conan remote list conan remote list

View File

@@ -138,7 +138,6 @@ 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.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

View File

@@ -74,14 +74,14 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
continue continue
# RHEL: # RHEL:
# - 9 using GCC 12: Debug and Unity on linux/amd64. # - 9.4 using GCC 12: Debug and Unity on linux/amd64.
# - 10 using Clang: Release and no Unity on linux/amd64. # - 9.6 using Clang: Release and no Unity on linux/amd64.
if os['distro_name'] == 'rhel': if os['distro_name'] == 'rhel':
skip = True skip = True
if os['distro_version'] == '9': if os['distro_version'] == '9.4':
if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-12' and build_type == 'Debug' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64': if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-12' and build_type == 'Debug' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64':
skip = False skip = False
elif os['distro_version'] == '10': elif os['distro_version'] == '9.6':
if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-any' and build_type == 'Release' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64': if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-any' and build_type == 'Release' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64':
skip = False skip = False
if skip: if skip:
@@ -130,14 +130,16 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
if os['distro_name'] == 'rhel' and architecture['platform'] == 'linux/arm64': if os['distro_name'] == 'rhel' and architecture['platform'] == 'linux/arm64':
continue continue
# We skip all clang 20+ on arm64 due to Boost build error. # We skip all clang-20 on arm64 due to boost 1.86 build error
if f'{os['compiler_name']}-{os['compiler_version']}' in ['clang-20', 'clang-21'] and architecture['platform'] == 'linux/arm64': if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-20' and architecture['platform'] == 'linux/arm64':
continue continue
# Enable code coverage for Debian Bookworm using GCC 15 in Debug and no # Enable code coverage for Debian Bookworm using GCC 15 in Debug and no
# Unity on linux/amd64 # Unity on linux/amd64
if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-15' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64': if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-15' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64':
cmake_args = f'-Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0 {cmake_args}' cmake_args = f'-Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0 {cmake_args}'
cmake_target = 'coverage'
build_only = True
# Generate a unique name for the configuration, e.g. macos-arm64-debug # Generate a unique name for the configuration, e.g. macos-arm64-debug
# or debian-bookworm-gcc-12-amd64-release-unity. # or debian-bookworm-gcc-12-amd64-release-unity.
@@ -160,7 +162,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
'config_name': config_name, 'config_name': config_name,
'cmake_args': cmake_args, 'cmake_args': cmake_args,
'cmake_target': cmake_target, 'cmake_target': cmake_target,
'build_only': build_only, 'build_only': 'true' if build_only else 'false',
'build_type': build_type, 'build_type': build_type,
'os': os, 'os': os,
'architecture': architecture, 'architecture': architecture,

View File

@@ -14,197 +14,139 @@
"distro_name": "debian", "distro_name": "debian",
"distro_version": "bookworm", "distro_version": "bookworm",
"compiler_name": "gcc", "compiler_name": "gcc",
"compiler_version": "12", "compiler_version": "12"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "debian",
"distro_version": "bookworm", "distro_version": "bookworm",
"compiler_name": "gcc", "compiler_name": "gcc",
"compiler_version": "13", "compiler_version": "13"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "debian",
"distro_version": "bookworm", "distro_version": "bookworm",
"compiler_name": "gcc", "compiler_name": "gcc",
"compiler_version": "14", "compiler_version": "14"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "debian",
"distro_version": "bookworm", "distro_version": "bookworm",
"compiler_name": "gcc", "compiler_name": "gcc",
"compiler_version": "15", "compiler_version": "15"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "debian",
"distro_version": "bookworm", "distro_version": "bookworm",
"compiler_name": "clang", "compiler_name": "clang",
"compiler_version": "16", "compiler_version": "16"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "debian",
"distro_version": "bookworm", "distro_version": "bookworm",
"compiler_name": "clang", "compiler_name": "clang",
"compiler_version": "17", "compiler_version": "17"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "debian",
"distro_version": "bookworm", "distro_version": "bookworm",
"compiler_name": "clang", "compiler_name": "clang",
"compiler_version": "18", "compiler_version": "18"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "debian",
"distro_version": "bookworm", "distro_version": "bookworm",
"compiler_name": "clang", "compiler_name": "clang",
"compiler_version": "19", "compiler_version": "19"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "debian",
"distro_version": "bookworm", "distro_version": "bookworm",
"compiler_name": "clang", "compiler_name": "clang",
"compiler_version": "20", "compiler_version": "20"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "rhel",
"distro_version": "trixie", "distro_version": "9.4",
"compiler_name": "gcc", "compiler_name": "gcc",
"compiler_version": "14", "compiler_version": "12"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "rhel",
"distro_version": "trixie", "distro_version": "9.4",
"compiler_name": "gcc", "compiler_name": "gcc",
"compiler_version": "15", "compiler_version": "13"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "rhel",
"distro_version": "trixie", "distro_version": "9.4",
"compiler_name": "gcc",
"compiler_version": "14"
},
{
"distro_name": "rhel",
"distro_version": "9.6",
"compiler_name": "gcc",
"compiler_version": "13"
},
{
"distro_name": "rhel",
"distro_version": "9.6",
"compiler_name": "gcc",
"compiler_version": "14"
},
{
"distro_name": "rhel",
"distro_version": "9.4",
"compiler_name": "clang", "compiler_name": "clang",
"compiler_version": "20", "compiler_version": "any"
"image_sha": "0525eae"
}, },
{ {
"distro_name": "debian", "distro_name": "rhel",
"distro_version": "trixie", "distro_version": "9.6",
"compiler_name": "clang", "compiler_name": "clang",
"compiler_version": "21", "compiler_version": "any"
"image_sha": "0525eae"
},
{
"distro_name": "rhel",
"distro_version": "8",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "e1782cd"
},
{
"distro_name": "rhel",
"distro_version": "8",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "e1782cd"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "12",
"image_sha": "e1782cd"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "13",
"image_sha": "e1782cd"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "e1782cd"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "e1782cd"
},
{
"distro_name": "rhel",
"distro_version": "10",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "e1782cd"
},
{
"distro_name": "rhel",
"distro_version": "10",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "e1782cd"
}, },
{ {
"distro_name": "ubuntu", "distro_name": "ubuntu",
"distro_version": "jammy", "distro_version": "jammy",
"compiler_name": "gcc", "compiler_name": "gcc",
"compiler_version": "12", "compiler_version": "12"
"image_sha": "e1782cd"
}, },
{ {
"distro_name": "ubuntu", "distro_name": "ubuntu",
"distro_version": "noble", "distro_version": "noble",
"compiler_name": "gcc", "compiler_name": "gcc",
"compiler_version": "13", "compiler_version": "13"
"image_sha": "e1782cd"
}, },
{ {
"distro_name": "ubuntu", "distro_name": "ubuntu",
"distro_version": "noble", "distro_version": "noble",
"compiler_name": "gcc", "compiler_name": "gcc",
"compiler_version": "14", "compiler_version": "14"
"image_sha": "e1782cd"
}, },
{ {
"distro_name": "ubuntu", "distro_name": "ubuntu",
"distro_version": "noble", "distro_version": "noble",
"compiler_name": "clang", "compiler_name": "clang",
"compiler_version": "16", "compiler_version": "16"
"image_sha": "e1782cd"
}, },
{ {
"distro_name": "ubuntu", "distro_name": "ubuntu",
"distro_version": "noble", "distro_version": "noble",
"compiler_name": "clang", "compiler_name": "clang",
"compiler_version": "17", "compiler_version": "17"
"image_sha": "e1782cd"
}, },
{ {
"distro_name": "ubuntu", "distro_name": "ubuntu",
"distro_version": "noble", "distro_version": "noble",
"compiler_name": "clang", "compiler_name": "clang",
"compiler_version": "18", "compiler_version": "18"
"image_sha": "e1782cd"
}, },
{ {
"distro_name": "ubuntu", "distro_name": "ubuntu",
"distro_version": "noble", "distro_version": "noble",
"compiler_name": "clang", "compiler_name": "clang",
"compiler_version": "19", "compiler_version": "19"
"image_sha": "e1782cd"
} }
], ],
"build_type": ["Debug", "Release"], "build_type": ["Debug", "Release"],

View File

@@ -10,8 +10,7 @@
"distro_name": "macos", "distro_name": "macos",
"distro_version": "", "distro_version": "",
"compiler_name": "", "compiler_name": "",
"compiler_version": "", "compiler_version": ""
"image_sha": ""
} }
], ],
"build_type": ["Debug", "Release"], "build_type": ["Debug", "Release"],

View File

@@ -10,8 +10,7 @@
"distro_name": "windows", "distro_name": "windows",
"distro_version": "", "distro_version": "",
"compiler_name": "", "compiler_name": "",
"compiler_version": "", "compiler_version": ""
"image_sha": ""
} }
], ],
"build_type": ["Debug", "Release"], "build_type": ["Debug", "Release"],

View File

@@ -59,11 +59,8 @@ jobs:
.github/actions/build-test/** .github/actions/build-test/**
.github/actions/setup-conan/** .github/actions/setup-conan/**
.github/scripts/strategy-matrix/** .github/scripts/strategy-matrix/**
.github/workflows/reusable-build.yml
.github/workflows/reusable-build-test-config.yml
.github/workflows/reusable-build-test.yml .github/workflows/reusable-build-test.yml
.github/workflows/reusable-strategy-matrix.yml .github/workflows/reusable-strategy-matrix.yml
.github/workflows/reusable-test.yml
.codecov.yml .codecov.yml
cmake/** cmake/**
conan/** conan/**
@@ -103,19 +100,18 @@ jobs:
if: ${{ needs.should-run.outputs.go == 'true' }} if: ${{ needs.should-run.outputs.go == 'true' }}
uses: ./.github/workflows/reusable-build-test.yml uses: ./.github/workflows/reusable-build-test.yml
strategy: strategy:
fail-fast: false
matrix: matrix:
os: [linux, macos, windows] os: [linux, macos, windows]
with: with:
os: ${{ matrix.os }} os: ${{ matrix.os }}
secrets: secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} codecov_token: ${{ secrets.CODECOV_TOKEN }}
notify-clio: notify-clio:
needs: needs:
- should-run - should-run
- build-test - build-test
if: ${{ needs.should-run.outputs.go == 'true' && (startsWith(github.base_ref, 'release') || github.base_ref == 'master') }} if: ${{ needs.should-run.outputs.go == 'true' && contains(fromJSON('["release", "master"]'), github.ref_name) }}
uses: ./.github/workflows/reusable-notify-clio.yml uses: ./.github/workflows/reusable-notify-clio.yml
secrets: secrets:
clio_notify_token: ${{ secrets.CLIO_NOTIFY_TOKEN }} clio_notify_token: ${{ secrets.CLIO_NOTIFY_TOKEN }}

View File

@@ -9,23 +9,22 @@ name: Trigger
on: on:
push: push:
branches: branches:
- "develop" - develop
- "release*" - release
- "master" - master
paths: paths:
# These paths are unique to `on-trigger.yml`. # These paths are unique to `on-trigger.yml`.
- ".github/workflows/reusable-check-missing-commits.yml"
- ".github/workflows/on-trigger.yml" - ".github/workflows/on-trigger.yml"
- ".github/workflows/publish-docs.yml"
# Keep the paths below in sync with those in `on-pr.yml`. # Keep the paths below in sync with those in `on-pr.yml`.
- ".github/actions/build-deps/**" - ".github/actions/build-deps/**"
- ".github/actions/build-test/**" - ".github/actions/build-test/**"
- ".github/actions/setup-conan/**" - ".github/actions/setup-conan/**"
- ".github/scripts/strategy-matrix/**" - ".github/scripts/strategy-matrix/**"
- ".github/workflows/reusable-build.yml"
- ".github/workflows/reusable-build-test-config.yml"
- ".github/workflows/reusable-build-test.yml" - ".github/workflows/reusable-build-test.yml"
- ".github/workflows/reusable-strategy-matrix.yml" - ".github/workflows/reusable-strategy-matrix.yml"
- ".github/workflows/reusable-test.yml"
- ".codecov.yml" - ".codecov.yml"
- "cmake/**" - "cmake/**"
- "conan/**" - "conan/**"
@@ -44,16 +43,25 @@ on:
schedule: schedule:
- cron: "32 6 * * 1-5" - cron: "32 6 * * 1-5"
# Run when manually triggered via the GitHub UI or API. # Run when manually triggered via the GitHub UI or API. If `force_upload` is
# true, then the dependencies that were missing (`force_rebuild` is false) or
# rebuilt (`force_rebuild` is true) will be uploaded, overwriting existing
# dependencies if needed.
workflow_dispatch: workflow_dispatch:
inputs:
dependencies_force_build:
description: "Force building of all dependencies."
required: false
type: boolean
default: false
dependencies_force_upload:
description: "Force uploading of all dependencies."
required: false
type: boolean
default: false
concurrency: concurrency:
# When a PR is merged into the develop branch it will be assigned a unique group: ${{ github.workflow }}-${{ github.ref }}
# group identifier, so execution will continue even if another PR is merged
# while it is still running. In all other cases the group identifier is shared
# per branch, so that any in-progress runs are cancelled when a new commit is
# pushed.
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && github.sha || github.ref }}
cancel-in-progress: true cancel-in-progress: true
defaults: defaults:
@@ -61,14 +69,17 @@ defaults:
shell: bash shell: bash
jobs: jobs:
check-missing-commits:
if: ${{ github.event_name == 'push' && github.ref_type == 'branch' && contains(fromJSON('["develop", "release"]'), github.ref_name) }}
uses: ./.github/workflows/reusable-check-missing-commits.yml
build-test: build-test:
uses: ./.github/workflows/reusable-build-test.yml uses: ./.github/workflows/reusable-build-test.yml
strategy: strategy:
fail-fast: ${{ github.event_name == 'merge_group' }}
matrix: matrix:
os: [linux, macos, windows] os: [linux, macos, windows]
with: with:
os: ${{ matrix.os }} os: ${{ matrix.os }}
strategy_matrix: ${{ github.event_name == 'schedule' && 'all' || 'minimal' }} strategy_matrix: ${{ github.event_name == 'schedule' && 'all' || 'minimal' }}
secrets: secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} codecov_token: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -9,7 +9,7 @@ on:
jobs: jobs:
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks. # Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
run-hooks: run-hooks:
uses: XRPLF/actions/.github/workflows/pre-commit.yml@34790936fae4c6c751f62ec8c06696f9c1a5753a uses: XRPLF/actions/.github/workflows/pre-commit.yml@af1b0f0d764cda2e5435f5ac97b240d4bd4d95d3
with: with:
runs_on: ubuntu-latest runs_on: ubuntu-latest
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-a8c7be1" }' container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-d1496b8" }'

View File

@@ -23,24 +23,16 @@ defaults:
env: env:
BUILD_DIR: .build BUILD_DIR: .build
NPROC_SUBTRACT: 2
jobs: jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/xrplf/ci/tools-rippled-documentation:sha-a8c7be1 container: ghcr.io/xrplf/ci/tools-rippled-documentation:sha-d1496b8
permissions: permissions:
contents: write contents: write
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- name: Get number of processors
uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a
id: nproc
with:
subtract: ${{ env.NPROC_SUBTRACT }}
- name: Check configuration - name: Check configuration
run: | run: |
echo 'Checking path.' echo 'Checking path.'
@@ -54,16 +46,12 @@ jobs:
echo 'Checking Doxygen version.' echo 'Checking Doxygen version.'
doxygen --version doxygen --version
- name: Build documentation - name: Build documentation
env:
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
run: | run: |
mkdir -p "${BUILD_DIR}" mkdir -p ${{ env.BUILD_DIR }}
cd "${BUILD_DIR}" cd ${{ env.BUILD_DIR }}
cmake -Donly_docs=ON .. cmake -Donly_docs=ON ..
cmake --build . --target docs --parallel ${BUILD_NPROC} cmake --build . --target docs --parallel $(nproc)
- name: Publish documentation - name: Publish documentation
if: ${{ github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch }} if: ${{ github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch }}
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0

View File

@@ -1,213 +0,0 @@
name: Build and test configuration
on:
workflow_call:
inputs:
build_dir:
description: "The directory where to build."
required: true
type: string
build_only:
description: 'Whether to only build or to build and test the code ("true", "false").'
required: true
type: boolean
build_type:
description: 'The build type to use ("Debug", "Release").'
type: string
required: true
cmake_args:
description: "Additional arguments to pass to CMake."
required: false
type: string
default: ""
cmake_target:
description: "The CMake target to build."
type: string
required: true
runs_on:
description: Runner to run the job on as a JSON string
required: true
type: string
image:
description: "The image to run in (leave empty to run natively)"
required: true
type: string
config_name:
description: "The configuration string (used for naming artifacts and such)."
required: true
type: string
nproc_subtract:
description: "The number of processors to subtract when calculating parallelism."
required: false
type: number
default: 2
secrets:
CODECOV_TOKEN:
description: "The Codecov token to use for uploading coverage reports."
required: true
defaults:
run:
shell: bash
jobs:
build-and-test:
name: ${{ inputs.config_name }}
runs-on: ${{ fromJSON(inputs.runs_on) }}
container: ${{ inputs.image != '' && inputs.image || null }}
timeout-minutes: 60
env:
ENABLED_VOIDSTAR: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }}
ENABLED_COVERAGE: ${{ contains(inputs.cmake_args, '-Dcoverage=ON') }}
steps:
- name: Cleanup workspace (macOS and Windows)
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
uses: XRPLF/actions/.github/actions/cleanup-workspace@01b244d2718865d427b499822fbd3f15e7197fcc
- name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- name: Prepare runner
uses: XRPLF/actions/.github/actions/prepare-runner@99685816bb60a95a66852f212f382580e180df3a
with:
disable_ccache: false
- name: Print build environment
uses: ./.github/actions/print-env
- name: Get number of processors
uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a
id: nproc
with:
subtract: ${{ inputs.nproc_subtract }}
- name: Setup Conan
uses: ./.github/actions/setup-conan
- name: Build dependencies
uses: ./.github/actions/build-deps
with:
build_dir: ${{ inputs.build_dir }}
build_nproc: ${{ steps.nproc.outputs.nproc }}
build_type: ${{ inputs.build_type }}
# Set the verbosity to "quiet" for Windows to avoid an excessive
# amount of logs. For other OSes, the "verbose" logs are more useful.
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
- name: Configure CMake
working-directory: ${{ inputs.build_dir }}
env:
BUILD_TYPE: ${{ inputs.build_type }}
CMAKE_ARGS: ${{ inputs.cmake_args }}
run: |
cmake \
-G '${{ runner.os == 'Windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
${CMAKE_ARGS} \
..
- name: Build the binary
working-directory: ${{ inputs.build_dir }}
env:
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
BUILD_TYPE: ${{ inputs.build_type }}
CMAKE_TARGET: ${{ inputs.cmake_target }}
run: |
cmake \
--build . \
--config "${BUILD_TYPE}" \
--parallel "${BUILD_NPROC}" \
--target "${CMAKE_TARGET}"
- name: Upload rippled artifact (Linux)
if: ${{ github.repository_owner == 'XRPLF' && runner.os == 'Linux' }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
env:
BUILD_DIR: ${{ inputs.build_dir }}
with:
name: rippled-${{ inputs.config_name }}
path: ${{ env.BUILD_DIR }}/rippled
retention-days: 3
if-no-files-found: error
- name: Check linking (Linux)
if: ${{ runner.os == 'Linux' }}
working-directory: ${{ inputs.build_dir }}
run: |
ldd ./rippled
if [ "$(ldd ./rippled | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then
echo 'The binary is statically linked.'
else
echo 'The binary is dynamically linked.'
exit 1
fi
- name: Verify presence of instrumentation (Linux)
if: ${{ runner.os == 'Linux' && env.ENABLED_VOIDSTAR == 'true' }}
working-directory: ${{ inputs.build_dir }}
run: |
./rippled --version | grep libvoidstar
- name: Run the separate tests
if: ${{ !inputs.build_only }}
working-directory: ${{ inputs.build_dir }}
# Windows locks some of the build files while running tests, and parallel jobs can collide
env:
BUILD_TYPE: ${{ inputs.build_type }}
PARALLELISM: ${{ runner.os == 'Windows' && '1' || steps.nproc.outputs.nproc }}
run: |
ctest \
--output-on-failure \
-C "${BUILD_TYPE}" \
-j "${PARALLELISM}"
- name: Run the embedded tests
if: ${{ !inputs.build_only }}
working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', inputs.build_dir, inputs.build_type) || inputs.build_dir }}
env:
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
run: |
./rippled --unittest --unittest-jobs "${BUILD_NPROC}"
- name: Debug failure (Linux)
if: ${{ failure() && runner.os == 'Linux' && !inputs.build_only }}
run: |
echo "IPv4 local port range:"
cat /proc/sys/net/ipv4/ip_local_port_range
echo "Netstat:"
netstat -an
- name: Prepare coverage report
if: ${{ !inputs.build_only && env.ENABLED_COVERAGE == 'true' }}
working-directory: ${{ inputs.build_dir }}
env:
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
BUILD_TYPE: ${{ inputs.build_type }}
run: |
cmake \
--build . \
--config "${BUILD_TYPE}" \
--parallel "${BUILD_NPROC}" \
--target coverage
- name: Upload coverage report
if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.ENABLED_COVERAGE == 'true' }}
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
with:
disable_search: true
disable_telem: true
fail_ci_if_error: true
files: ${{ inputs.build_dir }}/coverage.xml
plugins: noop
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true

View File

@@ -13,6 +13,16 @@ on:
required: false required: false
type: string type: string
default: ".build" default: ".build"
dependencies_force_build:
description: "Force building of all dependencies."
required: false
type: boolean
default: false
dependencies_force_upload:
description: "Force uploading of all dependencies."
required: false
type: boolean
default: false
os: os:
description: 'The operating system to use for the build ("linux", "macos", "windows").' description: 'The operating system to use for the build ("linux", "macos", "windows").'
required: true required: true
@@ -24,9 +34,17 @@ on:
type: string type: string
default: "minimal" default: "minimal"
secrets: secrets:
CODECOV_TOKEN: codecov_token:
description: "The Codecov token to use for uploading coverage reports." description: "The Codecov token to use for uploading coverage reports."
required: true required: false
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ inputs.os }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs: jobs:
# Generate the strategy matrix to be used by the following job. # Generate the strategy matrix to be used by the following job.
@@ -36,23 +54,94 @@ jobs:
os: ${{ inputs.os }} os: ${{ inputs.os }}
strategy_matrix: ${{ inputs.strategy_matrix }} strategy_matrix: ${{ inputs.strategy_matrix }}
# Build and test the binary for each configuration. # Build and test the binary.
build-test-config: build-test:
needs: needs:
- generate-matrix - generate-matrix
uses: ./.github/workflows/reusable-build-test-config.yml
strategy: strategy:
fail-fast: ${{ github.event_name == 'merge_group' }} fail-fast: false
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
max-parallel: 10 max-parallel: 10
with: runs-on: ${{ matrix.architecture.runner }}
build_dir: ${{ inputs.build_dir }} container: ${{ inputs.os == 'linux' && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-5dd7158', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version) || null }}
build_only: ${{ matrix.build_only }} steps:
build_type: ${{ matrix.build_type }} - name: Check strategy matrix
cmake_args: ${{ matrix.cmake_args }} run: |
cmake_target: ${{ matrix.cmake_target }} echo 'Operating system distro name: ${{ matrix.os.distro_name }}'
runs_on: ${{ toJSON(matrix.architecture.runner) }} echo 'Operating system distro version: ${{ matrix.os.distro_version }}'
image: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) || '' }} echo 'Operating system compiler name: ${{ matrix.os.compiler_name }}'
config_name: ${{ matrix.config_name }} echo 'Operating system compiler version: ${{ matrix.os.compiler_version }}'
secrets: echo 'Architecture platform: ${{ matrix.architecture.platform }}'
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} echo 'Architecture runner: ${{ toJson(matrix.architecture.runner) }}'
echo 'Build type: ${{ matrix.build_type }}'
echo 'Build only: ${{ matrix.build_only }}'
echo 'CMake arguments: ${{ matrix.cmake_args }}'
echo 'CMake target: ${{ matrix.cmake_target }}'
echo 'Config name: ${{ matrix.config_name }}'
- name: Cleanup workspace
if: ${{ runner.os == 'macOS' }}
uses: XRPLF/actions/.github/actions/cleanup-workspace@3f044c7478548e3c32ff68980eeb36ece02b364e
- name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- name: Prepare runner
uses: XRPLF/actions/.github/actions/prepare-runner@638e0dc11ea230f91bd26622fb542116bb5254d5
with:
disable_ccache: false
- name: Check configuration (Windows)
if: ${{ inputs.os == 'windows' }}
run: |
echo 'Checking environment variables.'
set
echo 'Checking CMake version.'
cmake --version
echo 'Checking Conan version.'
conan --version
- name: Check configuration (Linux and MacOS)
if: ${{ inputs.os == 'linux' || inputs.os == 'macos' }}
run: |
echo 'Checking path.'
echo ${PATH} | tr ':' '\n'
echo 'Checking environment variables.'
env | sort
echo 'Checking CMake version.'
cmake --version
echo 'Checking compiler version.'
${{ inputs.os == 'linux' && '${CC}' || 'clang' }} --version
echo 'Checking Conan version.'
conan --version
echo 'Checking Ninja version.'
ninja --version
echo 'Checking nproc version.'
nproc --version
- name: Setup Conan
uses: ./.github/actions/setup-conan
- name: Build dependencies
uses: ./.github/actions/build-deps
with:
build_dir: ${{ inputs.build_dir }}
build_type: ${{ matrix.build_type }}
force_build: ${{ inputs.dependencies_force_build }}
- name: Build and test binary
uses: ./.github/actions/build-test
with:
build_dir: ${{ inputs.build_dir }}
build_only: ${{ matrix.build_only }}
build_type: ${{ matrix.build_type }}
cmake_args: ${{ matrix.cmake_args }}
cmake_target: ${{ matrix.cmake_target }}
codecov_token: ${{ secrets.codecov_token }}
os: ${{ inputs.os }}

View File

@@ -0,0 +1,62 @@
# This workflow checks that all commits in the "master" branch are also in the
# "release" and "develop" branches, and that all commits in the "release" branch
# are also in the "develop" branch.
name: Check for missing commits
# This workflow can only be triggered by other workflows.
on: workflow_call
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-missing-commits
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
- name: Check for missing commits
env:
MESSAGE: |
If you are reading this, then the commits indicated above are missing
from the "develop" and/or "release" branch. Do a reverse-merge as soon
as possible. See CONTRIBUTING.md for instructions.
run: |
set -o pipefail
# Branches are ordered by how "canonical" they are. Every commit in one
# branch should be in all the branches behind it.
order=(master release develop)
branches=()
for branch in "${order[@]}"; do
# Check that the branches exist so that this job will work on forked
# repos, which don't necessarily have master and release branches.
echo "Checking if ${branch} exists."
if git ls-remote --exit-code --heads origin \
refs/heads/${branch} > /dev/null; then
branches+=(origin/${branch})
fi
done
prior=()
for branch in "${branches[@]}"; do
if [[ ${#prior[@]} -ne 0 ]]; then
echo "Checking ${prior[@]} for commits missing from ${branch}."
git log --oneline --no-merges "${prior[@]}" \
^$branch | tee -a "missing-commits.txt"
echo
fi
prior+=("${branch}")
done
if [[ $(cat missing-commits.txt | wc -l) -ne 0 ]]; then
echo "${MESSAGE}"
exit 1
fi

View File

@@ -46,46 +46,41 @@ jobs:
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- name: Generate outputs - name: Generate outputs
id: generate id: generate
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
run: | run: |
echo 'Generating user and channel.' echo 'Generating user and channel.'
echo "user=clio" >> "${GITHUB_OUTPUT}" echo "user=clio" >> "${GITHUB_OUTPUT}"
echo "channel=pr_${PR_NUMBER}" >> "${GITHUB_OUTPUT}" echo "channel=pr_${{ github.event.pull_request.number }}" >> "${GITHUB_OUTPUT}"
echo 'Extracting version.' echo 'Extracting version.'
echo "version=$(cat src/libxrpl/protocol/BuildInfo.cpp | grep "versionString =" | awk -F '"' '{print $2}')" >> "${GITHUB_OUTPUT}" echo "version=$(cat src/libxrpl/protocol/BuildInfo.cpp | grep "versionString =" | awk -F '"' '{print $2}')" >> "${GITHUB_OUTPUT}"
- name: Calculate conan reference - name: Calculate conan reference
id: conan_ref id: conan_ref
run: | run: |
echo "conan_ref=${{ steps.generate.outputs.version }}@${{ steps.generate.outputs.user }}/${{ steps.generate.outputs.channel }}" >> "${GITHUB_OUTPUT}" echo "conan_ref=${{ steps.generate.outputs.version }}@${{ steps.generate.outputs.user }}/${{ steps.generate.outputs.channel }}" >> "${GITHUB_OUTPUT}"
- name: Set up Conan - name: Set up Conan
uses: ./.github/actions/setup-conan uses: ./.github/actions/setup-conan
with: with:
conan_remote_name: ${{ inputs.conan_remote_name }} conan_remote_name: ${{ inputs.conan_remote_name }}
conan_remote_url: ${{ inputs.conan_remote_url }} conan_remote_url: ${{ inputs.conan_remote_url }}
- name: Log into Conan remote - name: Log into Conan remote
env: run: conan remote login ${{ inputs.conan_remote_name }} "${{ secrets.conan_remote_username }}" --password "${{ secrets.conan_remote_password }}"
CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }}
run: conan remote login "${CONAN_REMOTE_NAME}" "${{ secrets.conan_remote_username }}" --password "${{ secrets.conan_remote_password }}"
- name: Upload package - name: Upload package
env:
CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }}
run: | run: |
conan export --user=${{ steps.generate.outputs.user }} --channel=${{ steps.generate.outputs.channel }} . conan export --user=${{ steps.generate.outputs.user }} --channel=${{ steps.generate.outputs.channel }} .
conan upload --confirm --check --remote="${CONAN_REMOTE_NAME}" xrpl/${{ steps.conan_ref.outputs.conan_ref }} conan upload --confirm --check --remote=${{ inputs.conan_remote_name }} xrpl/${{ steps.conan_ref.outputs.conan_ref }}
outputs: outputs:
conan_ref: ${{ steps.conan_ref.outputs.conan_ref }} conan_ref: ${{ steps.conan_ref.outputs.conan_ref }}
notify: notify:
needs: upload needs: upload
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.clio_notify_token }}
steps: steps:
- name: Notify Clio - name: Notify Clio
env:
GH_TOKEN: ${{ secrets.clio_notify_token }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: | run: |
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" \ gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" \
/repos/xrplf/clio/dispatches -f "event_type=check_libxrpl" \ /repos/xrplf/clio/dispatches -f "event_type=check_libxrpl" \
-F "client_payload[conan_ref]=${{ needs.upload.outputs.conan_ref }}" \ -F "client_payload[conan_ref]=${{ needs.upload.outputs.conan_ref }}" \
-F "client_payload[pr_url]=${PR_URL}" -F "client_payload[pr_url]=${{ github.event.pull_request.html_url }}"

View File

@@ -18,10 +18,6 @@ on:
description: "The generated strategy matrix." description: "The generated strategy matrix."
value: ${{ jobs.generate-matrix.outputs.matrix }} value: ${{ jobs.generate-matrix.outputs.matrix }}
defaults:
run:
shell: bash
jobs: jobs:
generate-matrix: generate-matrix:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -39,7 +35,4 @@ jobs:
- name: Generate strategy matrix - name: Generate strategy matrix
working-directory: .github/scripts/strategy-matrix working-directory: .github/scripts/strategy-matrix
id: generate id: generate
env: run: ./generate.py ${{ inputs.strategy_matrix == 'all' && '--all' || '' }} ${{ inputs.os != '' && format('--config={0}.json', inputs.os) || '' }} >> "${GITHUB_OUTPUT}"
GENERATE_CONFIG: ${{ inputs.os != '' && format('--config={0}.json', inputs.os) || '' }}
GENERATE_OPTION: ${{ inputs.strategy_matrix == 'all' && '--all' || '' }}
run: ./generate.py ${GENERATE_OPTION} ${GENERATE_CONFIG} >> "${GITHUB_OUTPUT}"

View File

@@ -24,34 +24,30 @@ on:
branches: [develop] branches: [develop]
paths: paths:
- .github/workflows/upload-conan-deps.yml - .github/workflows/upload-conan-deps.yml
- .github/workflows/reusable-strategy-matrix.yml - .github/workflows/reusable-strategy-matrix.yml
- .github/actions/build-deps/action.yml - .github/actions/build-deps/action.yml
- .github/actions/setup-conan/action.yml - .github/actions/setup-conan/action.yml
- ".github/scripts/strategy-matrix/**" - ".github/scripts/strategy-matrix/**"
- conanfile.py - conanfile.py
- conan.lock - conan.lock
env: env:
CONAN_REMOTE_NAME: xrplf CONAN_REMOTE_NAME: xrplf
CONAN_REMOTE_URL: https://conan.ripplex.io CONAN_REMOTE_URL: https://conan.ripplex.io
NPROC_SUBTRACT: 2
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
defaults:
run:
shell: bash
jobs: jobs:
# Generate the strategy matrix to be used by the following job.
generate-matrix: generate-matrix:
uses: ./.github/workflows/reusable-strategy-matrix.yml uses: ./.github/workflows/reusable-strategy-matrix.yml
with: with:
strategy_matrix: ${{ github.event_name == 'pull_request' && 'minimal' || 'all' }} strategy_matrix: ${{ github.event_name == 'pull_request' && 'minimal' || 'all' }}
# Build and upload the dependencies for each configuration.
run-upload-conan-deps: run-upload-conan-deps:
needs: needs:
- generate-matrix - generate-matrix
@@ -60,29 +56,19 @@ jobs:
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
max-parallel: 10 max-parallel: 10
runs-on: ${{ matrix.architecture.runner }} runs-on: ${{ matrix.architecture.runner }}
container: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) || null }} container: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-5dd7158', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version) || null }}
steps: steps:
- name: Cleanup workspace (macOS and Windows) - name: Cleanup workspace
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }} if: ${{ runner.os == 'macOS' }}
uses: XRPLF/actions/.github/actions/cleanup-workspace@01b244d2718865d427b499822fbd3f15e7197fcc uses: XRPLF/actions/.github/actions/cleanup-workspace@3f044c7478548e3c32ff68980eeb36ece02b364e
- name: Checkout repository
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@99685816bb60a95a66852f212f382580e180df3a uses: XRPLF/actions/.github/actions/prepare-runner@638e0dc11ea230f91bd26622fb542116bb5254d5
with: with:
disable_ccache: false disable_ccache: false
- name: Print build environment
uses: ./.github/actions/print-env
- name: Get number of processors
uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a
id: nproc
with:
subtract: ${{ env.NPROC_SUBTRACT }}
- name: Setup Conan - name: Setup Conan
uses: ./.github/actions/setup-conan uses: ./.github/actions/setup-conan
with: with:
@@ -93,19 +79,13 @@ jobs:
uses: ./.github/actions/build-deps uses: ./.github/actions/build-deps
with: with:
build_dir: .build build_dir: .build
build_nproc: ${{ steps.nproc.outputs.nproc }}
build_type: ${{ matrix.build_type }} build_type: ${{ matrix.build_type }}
force_build: ${{ github.event_name == 'schedule' || github.event.inputs.force_source_build == 'true' }} force_build: ${{ github.event_name == 'schedule' || github.event.inputs.force_source_build == 'true' }}
# Set the verbosity to "quiet" for Windows to avoid an excessive
# amount of logs. For other OSes, the "verbose" logs are more useful.
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
- name: Log into Conan remote - name: Log into Conan remote
if: ${{ github.repository_owner == 'XRPLF' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }} if: ${{ github.repository_owner == 'XRPLF' && github.event_name != 'pull_request' }}
run: conan remote login "${CONAN_REMOTE_NAME}" "${{ secrets.CONAN_REMOTE_USERNAME }}" --password "${{ secrets.CONAN_REMOTE_PASSWORD }}" run: conan remote login ${{ env.CONAN_REMOTE_NAME }} "${{ secrets.CONAN_REMOTE_USERNAME }}" --password "${{ secrets.CONAN_REMOTE_PASSWORD }}"
- name: Upload Conan packages - name: Upload Conan packages
if: ${{ github.repository_owner == 'XRPLF' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }} if: ${{ github.repository_owner == 'XRPLF' && github.event_name != 'pull_request' && github.event_name != 'schedule' }}
env: run: conan upload "*" -r=${{ env.CONAN_REMOTE_NAME }} --confirm ${{ github.event.inputs.force_upload == 'true' && '--force' || '' }}
FORCE_OPTION: ${{ github.event.inputs.force_upload == 'true' && '--force' || '' }}
run: conan upload "*" --remote="${CONAN_REMOTE_NAME}" --confirm ${FORCE_OPTION}

View File

@@ -34,5 +34,6 @@ repos:
exclude: | exclude: |
(?x)^( (?x)^(
external/.*| external/.*|
.github/scripts/levelization/results/.*\.txt .github/scripts/levelization/results/.*\.txt|
conan\.lock
)$ )$

View File

@@ -39,12 +39,17 @@ found here](./docs/build/environment.md).
- [Python 3.11](https://www.python.org/downloads/), or higher - [Python 3.11](https://www.python.org/downloads/), or higher
- [Conan 2.17](https://conan.io/downloads.html)[^1], or higher - [Conan 2.17](https://conan.io/downloads.html)[^1], or higher
- [CMake 3.22](https://cmake.org/download/), or higher - [CMake 3.22](https://cmake.org/download/)[^2], or higher
[^1]: [^1]:
It is possible to build with Conan 1.60+, but the instructions are It is possible to build with Conan 1.60+, but the instructions are
significantly different, which is why we are not recommending it. significantly different, which is why we are not recommending it.
[^2]:
CMake 4 is not yet supported by all dependencies required by this project.
If you are affected by this issue, follow [conan workaround for cmake
4](#workaround-for-cmake-4)
`rippled` is written in the C++20 dialect and includes the `<concepts>` header. `rippled` is written in the C++20 dialect and includes the `<concepts>` header.
The [minimum compiler versions][2] required are: The [minimum compiler versions][2] required are:
@@ -142,6 +147,7 @@ git sparse-checkout set recipes/snappy
git sparse-checkout add recipes/soci git sparse-checkout add recipes/soci
git fetch origin master git fetch origin master
git checkout master git checkout master
conan export --version 2.4.1 external/wamr # TODO: needs to be added to the conan center index
conan export --version 1.1.10 recipes/snappy/all conan export --version 1.1.10 recipes/snappy/all
conan export --version 4.0.3 recipes/soci/all conan export --version 4.0.3 recipes/soci/all
rm -rf .git rm -rf .git
@@ -277,6 +283,21 @@ sed -i.bak -e 's|^arch=.*$|arch=x86_64|' $(conan config home)/profiles/default
sed -i.bak -e 's|^compiler\.runtime=.*$|compiler.runtime=static|' $(conan config home)/profiles/default sed -i.bak -e 's|^compiler\.runtime=.*$|compiler.runtime=static|' $(conan config home)/profiles/default
``` ```
#### Workaround for CMake 4
If your system CMake is version 4 rather than 3, you may have to configure Conan
profile to use CMake version 3 for dependencies, by adding the following two
lines to your profile:
```text
[tool_requires]
!cmake/*: cmake/[>=3 <4]
```
This will force Conan to download and use a locally cached CMake 3 version, and
is needed because some of the dependencies used by this project do not support
CMake 4.
#### Clang workaround for grpc #### Clang workaround for grpc
If your compiler is clang, version 19 or later, or apple-clang, version 17 or If your compiler is clang, version 19 or later, or apple-clang, version 17 or
@@ -495,18 +516,18 @@ A coverage report is created when the following steps are completed, in order:
1. `rippled` binary built with instrumentation data, enabled by the `coverage` 1. `rippled` binary built with instrumentation data, enabled by the `coverage`
option mentioned above option mentioned above
2. completed one or more run of the unit tests, which populates coverage capture data 2. completed run of unit tests, which populates coverage capture data
3. completed run of the `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`) 3. completed run of the `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`)
to assemble both instrumentation data and the coverage capture data into a coverage report to assemble both instrumentation data and the coverage capture data into a coverage report
The last step of the above is automated into a single target `coverage`. The instrumented The above steps are automated into a single target `coverage`. The instrumented
`rippled` binary can also be used for regular development or testing work, at `rippled` binary can also be used for regular development or testing work, at
the cost of extra disk space utilization and a small performance hit the cost of extra disk space utilization and a small performance hit
(to store coverage capture data). Since `rippled` binary is simply a dependency of the (to store coverage capture). In case of a spurious failure of unit tests, it is
coverage report target, it is possible to re-run the `coverage` target without possible to re-run the `coverage` target without rebuilding the `rippled` binary
rebuilding the `rippled` binary. Note, running of the unit tests before the `coverage` (since it is simply a dependency of the coverage report target). It is also possible
target is left to the developer. Each such run will append to the coverage data to select only specific tests for the purpose of the coverage report, by setting
collected in the build directory. the `coverage_test` variable in `cmake`
The default coverage report format is `html-details`, but the user The default coverage report format is `html-details`, but the user
can override it to any of the formats listed in `Builds/CMake/CodeCoverage.cmake` can override it to any of the formats listed in `Builds/CMake/CodeCoverage.cmake`
@@ -515,6 +536,11 @@ to generate more than one format at a time by setting the `coverage_extra_args`
variable in `cmake`. The specific command line used to run the `gcovr` tool will be variable in `cmake`. The specific command line used to run the `gcovr` tool will be
displayed if the `CODE_COVERAGE_VERBOSE` variable is set. displayed if the `CODE_COVERAGE_VERBOSE` variable is set.
By default, the code coverage tool runs parallel unit tests with `--unittest-jobs`
set to the number of available CPU cores. This may cause spurious test
errors on Apple. Developers can override the number of unit test jobs with
the `coverage_test_parallelism` variable in `cmake`.
Example use with some cmake variables set: Example use with some cmake variables set:
``` ```

View File

@@ -120,6 +120,7 @@ endif()
find_package(nudb REQUIRED) find_package(nudb REQUIRED)
find_package(date REQUIRED) find_package(date REQUIRED)
find_package(xxHash REQUIRED) find_package(xxHash REQUIRED)
find_package(wamr REQUIRED)
target_link_libraries(ripple_libs INTERFACE target_link_libraries(ripple_libs INTERFACE
ed25519::ed25519 ed25519::ed25519

View File

@@ -1249,6 +1249,39 @@
# Example: # Example:
# owner_reserve = 2000000 # 2 XRP # owner_reserve = 2000000 # 2 XRP
# #
# extension_compute_limit = <gas>
#
# The extension compute limit is the maximum amount of gas that can be
# consumed by a single transaction. The gas limit is used to prevent
# transactions from consuming too many resources.
#
# If this parameter is unspecified, rippled will use an internal
# default. Don't change this without understanding the consequences.
#
# Example:
# extension_compute_limit = 1000000 # 1 million gas
#
# extension_size_limit = <bytes>
#
# The extension size limit is the maximum size of a WASM extension in
# bytes. The size limit is used to prevent extensions from consuming
# too many resources.
#
# If this parameter is unspecified, rippled will use an internal
# default. Don't change this without understanding the consequences.
#
# Example:
# extension_size_limit = 100000 # 100 kb
#
# gas_price = <bytes>
#
# The gas price is the conversion between WASM gas and its price in drops.
#
# If this parameter is unspecified, rippled will use an internal
# default. Don't change this without understanding the consequences.
#
# Example:
# gas_price = 1000000 # 1 drop per gas
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# #
# 9. Misc Settings # 9. Misc Settings

View File

@@ -1,3 +1,21 @@
macro(group_sources_in source_dir curdir)
file(GLOB children RELATIVE ${source_dir}/${curdir}
${source_dir}/${curdir}/*)
foreach (child ${children})
if (IS_DIRECTORY ${source_dir}/${curdir}/${child})
group_sources_in(${source_dir} ${curdir}/${child})
else()
string(REPLACE "/" "\\" groupname ${curdir})
source_group(${groupname} FILES
${source_dir}/${curdir}/${child})
endif()
endforeach()
endmacro()
macro(group_sources curdir)
group_sources_in(${PROJECT_SOURCE_DIR} ${curdir})
endmacro()
macro (exclude_from_default target_) macro (exclude_from_default target_)
set_target_properties (${target_} PROPERTIES EXCLUDE_FROM_ALL ON) set_target_properties (${target_} PROPERTIES EXCLUDE_FROM_ALL ON)
set_target_properties (${target_} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD ON) set_target_properties (${target_} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD ON)

View File

@@ -109,9 +109,6 @@
# - add a new function add_code_coverage_to_target # - add a new function add_code_coverage_to_target
# - remove some unused code # - remove some unused code
# #
# 2025-11-11, Bronek Kozicki
# - make EXECUTABLE and EXECUTABLE_ARGS optional
#
# USAGE: # USAGE:
# #
# 1. Copy this file into your cmake modules path. # 1. Copy this file into your cmake modules path.
@@ -320,10 +317,6 @@ function(setup_target_for_coverage_gcovr)
set(Coverage_FORMAT xml) set(Coverage_FORMAT xml)
endif() endif()
if(NOT DEFINED Coverage_EXECUTABLE AND DEFINED Coverage_EXECUTABLE_ARGS)
message(FATAL_ERROR "EXECUTABLE_ARGS must not be set if EXECUTABLE is not set")
endif()
if("--output" IN_LIST GCOVR_ADDITIONAL_ARGS) if("--output" IN_LIST GCOVR_ADDITIONAL_ARGS)
message(FATAL_ERROR "Unsupported --output option detected in GCOVR_ADDITIONAL_ARGS! Aborting...") message(FATAL_ERROR "Unsupported --output option detected in GCOVR_ADDITIONAL_ARGS! Aborting...")
else() else()
@@ -405,18 +398,17 @@ function(setup_target_for_coverage_gcovr)
endforeach() endforeach()
# Set up commands which will be run to generate coverage data # Set up commands which will be run to generate coverage data
# If EXECUTABLE is not set, the user is expected to run the tests manually # Run tests
# before running the coverage target NAME set(GCOVR_EXEC_TESTS_CMD
if(DEFINED Coverage_EXECUTABLE) ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
set(GCOVR_EXEC_TESTS_CMD )
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
)
endif()
# Create folder # Create folder
if(DEFINED GCOVR_CREATE_FOLDER) if(DEFINED GCOVR_CREATE_FOLDER)
set(GCOVR_FOLDER_CMD set(GCOVR_FOLDER_CMD
${CMAKE_COMMAND} -E make_directory ${GCOVR_CREATE_FOLDER}) ${CMAKE_COMMAND} -E make_directory ${GCOVR_CREATE_FOLDER})
else()
set(GCOVR_FOLDER_CMD echo) # dummy
endif() endif()
# Running gcovr # Running gcovr
@@ -433,13 +425,11 @@ function(setup_target_for_coverage_gcovr)
if(CODE_COVERAGE_VERBOSE) if(CODE_COVERAGE_VERBOSE)
message(STATUS "Executed command report") message(STATUS "Executed command report")
if(NOT "${GCOVR_EXEC_TESTS_CMD}" STREQUAL "") message(STATUS "Command to run tests: ")
message(STATUS "Command to run tests: ") string(REPLACE ";" " " GCOVR_EXEC_TESTS_CMD_SPACED "${GCOVR_EXEC_TESTS_CMD}")
string(REPLACE ";" " " GCOVR_EXEC_TESTS_CMD_SPACED "${GCOVR_EXEC_TESTS_CMD}") message(STATUS "${GCOVR_EXEC_TESTS_CMD_SPACED}")
message(STATUS "${GCOVR_EXEC_TESTS_CMD_SPACED}")
endif()
if(NOT "${GCOVR_FOLDER_CMD}" STREQUAL "") if(NOT GCOVR_FOLDER_CMD STREQUAL "echo")
message(STATUS "Command to create a folder: ") message(STATUS "Command to create a folder: ")
string(REPLACE ";" " " GCOVR_FOLDER_CMD_SPACED "${GCOVR_FOLDER_CMD}") string(REPLACE ";" " " GCOVR_FOLDER_CMD_SPACED "${GCOVR_FOLDER_CMD}")
message(STATUS "${GCOVR_FOLDER_CMD_SPACED}") message(STATUS "${GCOVR_FOLDER_CMD_SPACED}")

View File

@@ -12,7 +12,7 @@ if (static OR MSVC)
else () else ()
set (Boost_USE_STATIC_RUNTIME OFF) set (Boost_USE_STATIC_RUNTIME OFF)
endif () endif ()
find_dependency (Boost find_dependency (Boost 1.70
COMPONENTS COMPONENTS
chrono chrono
container container
@@ -52,3 +52,5 @@ if (TARGET ZLIB::ZLIB)
set_target_properties(OpenSSL::Crypto PROPERTIES set_target_properties(OpenSSL::Crypto PROPERTIES
INTERFACE_LINK_LIBRARIES ZLIB::ZLIB) INTERFACE_LINK_LIBRARIES ZLIB::ZLIB)
endif () endif ()
include ("${CMAKE_CURRENT_LIST_DIR}/RippleTargets.cmake")

View File

@@ -65,14 +65,23 @@ target_link_libraries(xrpl.imports.main
xrpl.libpb xrpl.libpb
xxHash::xxhash xxHash::xxhash
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp> $<$<BOOL:${voidstar}>:antithesis-sdk-cpp>
wamr::wamr
) )
if (WIN32)
target_link_libraries(xrpl.imports.main INTERFACE ntdll)
endif()
include(add_module) include(add_module)
include(target_link_modules) include(target_link_modules)
# Level 01 # Level 01
add_module(xrpl beast) add_module(xrpl beast)
target_link_libraries(xrpl.libxrpl.beast PUBLIC xrpl.imports.main) target_link_libraries(xrpl.libxrpl.beast PUBLIC
xrpl.imports.main
xrpl.libpb
)
# Level 02 # Level 02
add_module(xrpl basics) add_module(xrpl basics)

View File

@@ -11,9 +11,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
return() return()
endif() endif()
include(ProcessorCount)
ProcessorCount(PROCESSOR_COUNT)
include(CodeCoverage) include(CodeCoverage)
# The instructions for these commands come from the `CodeCoverage` module, # The instructions for these commands come from the `CodeCoverage` module,
@@ -29,13 +26,15 @@ list(APPEND GCOVR_ADDITIONAL_ARGS
--exclude-throw-branches --exclude-throw-branches
--exclude-noncode-lines --exclude-noncode-lines
--exclude-unreachable-branches -s --exclude-unreachable-branches -s
-j ${PROCESSOR_COUNT}) -j ${coverage_test_parallelism})
setup_target_for_coverage_gcovr( setup_target_for_coverage_gcovr(
NAME coverage NAME coverage
FORMAT ${coverage_format} FORMAT ${coverage_format}
EXECUTABLE rippled
EXECUTABLE_ARGS --unittest$<$<BOOL:${coverage_test}>:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log
EXCLUDE "src/test" "src/tests" "include/xrpl/beast/test" "include/xrpl/beast/unit_test" "${CMAKE_BINARY_DIR}/pb-xrpl.libpb" EXCLUDE "src/test" "src/tests" "include/xrpl/beast/test" "include/xrpl/beast/unit_test" "${CMAKE_BINARY_DIR}/pb-xrpl.libpb"
DEPENDENCIES rippled xrpl.tests DEPENDENCIES rippled
) )
add_code_coverage_to_target(opts INTERFACE) add_code_coverage_to_target(opts INTERFACE)

View File

@@ -1,5 +1,5 @@
#[===================================================================[ #[===================================================================[
sanity checks convenience variables and sanity checks
#]===================================================================] #]===================================================================]
get_property(is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) get_property(is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
@@ -16,19 +16,39 @@ if (NOT is_multiconfig)
endif () endif ()
endif () endif ()
get_directory_property(has_parent PARENT_DIRECTORY)
if (has_parent)
set (is_root_project OFF)
else ()
set (is_root_project ON)
endif ()
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES ".*Clang") # both Clang and AppleClang if ("${CMAKE_CXX_COMPILER_ID}" MATCHES ".*Clang") # both Clang and AppleClang
set (is_clang TRUE) set (is_clang TRUE)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND
CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0) CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
message (FATAL_ERROR "This project requires clang 16 or later") message (FATAL_ERROR "This project requires clang 8 or later")
endif () endif ()
# TODO min AppleClang version check ?
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set (is_gcc TRUE) set (is_gcc TRUE)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0) if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0)
message (FATAL_ERROR "This project requires GCC 12 or later") message (FATAL_ERROR "This project requires GCC 8 or later")
endif () endif ()
endif () endif ()
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
set (is_linux TRUE)
else ()
set (is_linux FALSE)
endif ()
if ("$ENV{CI}" STREQUAL "true" OR "$ENV{CONTINUOUS_INTEGRATION}" STREQUAL "true")
set (is_ci TRUE)
else ()
set (is_ci FALSE)
endif ()
# check for in-source build and fail # check for in-source build and fail
if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message (FATAL_ERROR "Builds (in-source) are not allowed in " message (FATAL_ERROR "Builds (in-source) are not allowed in "

View File

@@ -1,25 +1,10 @@
#[===================================================================[ #[===================================================================[
declare options and variables declare user options/settings
#]===================================================================] #]===================================================================]
if(CMAKE_SYSTEM_NAME STREQUAL "Linux") include(ProcessorCount)
set (is_linux TRUE)
else()
set(is_linux FALSE)
endif()
if("$ENV{CI}" STREQUAL "true" OR "$ENV{CONTINUOUS_INTEGRATION}" STREQUAL "true") ProcessorCount(PROCESSOR_COUNT)
set(is_ci TRUE)
else()
set(is_ci FALSE)
endif()
get_directory_property(has_parent PARENT_DIRECTORY)
if(has_parent)
set(is_root_project OFF)
else()
set(is_root_project ON)
endif()
option(assert "Enables asserts, even in release builds" OFF) option(assert "Enables asserts, even in release builds" OFF)
@@ -40,28 +25,29 @@ if(unity)
endif() endif()
set(CMAKE_UNITY_BUILD ON CACHE BOOL "Do a unity build") set(CMAKE_UNITY_BUILD ON CACHE BOOL "Do a unity build")
endif() endif()
if(is_clang AND is_linux) if(is_clang AND is_linux)
option(voidstar "Enable Antithesis instrumentation." OFF) option(voidstar "Enable Antithesis instrumentation." OFF)
endif() endif()
if(is_gcc OR is_clang) if(is_gcc OR is_clang)
include(ProcessorCount)
ProcessorCount(PROCESSOR_COUNT)
option(coverage "Generates coverage info." OFF) option(coverage "Generates coverage info." OFF)
option(profile "Add profiling flags" OFF) option(profile "Add profiling flags" OFF)
set(coverage_test_parallelism "${PROCESSOR_COUNT}" CACHE STRING
"Unit tests parallelism for the purpose of coverage report.")
set(coverage_format "html-details" CACHE STRING set(coverage_format "html-details" CACHE STRING
"Output format of the coverage report.") "Output format of the coverage report.")
set(coverage_extra_args "" CACHE STRING set(coverage_extra_args "" CACHE STRING
"Additional arguments to pass to gcovr.") "Additional arguments to pass to gcovr.")
set(coverage_test "" CACHE STRING
"On gcc & clang, the specific unit test(s) to run for coverage. Default is all tests.")
if(coverage_test AND NOT coverage)
set(coverage ON CACHE BOOL "gcc/clang only" FORCE)
endif()
option(wextra "compile with extra gcc/clang warnings enabled" ON) option(wextra "compile with extra gcc/clang warnings enabled" ON)
else() else()
set(profile OFF CACHE BOOL "gcc/clang only" FORCE) set(profile OFF CACHE BOOL "gcc/clang only" FORCE)
set(coverage OFF CACHE BOOL "gcc/clang only" FORCE) set(coverage OFF CACHE BOOL "gcc/clang only" FORCE)
set(wextra OFF CACHE BOOL "gcc/clang only" FORCE) set(wextra OFF CACHE BOOL "gcc/clang only" FORCE)
endif() endif()
if(is_linux) if(is_linux)
option(BUILD_SHARED_LIBS "build shared ripple libraries" OFF) option(BUILD_SHARED_LIBS "build shared ripple libraries" OFF)
option(static "link protobuf, openssl, libc++, and boost statically" ON) option(static "link protobuf, openssl, libc++, and boost statically" ON)
@@ -78,13 +64,11 @@ else()
set(use_gold OFF CACHE BOOL "gold linker, linux only" FORCE) set(use_gold OFF CACHE BOOL "gold linker, linux only" FORCE)
set(use_mold OFF CACHE BOOL "mold linker, linux only" FORCE) set(use_mold OFF CACHE BOOL "mold linker, linux only" FORCE)
endif() endif()
if(is_clang) if(is_clang)
option(use_lld "enables detection of lld linker" ON) option(use_lld "enables detection of lld linker" ON)
else() else()
set(use_lld OFF CACHE BOOL "try lld linker, clang only" FORCE) set(use_lld OFF CACHE BOOL "try lld linker, clang only" FORCE)
endif() endif()
option(jemalloc "Enables jemalloc for heap profiling" OFF) option(jemalloc "Enables jemalloc for heap profiling" OFF)
option(werr "treat warnings as errors" OFF) option(werr "treat warnings as errors" OFF)
option(local_protobuf option(local_protobuf
@@ -118,26 +102,38 @@ if(san)
message(FATAL_ERROR "${san} sanitizer does not seem to be supported by your compiler") message(FATAL_ERROR "${san} sanitizer does not seem to be supported by your compiler")
endif() endif()
endif() endif()
set(container_label "" CACHE STRING "tag to use for package building containers")
option(packages_only
"ONLY generate package building targets. This is special use-case and almost \
certainly not what you want. Use with caution as you won't be able to build \
any compiled targets locally." OFF)
option(have_package_container
"Sometimes you already have the tagged container you want to use for package \
building and you don't want docker to rebuild it. This flag will detach the \
dependency of the package build from the container build. It's an advanced \
use case and most likely you should not be touching this flag." OFF)
# the remaining options are obscure and rarely used # the remaining options are obscure and rarely used
option(beast_no_unit_test_inline option(beast_no_unit_test_inline
"Prevents unit test definitions from being inserted into global table" "Prevents unit test definitions from being inserted into global table"
OFF) OFF)
option(single_io_service_thread option(single_io_service_thread
"Restricts the number of threads calling io_service::run to one. \ "Restricts the number of threads calling io_context::run to one. \
This can be useful when debugging." This can be useful when debugging."
OFF) OFF)
option(boost_show_deprecated option(boost_show_deprecated
"Allow boost to fail on deprecated usage. Only useful if you're trying\ "Allow boost to fail on deprecated usage. Only useful if you're trying\
to find deprecated calls." to find deprecated calls."
OFF) OFF)
option(beast_hashers
"Use local implementations for sha/ripemd hashes (experimental, not recommended)"
OFF)
if(WIN32) if(WIN32)
option(beast_disable_autolink "Disables autolinking of system libraries on WIN32" OFF) option(beast_disable_autolink "Disables autolinking of system libraries on WIN32" OFF)
else() else()
set(beast_disable_autolink OFF CACHE BOOL "WIN32 only" FORCE) set(beast_disable_autolink OFF CACHE BOOL "WIN32 only" FORCE)
endif() endif()
if(coverage) if(coverage)
message(STATUS "coverage build requested - forcing Debug build") message(STATUS "coverage build requested - forcing Debug build")
set(CMAKE_BUILD_TYPE Debug CACHE STRING "build type" FORCE) set(CMAKE_BUILD_TYPE Debug CACHE STRING "build type" FORCE)

View File

@@ -24,6 +24,7 @@ target_link_libraries(ripple_boost
Boost::date_time Boost::date_time
Boost::filesystem Boost::filesystem
Boost::json Boost::json
Boost::process
Boost::program_options Boost::program_options
Boost::regex Boost::regex
Boost::system Boost::system

View File

@@ -7,7 +7,7 @@ function(xrpl_add_test name)
"${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp"
) )
add_executable(${target} ${ARGN} ${sources}) add_executable(${target} EXCLUDE_FROM_ALL ${ARGN} ${sources})
isolate_headers( isolate_headers(
${target} ${target}
@@ -22,4 +22,20 @@ function(xrpl_add_test name)
UNITY_BUILD_BATCH_SIZE 0) # Adjust as needed UNITY_BUILD_BATCH_SIZE 0) # Adjust as needed
add_test(NAME ${target} COMMAND ${target}) add_test(NAME ${target} COMMAND ${target})
set_tests_properties(
${target} PROPERTIES
FIXTURES_REQUIRED ${target}_fixture
)
add_test(
NAME ${target}.build
COMMAND
${CMAKE_COMMAND}
--build ${CMAKE_BINARY_DIR}
--config $<CONFIG>
--target ${target}
)
set_tests_properties(${target}.build PROPERTIES
FIXTURES_SETUP ${target}_fixture
)
endfunction() endfunction()

View File

@@ -3,6 +3,7 @@
"requires": [ "requires": [
"zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1756234269.497", "zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1756234269.497",
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1756234289.683", "xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1756234289.683",
"wamr/2.4.1#731b101bc8fa06d84e5c84edb4dc41a5%1756223745.11",
"sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1756234266.869", "sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1756234266.869",
"soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1756234262.318", "soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1756234262.318",
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1756234314.246", "snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1756234314.246",
@@ -21,7 +22,7 @@
"date/3.0.4#f74bbba5a08fa388256688743136cb6f%1756234217.493", "date/3.0.4#f74bbba5a08fa388256688743136cb6f%1756234217.493",
"c-ares/1.34.5#b78b91e7cfb1f11ce777a285bbf169c6%1756234217.915", "c-ares/1.34.5#b78b91e7cfb1f11ce777a285bbf169c6%1756234217.915",
"bzip2/1.0.8#00b4a4658791c1f06914e087f0e792f5%1756234261.716", "bzip2/1.0.8#00b4a4658791c1f06914e087f0e792f5%1756234261.716",
"boost/1.83.0#5d975011d65b51abb2d2f6eb8386b368%1754325043.336", "boost/1.88.0#8852c0b72ce8271fb8ff7c53456d4983%1756223752.326",
"abseil/20230802.1#f0f91485b111dc9837a68972cb19ca7b%1756234220.907" "abseil/20230802.1#f0f91485b111dc9837a68972cb19ca7b%1756234220.907"
], ],
"build_requires": [ "build_requires": [
@@ -46,7 +47,7 @@
"lz4/1.10.0" "lz4/1.10.0"
], ],
"boost/1.83.0": [ "boost/1.83.0": [
"boost/1.83.0" "boost/1.88.0"
], ],
"sqlite3/3.44.2": [ "sqlite3/3.44.2": [
"sqlite3/3.49.1" "sqlite3/3.49.1"

View File

@@ -1,5 +1,9 @@
# Global configuration for Conan. This is used to set the number of parallel # Global configuration for Conan. This is used to set the number of parallel
# downloads and uploads. # downloads, uploads, and build jobs. The verbosity is set to verbose to
# provide more information during the build process.
core:non_interactive=True core:non_interactive=True
core.download:parallel={{ os.cpu_count() }} core.download:parallel={{ os.cpu_count() }}
core.upload:parallel={{ os.cpu_count() }} core.upload:parallel={{ os.cpu_count() }}
tools.build:jobs={{ (os.cpu_count() * 4/5) | int }}
tools.build:verbosity=verbose
tools.compilation:verbosity=verbose

View File

@@ -21,14 +21,14 @@ compiler.libcxx={{detect_api.detect_libcxx(compiler, version, compiler_exe)}}
[conf] [conf]
{% if compiler == "clang" and compiler_version >= 19 %} {% if compiler == "clang" and compiler_version >= 19 %}
grpc/1.50.1:tools.build:cxxflags+=['-Wno-missing-template-arg-list-after-template-kw'] tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
{% endif %} {% endif %}
{% if compiler == "apple-clang" and compiler_version >= 17 %} {% if compiler == "apple-clang" and compiler_version >= 17 %}
grpc/1.50.1:tools.build:cxxflags+=['-Wno-missing-template-arg-list-after-template-kw'] tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
{% endif %}
{% if compiler == "clang" and compiler_version == 16 %}
tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS']
{% endif %} {% endif %}
{% if compiler == "gcc" and compiler_version < 13 %} {% if compiler == "gcc" and compiler_version < 13 %}
tools.build:cxxflags+=['-Wno-restrict'] tools.build:cxxflags=['-Wno-restrict']
{% endif %} {% endif %}
[tool_requires]
!cmake/*: cmake/[>=3 <4]

View File

@@ -2,6 +2,7 @@ from conan import ConanFile, __version__ as conan_version
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
import re import re
class Xrpl(ConanFile): class Xrpl(ConanFile):
name = 'xrpl' name = 'xrpl'
@@ -30,6 +31,7 @@ class Xrpl(ConanFile):
'openssl/1.1.1w', 'openssl/1.1.1w',
'soci/4.0.3', 'soci/4.0.3',
'zlib/1.3.1', 'zlib/1.3.1',
'wamr/2.4.1',
] ]
test_requires = [ test_requires = [
@@ -100,11 +102,13 @@ class Xrpl(ConanFile):
def configure(self): def configure(self):
if self.settings.compiler == 'apple-clang': if self.settings.compiler == 'apple-clang':
self.options['boost'].visibility = 'global' self.options['boost'].visibility = 'global'
if self.settings.compiler in ['clang', 'gcc']:
self.options['boost'].without_cobalt = True
def requirements(self): def requirements(self):
# Conan 2 requires transitive headers to be specified # Conan 2 requires transitive headers to be specified
transitive_headers_opt = {'transitive_headers': True} if conan_version.split('.')[0] == '2' else {} transitive_headers_opt = {'transitive_headers': True} if conan_version.split('.')[0] == '2' else {}
self.requires('boost/1.83.0', force=True, **transitive_headers_opt) self.requires('boost/1.88.0', force=True, **transitive_headers_opt)
self.requires('date/3.0.4', **transitive_headers_opt) self.requires('date/3.0.4', **transitive_headers_opt)
self.requires('lz4/1.10.0', force=True) self.requires('lz4/1.10.0', force=True)
self.requires('protobuf/3.21.12', force=True) self.requires('protobuf/3.21.12', force=True)
@@ -131,6 +135,7 @@ class Xrpl(ConanFile):
self.folders.generators = 'build/generators' self.folders.generators = 'build/generators'
generators = 'CMakeDeps' generators = 'CMakeDeps'
def generate(self): def generate(self):
tc = CMakeToolchain(self) tc = CMakeToolchain(self)
tc.variables['tests'] = self.options.tests tc.variables['tests'] = self.options.tests
@@ -175,6 +180,7 @@ class Xrpl(ConanFile):
'boost::filesystem', 'boost::filesystem',
'boost::json', 'boost::json',
'boost::program_options', 'boost::program_options',
'boost::process',
'boost::regex', 'boost::regex',
'boost::system', 'boost::system',
'boost::thread', 'boost::thread',
@@ -187,6 +193,7 @@ class Xrpl(ConanFile):
'protobuf::libprotobuf', 'protobuf::libprotobuf',
'soci::soci', 'soci::soci',
'sqlite3::sqlite', 'sqlite3::sqlite',
'wamr::wamr',
'xxhash::xxhash', 'xxhash::xxhash',
'zlib::zlib', 'zlib::zlib',
] ]

View File

@@ -541,7 +541,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
/** Verify an ECDSA signature. /** Verify an ECDSA signature.
* *
* Returns: 1: correct signature * Returns: 1: correct signature
* 0: incorrect or unparsable signature * 0: incorrect or unparseable signature
* Args: ctx: pointer to a context object * Args: ctx: pointer to a context object
* In: sig: the signature being verified. * In: sig: the signature being verified.
* msghash32: the 32-byte message hash being verified. * msghash32: the 32-byte message hash being verified.

88
external/wamr/conanfile.py vendored Normal file
View File

@@ -0,0 +1,88 @@
from conan import ConanFile, tools
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps, cmake_layout
#from conan.tools.files import (apply_conandata_patches, export_conandata_patches,)
from conan.tools.scm import Git
# import os
required_conan_version = ">=1.55.0"
class WamrConan(ConanFile):
name = "wamr"
version = "2.4.1"
license = "Apache License v2.0"
url = "https://github.com/ripple/wasm-micro-runtime.git"
description = "Webassembly micro runtime"
package_type = "library"
settings = "os", "compiler", "build_type", "arch"
options = {"shared": [True, False], "fPIC": [True, False]}
default_options = {"shared": False, "fPIC": True}
# requires = [("llvm/20.1.1@")]
def export_sources(self):
#export_conandata_patches(self)
pass
# def build_requirements(self):
# self.tool_requires("llvm/20.1.1")
def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
def layout(self):
cmake_layout(self, src_folder="src")
def source(self):
git = Git(self)
git.fetch_commit(
url="https://github.com/ripple/wasm-micro-runtime.git",
commit="a87e56fe8042bbe3ed99a514333ddef42e6c2a41",
)
# get(self, **self.conan_data["sources"][self.version], strip_root=True)
def generate(self):
tc = CMakeToolchain(self)
tc.variables["WAMR_BUILD_INTERP"] = 1
tc.variables["WAMR_BUILD_FAST_INTERP"] = 1
tc.variables["WAMR_BUILD_INSTRUCTION_METERING"] = 1
tc.variables["WAMR_BUILD_AOT"] = 0
tc.variables["WAMR_BUILD_JIT"] = 0
tc.variables["WAMR_BUILD_FAST_JIT"] = 0
tc.variables["WAMR_BUILD_SIMD"] = 0
tc.variables["WAMR_BUILD_LIB_PTHREAD"] = 0
tc.variables["WAMR_BUILD_LIB_WASI_THREADS"] = 0
tc.variables["WAMR_BUILD_TAIL_CALL"] = 1
tc.variables["WAMR_BUILD_BULK_MEMORY"] = 0
tc.variables["WAMR_DISABLE_HW_BOUND_CHECK"] = 1
tc.variables["WAMR_DISABLE_STACK_HW_BOUND_CHECK"] = 1
tc.variables["WAMR_BH_LOG"] = "wamr_log_to_rippled"
tc.generate()
# This generates "foo-config.cmake" and "bar-config.cmake" in self.generators_folder
deps = CMakeDeps(self)
deps.generate()
def build(self):
#apply_conandata_patches(self)
cmake = CMake(self)
cmake.verbose = True
cmake.configure()
cmake.build()
# self.run(f'echo {self.source_folder}')
# Explicit way:
# self.run('cmake %s/hello %s' % (self.source_folder, cmake.command_line))
# self.run("cmake --build . %s" % cmake.build_config)
def package(self):
cmake = CMake(self)
cmake.verbose = True
cmake.install()
def package_info(self):
self.cpp_info.libs = ["iwasm"]
self.cpp_info.names["cmake_find_package"] = "wamr"
self.cpp_info.names["cmake_find_package_multi"] = "wamr"

View File

@@ -654,14 +654,12 @@ SharedWeakUnion<T>::convertToWeak()
break; break;
case destroy: case destroy:
// We just added a weak ref. How could we destroy? // We just added a weak ref. How could we destroy?
// LCOV_EXCL_START
UNREACHABLE( UNREACHABLE(
"ripple::SharedWeakUnion::convertToWeak : destroying freshly " "ripple::SharedWeakUnion::convertToWeak : destroying freshly "
"added ref"); "added ref");
delete p; delete p;
unsafeSetRawPtr(nullptr); unsafeSetRawPtr(nullptr);
return true; // Should never happen return true; // Should never happen
// LCOV_EXCL_STOP
case partialDestroy: case partialDestroy:
// This is a weird case. We just converted the last strong // This is a weird case. We just converted the last strong
// pointer to a weak pointer. // pointer to a weak pointer.

View File

@@ -32,15 +32,6 @@ class Number;
std::string std::string
to_string(Number const& amount); to_string(Number const& amount);
template <typename T>
constexpr bool
isPowerOfTen(T value)
{
while (value >= 10 && value % 10 == 0)
value /= 10;
return value == 1;
}
class Number class Number
{ {
using rep = std::int64_t; using rep = std::int64_t;
@@ -50,9 +41,7 @@ class Number
public: public:
// The range for the mantissa when normalized // The range for the mantissa when normalized
constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL; constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL;
static_assert(isPowerOfTen(minMantissa)); constexpr static std::int64_t maxMantissa = 9'999'999'999'999'999LL;
constexpr static std::int64_t maxMantissa = minMantissa * 10 - 1;
static_assert(maxMantissa == 9'999'999'999'999'999LL);
// The range for the exponent when normalized // The range for the exponent when normalized
constexpr static int minExponent = -32768; constexpr static int minExponent = -32768;
@@ -162,7 +151,22 @@ public:
} }
Number Number
truncate() const noexcept; truncate() const noexcept
{
if (exponent_ >= 0 || mantissa_ == 0)
return *this;
Number ret = *this;
while (ret.exponent_ < 0 && ret.mantissa_ != 0)
{
ret.exponent_ += 1;
ret.mantissa_ /= rep(10);
}
// We are guaranteed that normalize() will never throw an exception
// because exponent is either negative or zero at this point.
ret.normalize();
return ret;
}
friend constexpr bool friend constexpr bool
operator>(Number const& x, Number const& y) noexcept operator>(Number const& x, Number const& y) noexcept
@@ -207,8 +211,6 @@ private:
class Guard; class Guard;
}; };
constexpr static Number numZero{};
inline constexpr Number::Number(rep mantissa, int exponent, unchecked) noexcept inline constexpr Number::Number(rep mantissa, int exponent, unchecked) noexcept
: mantissa_{mantissa}, exponent_{exponent} : mantissa_{mantissa}, exponent_{exponent}
{ {
@@ -358,6 +360,10 @@ abs(Number x) noexcept
Number Number
power(Number const& f, unsigned n); power(Number const& f, unsigned n);
// logarithm with base 10
Number
lg(Number const& value);
// Returns f^(1/d) // Returns f^(1/d)
// Uses NewtonRaphson iterations until the result stops changing // Uses NewtonRaphson iterations until the result stops changing
// to find the root of the polynomial g(x) = x^d - f // to find the root of the polynomial g(x) = x^d - f

View File

@@ -23,7 +23,7 @@
#include <xrpl/basics/Resolver.h> #include <xrpl/basics/Resolver.h>
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
namespace ripple { namespace ripple {
@@ -33,7 +33,7 @@ public:
explicit ResolverAsio() = default; explicit ResolverAsio() = default;
static std::unique_ptr<ResolverAsio> static std::unique_ptr<ResolverAsio>
New(boost::asio::io_service&, beast::Journal); New(boost::asio::io_context&, beast::Journal);
}; };
} // namespace ripple } // namespace ripple

View File

@@ -176,7 +176,7 @@ public:
@param count the number of items the slab allocator can allocate; note @param count the number of items the slab allocator can allocate; note
that a count of 0 is valid and means that the allocator that a count of 0 is valid and means that the allocator
is, effectively, disabled. This can be very useful in some is, effectively, disabled. This can be very useful in some
contexts (e.g. when minimal memory usage is needed) and contexts (e.g. when mimimal memory usage is needed) and
allows for graceful failure. allows for graceful failure.
*/ */
constexpr explicit SlabAllocator( constexpr explicit SlabAllocator(

View File

@@ -565,7 +565,7 @@ operator<=>(base_uint<Bits, Tag> const& lhs, base_uint<Bits, Tag> const& rhs)
// This comparison might seem wrong on a casual inspection because it // This comparison might seem wrong on a casual inspection because it
// compares data internally stored as std::uint32_t byte-by-byte. But // compares data internally stored as std::uint32_t byte-by-byte. But
// note that the underlying data is stored in big endian, even if the // note that the underlying data is stored in big endian, even if the
// platform is little endian. This makes the comparison correct. // plaform is little endian. This makes the comparison correct.
// //
// FIXME: use std::lexicographical_compare_three_way once support is // FIXME: use std::lexicographical_compare_three_way once support is
// added to MacOS. // added to MacOS.

View File

@@ -28,7 +28,7 @@ namespace ripple {
/* /*
* MSVC 2019 version 16.9.0 added [[nodiscard]] to the std comparison * MSVC 2019 version 16.9.0 added [[nodiscard]] to the std comparison
* operator() functions. boost::bimap checks that the comparator is a * operator() functions. boost::bimap checks that the comparitor is a
* BinaryFunction, in part by calling the function and ignoring the value. * BinaryFunction, in part by calling the function and ignoring the value.
* These two things don't play well together. These wrapper classes simply * These two things don't play well together. These wrapper classes simply
* strip [[nodiscard]] from operator() for use in boost::bimap. * strip [[nodiscard]] from operator() for use in boost::bimap.

View File

@@ -23,7 +23,8 @@
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <boost/asio/basic_waitable_timer.hpp> #include <boost/asio/basic_waitable_timer.hpp>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <chrono> #include <chrono>
#include <condition_variable> #include <condition_variable>
@@ -32,7 +33,7 @@
namespace beast { namespace beast {
/** Measures handler latency on an io_service queue. */ /** Measures handler latency on an io_context queue. */
template <class Clock> template <class Clock>
class io_latency_probe class io_latency_probe
{ {
@@ -44,12 +45,12 @@ private:
std::condition_variable_any m_cond; std::condition_variable_any m_cond;
std::size_t m_count; std::size_t m_count;
duration const m_period; duration const m_period;
boost::asio::io_service& m_ios; boost::asio::io_context& m_ios;
boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer; boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer;
bool m_cancel; bool m_cancel;
public: public:
io_latency_probe(duration const& period, boost::asio::io_service& ios) io_latency_probe(duration const& period, boost::asio::io_context& ios)
: m_count(1) : m_count(1)
, m_period(period) , m_period(period)
, m_ios(ios) , m_ios(ios)
@@ -64,16 +65,16 @@ public:
cancel(lock, true); cancel(lock, true);
} }
/** Return the io_service associated with the latency probe. */ /** Return the io_context associated with the latency probe. */
/** @{ */ /** @{ */
boost::asio::io_service& boost::asio::io_context&
get_io_service() get_io_context()
{ {
return m_ios; return m_ios;
} }
boost::asio::io_service const& boost::asio::io_context const&
get_io_service() const get_io_context() const
{ {
return m_ios; return m_ios;
} }
@@ -109,8 +110,10 @@ public:
std::lock_guard lock(m_mutex); std::lock_guard lock(m_mutex);
if (m_cancel) if (m_cancel)
throw std::logic_error("io_latency_probe is canceled"); throw std::logic_error("io_latency_probe is canceled");
m_ios.post(sample_op<Handler>( boost::asio::post(
std::forward<Handler>(handler), Clock::now(), false, this)); m_ios,
sample_op<Handler>(
std::forward<Handler>(handler), Clock::now(), false, this));
} }
/** Initiate continuous i/o latency sampling. /** Initiate continuous i/o latency sampling.
@@ -124,8 +127,10 @@ public:
std::lock_guard lock(m_mutex); std::lock_guard lock(m_mutex);
if (m_cancel) if (m_cancel)
throw std::logic_error("io_latency_probe is canceled"); throw std::logic_error("io_latency_probe is canceled");
m_ios.post(sample_op<Handler>( boost::asio::post(
std::forward<Handler>(handler), Clock::now(), true, this)); m_ios,
sample_op<Handler>(
std::forward<Handler>(handler), Clock::now(), true, this));
} }
private: private:
@@ -236,12 +241,13 @@ private:
// The latency is too high to maintain the desired // The latency is too high to maintain the desired
// period so don't bother with a timer. // period so don't bother with a timer.
// //
m_probe->m_ios.post( boost::asio::post(
m_probe->m_ios,
sample_op<Handler>(m_handler, now, m_repeat, m_probe)); sample_op<Handler>(m_handler, now, m_repeat, m_probe));
} }
else else
{ {
m_probe->m_timer.expires_from_now(when - now); m_probe->m_timer.expires_after(when - now);
m_probe->m_timer.async_wait( m_probe->m_timer.async_wait(
sample_op<Handler>(m_handler, now, m_repeat, m_probe)); sample_op<Handler>(m_handler, now, m_repeat, m_probe));
} }
@@ -254,7 +260,8 @@ private:
if (!m_probe) if (!m_probe)
return; return;
typename Clock::time_point const now(Clock::now()); typename Clock::time_point const now(Clock::now());
m_probe->m_ios.post( boost::asio::post(
m_probe->m_ios,
sample_op<Handler>(m_handler, now, m_repeat, m_probe)); sample_op<Handler>(m_handler, now, m_repeat, m_probe));
} }
}; };

View File

@@ -94,11 +94,7 @@ hash_append(Hasher& h, beast::IP::Address const& addr) noexcept
else if (addr.is_v6()) else if (addr.is_v6())
hash_append(h, addr.to_v6().to_bytes()); hash_append(h, addr.to_v6().to_bytes());
else else
{
// LCOV_EXCL_START
UNREACHABLE("beast::hash_append : invalid address type"); UNREACHABLE("beast::hash_append : invalid address type");
// LCOV_EXCL_STOP
}
} }
} // namespace beast } // namespace beast

View File

@@ -8,9 +8,11 @@
#ifndef BEAST_TEST_YIELD_TO_HPP #ifndef BEAST_TEST_YIELD_TO_HPP
#define BEAST_TEST_YIELD_TO_HPP #define BEAST_TEST_YIELD_TO_HPP
#include <boost/asio/io_service.hpp> #include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/spawn.hpp> #include <boost/asio/spawn.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/thread/csbl/memory/allocator_arg.hpp>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
@@ -29,10 +31,12 @@ namespace test {
class enable_yield_to class enable_yield_to
{ {
protected: protected:
boost::asio::io_service ios_; boost::asio::io_context ios_;
private: private:
boost::optional<boost::asio::io_service::work> work_; boost::optional<boost::asio::executor_work_guard<
boost::asio::io_context::executor_type>>
work_;
std::vector<std::thread> threads_; std::vector<std::thread> threads_;
std::mutex m_; std::mutex m_;
std::condition_variable cv_; std::condition_variable cv_;
@@ -42,7 +46,8 @@ public:
/// The type of yield context passed to functions. /// The type of yield context passed to functions.
using yield_context = boost::asio::yield_context; using yield_context = boost::asio::yield_context;
explicit enable_yield_to(std::size_t concurrency = 1) : work_(ios_) explicit enable_yield_to(std::size_t concurrency = 1)
: work_(boost::asio::make_work_guard(ios_))
{ {
threads_.reserve(concurrency); threads_.reserve(concurrency);
while (concurrency--) while (concurrency--)
@@ -56,9 +61,9 @@ public:
t.join(); t.join();
} }
/// Return the `io_service` associated with the object /// Return the `io_context` associated with the object
boost::asio::io_service& boost::asio::io_context&
get_io_service() get_io_context()
{ {
return ios_; return ios_;
} }
@@ -111,13 +116,18 @@ enable_yield_to::spawn(F0&& f, FN&&... fn)
{ {
boost::asio::spawn( boost::asio::spawn(
ios_, ios_,
boost::allocator_arg,
boost::context::fixedsize_stack(2 * 1024 * 1024),
[&](yield_context yield) { [&](yield_context yield) {
f(yield); f(yield);
std::lock_guard lock{m_}; std::lock_guard lock{m_};
if (--running_ == 0) if (--running_ == 0)
cv_.notify_all(); cv_.notify_all();
}, },
boost::coroutines::attributes(2 * 1024 * 1024)); [](std::exception_ptr e) {
if (e)
std::rethrow_exception(e);
});
spawn(fn...); spawn(fn...);
} }

View File

@@ -42,7 +42,7 @@ public:
The argument string is available to suites and The argument string is available to suites and
allows for customization of the test. Each suite allows for customization of the test. Each suite
defines its own syntax for the argument string. defines its own syntax for the argumnet string.
The same argument is passed to all suites. The same argument is passed to all suites.
*/ */
void void

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

@@ -217,7 +217,7 @@ Reader::parse(Value& root, BufferSequence const& bs)
std::string s; std::string s;
s.reserve(buffer_size(bs)); s.reserve(buffer_size(bs));
for (auto const& b : bs) for (auto const& b : bs)
s.append(buffer_cast<char const*>(b), buffer_size(b)); s.append(static_cast<char const*>(b.data()), buffer_size(b));
return parse(s, root); return parse(s, root);
} }

View File

@@ -24,7 +24,6 @@
#include <xrpl/json/json_forwards.h> #include <xrpl/json/json_forwards.h>
#include <cstring> #include <cstring>
#include <limits>
#include <map> #include <map>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -159,9 +158,9 @@ public:
using ArrayIndex = UInt; using ArrayIndex = UInt;
static Value const null; static Value const null;
static constexpr Int minInt = std::numeric_limits<Int>::min(); static Int const minInt;
static constexpr Int maxInt = std::numeric_limits<Int>::max(); static Int const maxInt;
static constexpr UInt maxUInt = std::numeric_limits<UInt>::max(); static UInt const maxUInt;
private: private:
class CZString class CZString
@@ -264,10 +263,6 @@ public:
bool bool
asBool() const; asBool() const;
/** Correct absolute value from int or unsigned int */
UInt
asAbsUInt() const;
// TODO: What is the "empty()" method this docstring mentions? // TODO: What is the "empty()" method this docstring mentions?
/** isNull() tests to see if this field is null. Don't use this method to /** isNull() tests to see if this field is null. Don't use this method to
test for emptiness: use empty(). */ test for emptiness: use empty(). */
@@ -400,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

@@ -46,7 +46,7 @@ public:
* without formatting (not human friendly). * without formatting (not human friendly).
* *
* The JSON document is written in a single line. It is not intended for 'human' * The JSON document is written in a single line. It is not intended for 'human'
* consumption, but may be useful to support feature such as RPC where bandwidth * consumption, but may be useful to support feature such as RPC where bandwith
* is limited. \sa Reader, Value * is limited. \sa Reader, Value
*/ */

View File

@@ -284,14 +284,12 @@ public:
{ {
if (key.type != ltOFFER) if (key.type != ltOFFER)
{ {
// LCOV_EXCL_START
UNREACHABLE( UNREACHABLE(
"ripple::ApplyView::dirAppend : only Offers are appended to " "ripple::ApplyView::dirAppend : only Offers are appended to "
"book directories"); "book directories");
// Only Offers are appended to book directories. Call dirInsert() // Only Offers are appended to book directories. Call dirInsert()
// instead // instead
return std::nullopt; return std::nullopt;
// LCOV_EXCL_STOP
} }
return dirAdd(true, directory, key.key, describe); return dirAdd(true, directory, key.key, describe);
} }
@@ -387,45 +385,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

@@ -74,6 +74,18 @@ public:
deliver_ = amount; deliver_ = amount;
} }
void
setGasUsed(std::optional<std::uint32_t> const gasUsed)
{
gasUsed_ = gasUsed;
}
void
setWasmReturnCode(std::int32_t const wasmReturnCode)
{
wasmReturnCode_ = wasmReturnCode;
}
/** Get the number of modified entries /** Get the number of modified entries
*/ */
std::size_t std::size_t
@@ -92,6 +104,8 @@ public:
private: private:
std::optional<STAmount> deliver_; std::optional<STAmount> deliver_;
std::optional<std::uint32_t> gasUsed_;
std::optional<std::int32_t> wasmReturnCode_;
}; };
} // namespace ripple } // namespace ripple

View File

@@ -0,0 +1,105 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2025 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_LEDGER_OPENVIEWSANDBOX_H_INCLUDED
#define RIPPLE_LEDGER_OPENVIEWSANDBOX_H_INCLUDED
#include <xrpl/ledger/OpenView.h>
#include <memory>
namespace ripple {
class OpenViewSandbox
{
private:
OpenView& parent_;
std::unique_ptr<OpenView> sandbox_;
public:
using key_type = ReadView::key_type;
OpenViewSandbox(OpenView& parent)
: parent_(parent)
, sandbox_(std::make_unique<OpenView>(batch_view, parent))
{
}
void
rawErase(std::shared_ptr<SLE> const& sle)
{
sandbox_->rawErase(sle);
}
void
rawInsert(std::shared_ptr<SLE> const& sle)
{
sandbox_->rawInsert(sle);
}
void
rawReplace(std::shared_ptr<SLE> const& sle)
{
sandbox_->rawReplace(sle);
}
void
rawDestroyXRP(XRPAmount const& fee)
{
sandbox_->rawDestroyXRP(fee);
}
void
rawTxInsert(
key_type const& key,
std::shared_ptr<Serializer const> const& txn,
std::shared_ptr<Serializer const> const& metaData)
{
sandbox_->rawTxInsert(key, txn, metaData);
}
void
commit()
{
sandbox_->apply(parent_);
sandbox_ = std::make_unique<OpenView>(batch_view, parent_);
}
void
discard()
{
sandbox_ = std::make_unique<OpenView>(batch_view, parent_);
}
OpenView const&
view() const
{
return *sandbox_;
}
OpenView&
view()
{
return *sandbox_;
}
};
} // namespace ripple
#endif

View File

@@ -24,7 +24,6 @@
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/OpenView.h> #include <xrpl/ledger/OpenView.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Indexes.h> #include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/MPTIssue.h> #include <xrpl/protocol/MPTIssue.h>
#include <xrpl/protocol/Protocol.h> #include <xrpl/protocol/Protocol.h>
@@ -243,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,
@@ -362,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
accountSpendable(
ReadView const& view,
AccountID const& account,
Currency const& currency,
AccountID const& issuer,
FreezeHandling zeroIfFrozen,
beast::Journal j);
[[nodiscard]] STAmount
accountSpendable(
ReadView const& view,
AccountID const& account,
Issue const& issue,
FreezeHandling zeroIfFrozen,
beast::Journal j);
[[nodiscard]] STAmount
accountSpendable(
ReadView const& view,
AccountID const& account,
MPTIssue const& mptIssue,
FreezeHandling zeroIfFrozen,
AuthHandling zeroIfUnauthorized,
beast::Journal j);
[[nodiscard]] STAmount
accountSpendable(
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
@@ -651,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);
@@ -674,17 +552,14 @@ createPseudoAccount(
uint256 const& pseudoOwnerKey, uint256 const& pseudoOwnerKey,
SField const& ownerField); SField const& ownerField);
// Returns true iff sleAcct is a pseudo-account or specific // Returns true iff sleAcct is a pseudo-account.
// pseudo-accounts in pseudoFieldFilter.
// //
// Returns false if sleAcct is // Returns false if sleAcct is
// * NOT a pseudo-account OR // * NOT a pseudo-account OR
// * NOT a ltACCOUNT_ROOT OR // * NOT a ltACCOUNT_ROOT OR
// * null pointer // * null pointer
[[nodiscard]] bool [[nodiscard]] bool
isPseudoAccount( isPseudoAccount(std::shared_ptr<SLE const> sleAcct);
std::shared_ptr<SLE const> sleAcct,
std::set<SField const*> const& pseudoFieldFilter = {});
// Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account if // Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account if
// set // set
@@ -698,91 +573,14 @@ isPseudoAccount(
getPseudoAccountFields(); getPseudoAccountFields();
[[nodiscard]] inline bool [[nodiscard]] inline bool
isPseudoAccount( isPseudoAccount(ReadView const& view, AccountID accountId)
ReadView const& view,
AccountID const& accountId,
std::set<SField const*> const& pseudoFieldFilter = {})
{ {
return isPseudoAccount( return isPseudoAccount(view.read(keylet::account(accountId)));
view.read(keylet::account(accountId)), pseudoFieldFilter);
} }
[[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);
[[nodiscard]] TER
doWithdraw(
ApplyView& view,
STTx const& tx,
AccountID const& senderAcct,
AccountID const& dstAcct,
AccountID const& sourceAcct,
XRPAmount priorBalance,
STAmount const& amount,
beast::Journal j);
/// 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
@@ -791,6 +589,7 @@ addEmptyHolding(
AccountID const& accountID, AccountID const& accountID,
XRPAmount priorBalance, XRPAmount priorBalance,
Issue const& issue, Issue const& issue,
STAmount const& limit,
beast::Journal journal); beast::Journal journal);
[[nodiscard]] TER [[nodiscard]] TER
@@ -799,6 +598,7 @@ addEmptyHolding(
AccountID const& accountID, AccountID const& accountID,
XRPAmount priorBalance, XRPAmount priorBalance,
MPTIssue const& mptIssue, MPTIssue const& mptIssue,
STAmount const& limit,
beast::Journal journal); beast::Journal journal);
[[nodiscard]] inline TER [[nodiscard]] inline TER
@@ -807,12 +607,13 @@ addEmptyHolding(
AccountID const& accountID, AccountID const& accountID,
XRPAmount priorBalance, XRPAmount priorBalance,
Asset const& asset, Asset const& asset,
STAmount const& limit,
beast::Journal journal) beast::Journal journal)
{ {
return std::visit( return std::visit(
[&]<ValidIssueType TIss>(TIss const& issue) -> TER { [&]<ValidIssueType TIss>(TIss const& issue) -> TER {
return addEmptyHolding( return addEmptyHolding(
view, accountID, priorBalance, issue, journal); view, accountID, priorBalance, issue, limit, journal);
}, },
asset.value()); asset.value());
} }
@@ -952,22 +753,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,
@@ -1039,8 +824,7 @@ requireAuth(
* purely defensive, as we currently do not allow such vaults to be created. * purely defensive, as we currently do not allow such vaults to be created.
* *
* If StrongAuth then return tecNO_AUTH if MPToken doesn't exist or * If StrongAuth then return tecNO_AUTH if MPToken doesn't exist or
* lsfMPTRequireAuth is set and MPToken is not authorized. Vault and LoanBroker * lsfMPTRequireAuth is set and MPToken is not authorized.
* pseudo-accounts are implicitly authorized.
* *
* If WeakAuth then return tecNO_AUTH if lsfMPTRequireAuth is set and MPToken * If WeakAuth then return tecNO_AUTH if lsfMPTRequireAuth is set and MPToken
* doesn't exist or is not authorized (explicitly or via credentials, if * doesn't exist or is not authorized (explicitly or via credentials, if
@@ -1102,6 +886,41 @@ enforceMPTokenAuthorization(
XRPAmount const& priorBalance, XRPAmount const& priorBalance,
beast::Journal j); beast::Journal j);
enum class SendIssuerHandling {
ihSENDER_NOT_ALLOWED,
ihRECEIVER_NOT_ALLOWED,
ihIGNORE
};
enum class SendEscrowHandling { ehIGNORE, ehCHECK };
enum class SendAuthHandling {
ahCHECK_SENDER,
ahCHECK_RECEIVER,
ahBOTH,
ahNEITHER
};
enum class SendFreezeHandling {
fhCHECK_SENDER,
fhCHECK_RECEIVER,
fhBOTH,
fhNEITHER
};
enum class SendTransferHandling { thIGNORE, thCHECK };
enum class SendBalanceHandling { bhIGNORE, bhCHECK };
TER
canTransferFT(
ReadView const& view,
AccountID const& sender,
AccountID const& receiver,
STAmount const& amount,
beast::Journal j,
SendIssuerHandling issuerHandling,
SendEscrowHandling escrowHandling,
SendAuthHandling authHandling,
SendFreezeHandling freezeHandling,
SendTransferHandling transferHandling,
SendBalanceHandling balanceHandling);
/** Check if the destination account is allowed /** Check if the destination account is allowed
* to receive MPT. Return tecNO_AUTH if it doesn't * to receive MPT. Return tecNO_AUTH if it doesn't
* and tesSUCCESS otherwise. * and tesSUCCESS otherwise.
@@ -1113,26 +932,6 @@ canTransfer(
AccountID const& from, AccountID const& from,
AccountID const& to); AccountID const& to);
[[nodiscard]] TER
canTransfer(
ReadView const& view,
Issue const& issue,
AccountID const& from,
AccountID const& to);
[[nodiscard]] TER inline canTransfer(
ReadView const& view,
Asset const& asset,
AccountID const& from,
AccountID const& to)
{
return std::visit(
[&]<ValidIssueType TIss>(TIss const& issue) -> TER {
return canTransfer(view, issue, from, to);
},
asset.value());
}
/** Deleter function prototype. Returns the status of the entry deletion /** Deleter function prototype. Returns the status of the entry deletion
* (if should not be skipped) and if the entry should be skipped. The status * (if should not be skipped) and if the entry should be skipped. The status
* is always tesSUCCESS if the entry should be skipped. * is always tesSUCCESS if the entry should be skipped.

View File

@@ -72,6 +72,8 @@ public:
TER ter, TER ter,
std::optional<STAmount> const& deliver, std::optional<STAmount> const& deliver,
std::optional<uint256 const> const& parentBatchId, std::optional<uint256 const> const& parentBatchId,
std::optional<std::uint32_t> const& gasUsed,
std::optional<std::int32_t> const& wasmReturnCode,
bool isDryRun, bool isDryRun,
beast::Journal j); beast::Journal j);

View File

@@ -47,7 +47,7 @@ public:
public: public:
AutoSocket( AutoSocket(
boost::asio::io_service& s, boost::asio::io_context& s,
boost::asio::ssl::context& c, boost::asio::ssl::context& c,
bool secureOnly, bool secureOnly,
bool plainOnly) bool plainOnly)
@@ -58,7 +58,7 @@ public:
mSocket = std::make_unique<ssl_socket>(s, c); mSocket = std::make_unique<ssl_socket>(s, c);
} }
AutoSocket(boost::asio::io_service& s, boost::asio::ssl::context& c) AutoSocket(boost::asio::io_context& s, boost::asio::ssl::context& c)
: AutoSocket(s, c, false, false) : AutoSocket(s, c, false, false)
{ {
} }

View File

@@ -23,7 +23,7 @@
#include <xrpl/basics/ByteUtilities.h> #include <xrpl/basics/ByteUtilities.h>
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/streambuf.hpp> #include <boost/asio/streambuf.hpp>
#include <chrono> #include <chrono>
@@ -51,7 +51,7 @@ public:
static void static void
get(bool bSSL, get(bool bSSL,
boost::asio::io_service& io_service, boost::asio::io_context& io_context,
std::deque<std::string> deqSites, std::deque<std::string> deqSites,
unsigned short const port, unsigned short const port,
std::string const& strPath, std::string const& strPath,
@@ -65,7 +65,7 @@ public:
static void static void
get(bool bSSL, get(bool bSSL,
boost::asio::io_service& io_service, boost::asio::io_context& io_context,
std::string strSite, std::string strSite,
unsigned short const port, unsigned short const port,
std::string const& strPath, std::string const& strPath,
@@ -80,7 +80,7 @@ public:
static void static void
request( request(
bool bSSL, bool bSSL,
boost::asio::io_service& io_service, boost::asio::io_context& io_context,
std::string strSite, std::string strSite,
unsigned short const port, unsigned short const port,
std::function< std::function<

View File

@@ -153,7 +153,7 @@ public:
{ {
strm.set_verify_callback( strm.set_verify_callback(
std::bind( std::bind(
&rfc2818_verify, &rfc6125_verify,
host, host,
std::placeholders::_1, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_2,
@@ -167,7 +167,7 @@ public:
/** /**
* @brief callback invoked for name verification - just passes through * @brief callback invoked for name verification - just passes through
* to the asio rfc2818 implementation. * to the asio `host_name_verification` (rfc6125) implementation.
* *
* @param domain hostname expected * @param domain hostname expected
* @param preverified passed by implementation * @param preverified passed by implementation
@@ -175,13 +175,13 @@ public:
* @param j journal for logging * @param j journal for logging
*/ */
static bool static bool
rfc2818_verify( rfc6125_verify(
std::string const& domain, std::string const& domain,
bool preverified, bool preverified,
boost::asio::ssl::verify_context& ctx, boost::asio::ssl::verify_context& ctx,
beast::Journal j) beast::Journal j)
{ {
if (boost::asio::ssl::rfc2818_verification(domain)(preverified, ctx)) if (boost::asio::ssl::host_name_verification(domain)(preverified, ctx))
return true; return true;
JLOG(j.warn()) << "Outbound SSL connection to " << domain JLOG(j.warn()) << "Outbound SSL connection to " << domain

View File

@@ -100,27 +100,7 @@ public:
bool bool
native() const native() const
{ {
return std::visit( return holds<Issue>() && get<Issue>().native();
[&]<ValidIssueType TIss>(TIss const& issue) {
if constexpr (std::is_same_v<TIss, Issue>)
return issue.native();
if constexpr (std::is_same_v<TIss, MPTIssue>)
return false;
},
issue_);
}
bool
integral() const
{
return std::visit(
[&]<ValidIssueType TIss>(TIss const& issue) {
if constexpr (std::is_same_v<TIss, Issue>)
return issue.native();
if constexpr (std::is_same_v<TIss, MPTIssue>)
return true;
},
issue_);
} }
friend constexpr bool friend constexpr bool

View File

@@ -24,6 +24,8 @@
namespace ripple { namespace ripple {
constexpr std::uint32_t MICRO_DROPS_PER_DROP{1'000'000};
/** Reflects the fee settings for a particular ledger. /** Reflects the fee settings for a particular ledger.
The fees are always the same for any transactions applied The fees are always the same for any transactions applied
@@ -34,6 +36,10 @@ struct Fees
XRPAmount base{0}; // Reference tx cost (drops) XRPAmount base{0}; // Reference tx cost (drops)
XRPAmount reserve{0}; // Reserve base (drops) XRPAmount reserve{0}; // Reserve base (drops)
XRPAmount increment{0}; // Reserve increment (drops) XRPAmount increment{0}; // Reserve increment (drops)
std::uint32_t extensionComputeLimit{
0}; // Extension compute limit (instructions)
std::uint32_t extensionSizeLimit{0}; // Extension size limit (bytes)
std::uint32_t gasPrice{0}; // price of WASM gas (micro-drops)
explicit Fees() = default; explicit Fees() = default;
Fees(Fees const&) = default; Fees(Fees const&) = default;

View File

@@ -58,6 +58,13 @@ private:
normalize(); normalize();
public: public:
/* The range for the mantissa when normalized */
static std::int64_t constexpr minMantissa = 1000000000000000ull;
static std::int64_t constexpr maxMantissa = 9999999999999999ull;
/* The range for the exponent when normalized */
static int constexpr minExponent = -96;
static int constexpr maxExponent = 80;
IOUAmount() = default; IOUAmount() = default;
explicit IOUAmount(Number const& other); explicit IOUAmount(Number const& other);
IOUAmount(beast::Zero); IOUAmount(beast::Zero);

View File

@@ -231,6 +231,12 @@ page(Keylet const& root, std::uint64_t index = 0) noexcept
Keylet Keylet
escrow(AccountID const& src, std::uint32_t seq) noexcept; escrow(AccountID const& src, std::uint32_t seq) noexcept;
inline Keylet
escrow(uint256 const& key) noexcept
{
return {ltESCROW, key};
}
/** A PaymentChannel */ /** A PaymentChannel */
Keylet Keylet
payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept; payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept;
@@ -346,29 +352,30 @@ 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;
Keylet Keylet
permissionedDomain(uint256 const& domainID) noexcept; permissionedDomain(uint256 const& domainID) noexcept;
Keylet
contractSource(uint256 const& contractHash) noexcept;
Keylet
contract(
uint256 const& contractHash,
AccountID const& owner,
std::uint32_t seq) noexcept;
inline Keylet
contract(uint256 const& contractID)
{
return {ltCONTRACT, contractID};
}
Keylet
contractData(AccountID const& owner, AccountID const& contractAccount) noexcept;
} // namespace keylet } // namespace keylet
// Everything below is deprecated and should be removed in favor of keylets: // Everything below is deprecated and should be removed in favor of keylets:

View File

@@ -99,14 +99,6 @@ enum LedgerEntryType : std::uint16_t
*/ */
ltNICKNAME [[deprecated("This object type is not supported and should not be used.")]] = 0x006e, ltNICKNAME [[deprecated("This object type is not supported and should not be used.")]] = 0x006e,
/** A legacy, deprecated type.
\deprecated **This object type is not supported and should not be used.**
Support for this type of object was never implemented.
No objects of this type were ever created.
*/
ltCONTRACT [[deprecated("This object type is not supported and should not be used.")]] = 0x0063,
/** A legacy, deprecated type. /** A legacy, deprecated type.
\deprecated **This object type is not supported and should not be used.** \deprecated **This object type is not supported and should not be used.**
@@ -188,14 +180,14 @@ enum LedgerSpecificFlags {
lsfMPTCanTransfer = 0x00000020, lsfMPTCanTransfer = 0x00000020,
lsfMPTCanClawback = 0x00000040, lsfMPTCanClawback = 0x00000040,
lsmfMPTCanMutateCanLock = 0x00000002, lmfMPTCanMutateCanLock = 0x00000002,
lsmfMPTCanMutateRequireAuth = 0x00000004, lmfMPTCanMutateRequireAuth = 0x00000004,
lsmfMPTCanMutateCanEscrow = 0x00000008, lmfMPTCanMutateCanEscrow = 0x00000008,
lsmfMPTCanMutateCanTrade = 0x00000010, lmfMPTCanMutateCanTrade = 0x00000010,
lsmfMPTCanMutateCanTransfer = 0x00000020, lmfMPTCanMutateCanTransfer = 0x00000020,
lsmfMPTCanMutateCanClawback = 0x00000040, lmfMPTCanMutateCanClawback = 0x00000040,
lsmfMPTCanMutateMetadata = 0x00010000, lmfMPTCanMutateMetadata = 0x00010000,
lsmfMPTCanMutateTransferFee = 0x00020000, lmfMPTCanMutateTransferFee = 0x00020000,
// ltMPTOKEN // ltMPTOKEN
lsfMPTAuthorized = 0x00000002, lsfMPTAuthorized = 0x00000002,
@@ -205,11 +197,6 @@ enum LedgerSpecificFlags {
// ltVAULT // ltVAULT
lsfVaultPrivate = 0x00010000, lsfVaultPrivate = 0x00010000,
// ltLOAN
lsfLoanDefault = 0x00010000,
lsfLoanImpaired = 0x00020000,
lsfLoanOverpayment = 0x00040000, // True, loan allows overpayments
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -149,11 +149,12 @@ mulRatio(
bool roundUp) bool roundUp)
{ {
using namespace boost::multiprecision; using namespace boost::multiprecision;
using int128 = boost::multiprecision::int128_t;
if (!den) if (!den)
Throw<std::runtime_error>("division by zero"); Throw<std::runtime_error>("division by zero");
int128_t const amt128(amt.value()); int128 const amt128(amt.value());
auto const neg = amt.value() < 0; auto const neg = amt.value() < 0;
auto const m = amt128 * num; auto const m = amt128 * num;
auto r = m / den; auto r = m / den;

View File

@@ -86,9 +86,6 @@ public:
std::optional<TxType> std::optional<TxType>
getGranularTxType(GranularPermissionType const& gpType) const; getGranularTxType(GranularPermissionType const& gpType) const;
std::optional<std::reference_wrapper<uint256 const>> const
getTxFeature(TxType txType) const;
bool bool
isDelegatable(std::uint32_t const& permissionValue, Rules const& rules) isDelegatable(std::uint32_t const& permissionValue, Rules const& rules)
const; const;

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,10 +55,7 @@ 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 */
@@ -85,140 +81,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);
static_assert(bipsPerUnity == Bips32{10'000});
TenthBips32 constexpr tenthBipsPerUnity(bipsPerUnity.value() * 10);
static_assert(tenthBipsPerUnity == TenthBips32(100'000));
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();
}
namespace Lending {
/** 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;
} // namespace Lending
/** 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;
@@ -270,6 +132,13 @@ std::uint8_t constexpr vaultMaximumIOUScale = 18;
* another vault; counted from 0 */ * another vault; counted from 0 */
std::uint8_t constexpr maxAssetCheckDepth = 5; std::uint8_t constexpr maxAssetCheckDepth = 5;
/** The maximum length of a Data field in Escrow object that can be updated by
* Wasm code */
std::size_t constexpr maxWasmDataLength = 4 * 1024;
/** The maximum length of a parameters passed from Wasm code*/
std::size_t constexpr maxWasmParamLength = 1024;
/** A ledger index. */ /** A ledger index. */
using LedgerIndex = std::uint32_t; using LedgerIndex = std::uint32_t;

View File

@@ -53,6 +53,9 @@ class STNumber;
class STXChainBridge; class STXChainBridge;
class STVector256; class STVector256;
class STCurrency; class STCurrency;
class STData;
class STDataType;
class STJson;
#pragma push_macro("XMACRO") #pragma push_macro("XMACRO")
#undef XMACRO #undef XMACRO
@@ -91,6 +94,9 @@ class STCurrency;
STYPE(STI_ISSUE, 24) \ STYPE(STI_ISSUE, 24) \
STYPE(STI_XCHAIN_BRIDGE, 25) \ STYPE(STI_XCHAIN_BRIDGE, 25) \
STYPE(STI_CURRENCY, 26) \ STYPE(STI_CURRENCY, 26) \
STYPE(STI_DATA, 27) \
STYPE(STI_DATATYPE, 28) \
STYPE(STI_JSON, 29) \
\ \
/* high-level types */ \ /* high-level types */ \
/* cannot be serialized inside other types */ \ /* cannot be serialized inside other types */ \
@@ -139,8 +145,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
{ {
@@ -359,7 +365,6 @@ using SF_UINT384 = TypedField<STBitString<384>>;
using SF_UINT512 = TypedField<STBitString<512>>; using SF_UINT512 = TypedField<STBitString<512>>;
using SF_INT32 = TypedField<STInteger<std::int32_t>>; using SF_INT32 = TypedField<STInteger<std::int32_t>>;
using SF_INT64 = TypedField<STInteger<std::int64_t>>;
using SF_ACCOUNT = TypedField<STAccount>; using SF_ACCOUNT = TypedField<STAccount>;
using SF_AMOUNT = TypedField<STAmount>; using SF_AMOUNT = TypedField<STAmount>;
@@ -369,6 +374,9 @@ using SF_NUMBER = TypedField<STNumber>;
using SF_VL = TypedField<STBlob>; using SF_VL = TypedField<STBlob>;
using SF_VECTOR256 = TypedField<STVector256>; using SF_VECTOR256 = TypedField<STVector256>;
using SF_XCHAIN_BRIDGE = TypedField<STXChainBridge>; using SF_XCHAIN_BRIDGE = TypedField<STXChainBridge>;
using SF_DATA = TypedField<STData>;
using SF_DATATYPE = TypedField<STDataType>;
using SF_JSON = TypedField<STJson>;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -66,18 +66,16 @@ 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
constexpr static std::uint64_t cMinValue = 1'000'000'000'000'000ull; static std::uint64_t const cMinValue = 1000000000000000ull;
static_assert(isPowerOfTen(cMinValue)); static std::uint64_t const cMaxValue = 9999999999999999ull;
constexpr static std::uint64_t cMaxValue = cMinValue * 10 - 1; static std::uint64_t const cMaxNative = 9000000000000000000ull;
static_assert(cMaxValue == 9'999'999'999'999'999ull);
constexpr static std::uint64_t cMaxNative = 9'000'000'000'000'000'000ull;
// Max native value on network. // Max native value on network.
constexpr static std::uint64_t cMaxNativeN = 100'000'000'000'000'000ull; static std::uint64_t const cMaxNativeN = 100000000000000000ull;
constexpr static std::uint64_t cIssuedCurrency = 0x8'000'000'000'000'000ull; static std::uint64_t const cIssuedCurrency = 0x8000000000000000ull;
constexpr static std::uint64_t cPositive = 0x4'000'000'000'000'000ull; static std::uint64_t const cPositive = 0x4000000000000000ull;
constexpr static std::uint64_t cMPToken = 0x2'000'000'000'000'000ull; static std::uint64_t const cMPToken = 0x2000000000000000ull;
constexpr static std::uint64_t cValueMask = ~(cPositive | cMPToken); static std::uint64_t const cValueMask = ~(cPositive | cMPToken);
static std::uint64_t const uRateOne; static std::uint64_t const uRateOne;
@@ -176,9 +174,6 @@ public:
int int
exponent() const noexcept; exponent() const noexcept;
bool
integral() const noexcept;
bool bool
native() const noexcept; native() const noexcept;
@@ -459,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
{ {
@@ -583,7 +572,7 @@ STAmount::clear()
{ {
// The -100 is used to allow 0 to sort less than a small positive values // The -100 is used to allow 0 to sort less than a small positive values
// which have a negative exponent. // which have a negative exponent.
mOffset = integral() ? 0 : -100; mOffset = native() ? 0 : -100;
mValue = 0; mValue = 0;
mIsNegative = false; mIsNegative = false;
} }
@@ -706,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 const& 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;
// Note 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

@@ -0,0 +1,308 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2023 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_PROTOCOL_STDATA_H_INCLUDED
#define RIPPLE_PROTOCOL_STDATA_H_INCLUDED
#include <xrpl/basics/Buffer.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STAccount.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STBase.h>
#include <xrpl/protocol/STBitString.h>
#include <xrpl/protocol/STInteger.h>
#include <xrpl/protocol/detail/STVar.h>
#include <cstdint>
#include <string>
#include <vector>
namespace ripple {
class STData final : public STBase
{
private:
using data_type = detail::STVar;
std::uint16_t inner_type_;
data_type data_;
bool default_{true};
public:
using value_type = STData; // Although not directly holding a single value
STData(SField const& n);
STData(SField const& n, unsigned char);
STData(SField const& n, std::uint16_t);
STData(SField const& n, std::uint32_t);
STData(SField const& n, std::uint64_t);
STData(SField const& n, uint128 const&);
STData(SField const& n, uint160 const&);
STData(SField const& n, uint192 const&);
STData(SField const& n, uint256 const&);
STData(SField const& n, Blob const&);
STData(SField const& n, Slice const&);
STData(SField const& n, AccountID const&);
STData(SField const& n, STAmount const&);
STData(SField const& n, STIssue const&);
STData(SField const& n, STCurrency const&);
STData(SField const& n, STNumber const&);
STData(SerialIter& sit, SField const& name);
std::size_t
size() const;
SerializedTypeID
getSType() const override;
std::string
getInnerTypeString() const;
std::string
getText() const override;
Json::Value getJson(JsonOptions) const override;
void
add(Serializer& s) const override;
bool
isEquivalent(STBase const& t) const override;
bool
isDefault() const override;
SerializedTypeID
getInnerSType() const noexcept;
STBase*
makeFieldPresent();
void
setFieldU8(unsigned char);
void setFieldU16(std::uint16_t);
void setFieldU32(std::uint32_t);
void setFieldU64(std::uint64_t);
void
setFieldH128(uint128 const&);
void
setFieldH160(uint160 const&);
void
setFieldH192(uint192 const&);
void
setFieldH256(uint256 const&);
void
setFieldVL(Blob const&);
void
setFieldVL(Slice const&);
void
setAccountID(AccountID const&);
void
setFieldAmount(STAmount const&);
void
setIssue(STIssue const&);
void
setCurrency(STCurrency const&);
void
setFieldNumber(STNumber const&);
unsigned char
getFieldU8() const;
std::uint16_t
getFieldU16() const;
std::uint32_t
getFieldU32() const;
std::uint64_t
getFieldU64() const;
uint128
getFieldH128() const;
uint160
getFieldH160() const;
uint192
getFieldH192() const;
uint256
getFieldH256() const;
Blob
getFieldVL() const;
AccountID
getAccountID() const;
STAmount const&
getFieldAmount() const;
STIssue
getFieldIssue() const;
STCurrency
getFieldCurrency() const;
STNumber
getFieldNumber() const;
private:
STBase*
copy(std::size_t n, void* buf) const override;
STBase*
move(std::size_t n, void* buf) override;
friend class detail::STVar;
// Implementation for getting (most) fields that return by value.
//
// The remove_cv and remove_reference are necessitated by the STBitString
// types. Their value() returns by const ref. We return those types
// by value.
template <
typename T,
typename V = typename std::remove_cv<typename std::remove_reference<
decltype(std::declval<T>().value())>::type>::type>
V
getFieldByValue() const;
// Implementations for getting (most) fields that return by const reference.
//
// If an absent optional field is deserialized we don't have anything
// obvious to return. So we insist on having the call provide an
// 'empty' value we return in that circumstance.
template <typename T, typename V>
V const&
getFieldByConstRef(V const& empty) const;
// Implementation for setting most fields with a setValue() method.
template <typename T, typename V>
void
setFieldUsingSetValue(V value);
// Implementation for setting fields using assignment
template <typename T>
void
setFieldUsingAssignment(T const& value);
};
//------------------------------------------------------------------------------
// Implementation
//------------------------------------------------------------------------------
inline SerializedTypeID
STData::getInnerSType() const noexcept
{
return static_cast<SerializedTypeID>(inner_type_);
}
template <typename T, typename V>
V
STData::getFieldByValue() const
{
STBase const* rf = &data_.get();
// if (!rf)
// throwFieldNotFound(getFName());
SerializedTypeID id = rf->getSType();
if (id == STI_NOTPRESENT)
Throw<std::runtime_error>("Field not present");
T const* cf = dynamic_cast<T const*>(rf);
if (!cf)
Throw<std::runtime_error>("Wrong field type");
return cf->value();
}
// Implementations for getting (most) fields that return by const reference.
//
// If an absent optional field is deserialized we don't have anything
// obvious to return. So we insist on having the call provide an
// 'empty' value we return in that circumstance.
template <typename T, typename V>
V const&
STData::getFieldByConstRef(V const& empty) const
{
STBase const* rf = &data_.get();
// if (!rf)
// throwFieldNotFound(field);
SerializedTypeID id = rf->getSType();
if (id == STI_NOTPRESENT)
return empty; // optional field not present
T const* cf = dynamic_cast<T const*>(rf);
if (!cf)
Throw<std::runtime_error>("Wrong field type");
return *cf;
}
// Implementation for setting most fields with a setValue() method.
template <typename T, typename V>
void
STData::setFieldUsingSetValue(V value)
{
static_assert(!std::is_lvalue_reference<V>::value, "");
STBase* rf = &data_.get();
// if (!rf)
// throwFieldNotFound(field);
if (rf->getSType() == STI_NOTPRESENT)
rf = makeFieldPresent();
T* cf = dynamic_cast<T*>(rf);
if (!cf)
Throw<std::runtime_error>("Wrong field type");
cf->setValue(std::move(value));
}
// Implementation for setting fields using assignment
template <typename T>
void
STData::setFieldUsingAssignment(T const& value)
{
STBase* rf = &data_.get();
// if (!rf)
// throwFieldNotFound(field);
// if (rf->getSType() == STI_NOTPRESENT)
// rf = makeFieldPresent(field);
T* cf = dynamic_cast<T*>(rf);
if (!cf)
Throw<std::runtime_error>("Wrong field type");
(*cf) = value;
}
//------------------------------------------------------------------------------
//
// Creation
//
//------------------------------------------------------------------------------
STData
dataFromJson(SField const& field, Json::Value const& value);
} // namespace ripple
#endif

View File

@@ -0,0 +1,110 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2023 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_PROTOCOL_STDATATYPE_H_INCLUDED
#define RIPPLE_PROTOCOL_STDATATYPE_H_INCLUDED
#include <xrpl/basics/Buffer.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STAccount.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STBase.h>
#include <xrpl/protocol/STBitString.h>
#include <xrpl/protocol/STInteger.h>
#include <xrpl/protocol/detail/STVar.h>
#include <cstdint>
#include <string>
#include <vector>
namespace ripple {
class STDataType final : public STBase
{
private:
std::uint16_t inner_type_;
bool default_{true};
public:
using value_type =
STDataType; // Although not directly holding a single value
STDataType(SField const& n);
STDataType(SField const& n, SerializedTypeID);
STDataType(SerialIter& sit, SField const& name);
SerializedTypeID
getSType() const override;
std::string
getInnerTypeString() const;
std::string
getText() const override;
Json::Value getJson(JsonOptions) const override;
void
add(Serializer& s) const override;
bool
isEquivalent(STBase const& t) const override;
bool
isDefault() const override;
void setInnerSType(SerializedTypeID);
SerializedTypeID
getInnerSType() const noexcept;
STBase*
makeFieldPresent();
STBase*
copy(std::size_t n, void* buf) const override;
STBase*
move(std::size_t n, void* buf) override;
friend class detail::STVar;
};
//------------------------------------------------------------------------------
// Implementation
//------------------------------------------------------------------------------
inline SerializedTypeID
STDataType::getInnerSType() const noexcept
{
return static_cast<SerializedTypeID>(inner_type_);
}
//------------------------------------------------------------------------------
//
// Creation
//
//------------------------------------------------------------------------------
STDataType
dataTypeFromJson(SField const& field, Json::Value const& value);
} // namespace ripple
#endif

View File

@@ -0,0 +1,214 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2025 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_PROTOCOL_STJSON_H_INCLUDED
#define RIPPLE_PROTOCOL_STJSON_H_INCLUDED
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/STBase.h>
#include <xrpl/protocol/Serializer.h>
#include <map>
#include <memory>
#include <string>
#include <variant>
#include <vector>
namespace ripple {
/**
* STJson: Serialized Type for JSON-like structures (objects or arrays).
*
* Supports two modes:
* - Object: Key-value pairs where keys are VL-encoded strings
* - Array: Ordered list of values
*
* Values are [SType marker][VL-encoded SType serialization].
* Values can be any SType, including nested STJson.
*
* Serialization format: [type_byte][VL_length][data...]
* - type_byte: 0x00 = Object, 0x01 = Array
*/
class STJson : public STBase
{
public:
enum class JsonType : uint8_t { Object = 0x00, Array = 0x01 };
using Key = std::string;
using Value = std::shared_ptr<STBase>;
using Map = std::map<Key, Value>;
using Array = std::vector<Value>;
STJson() = default;
explicit STJson(Map&& map);
explicit STJson(Array&& array);
explicit STJson(SField const& name);
explicit STJson(SerialIter& sit, SField const& name);
SerializedTypeID
getSType() const override;
// Type checking
bool
isArray() const;
bool
isObject() const;
JsonType
getType() const;
// Depth checking (0 = no nesting, 1 = one level of nesting)
int
getDepth() const;
// Parse from binary blob
static std::shared_ptr<STJson>
fromBlob(void const* data, std::size_t size);
// Parse from SerialIter
static std::shared_ptr<STJson>
fromSerialIter(SerialIter& sit);
// Serialize to binary
void
add(Serializer& s) const override;
// JSON representation
Json::Value
getJson(JsonOptions options) const override;
bool
isEquivalent(STBase const& t) const override;
bool
isDefault() const override;
// Blob representation
Blob
toBlob() const;
// STJson size
std::size_t
size() const;
// Object accessors (only valid when isObject() == true)
Map const&
getMap() const;
void
setObjectField(Key const& key, Value const& value);
std::optional<STJson::Value>
getObjectField(Key const& key) const;
void
setNestedObjectField(
Key const& key,
Key const& nestedKey,
Value const& value);
std::optional<Value>
getNestedObjectField(Key const& key, Key const& nestedKey) const;
// Array accessors (only valid when isArray() == true)
Array const&
getArray() const;
void
pushArrayElement(Value const& value);
std::optional<Value>
getArrayElement(size_t index) const;
void
setArrayElement(size_t index, Value const& value);
void
setArrayElementField(size_t index, Key const& key, Value const& value);
std::optional<Value>
getArrayElementField(size_t index, Key const& key) const;
size_t
arraySize() const;
// Nested array accessors (for arrays stored in object fields)
void
setNestedArrayElement(Key const& key, size_t index, Value const& value);
void
setNestedArrayElementField(
Key const& key,
size_t index,
Key const& nestedKey,
Value const& value);
std::optional<Value>
getNestedArrayElement(Key const& key, size_t index) const;
std::optional<Value>
getNestedArrayElementField(
Key const& key,
size_t index,
Key const& nestedKey) const;
// Factory for SType value from blob (with SType marker)
static Value
makeValueFromVLWithType(SerialIter& sit);
void
setValue(STJson const& v);
private:
std::variant<Map, Array> data_{Map{}};
bool default_{false};
// Helper: validate nesting depth (max 1 level)
void
validateDepth(Value const& value, int currentDepth) const;
// Helper: parse a single key-value pair from SerialIter
static std::pair<Key, Value>
parsePair(SerialIter& sit);
// Helper: parse array elements from SerialIter
static Array
parseArray(SerialIter& sit, int length);
// Helper: encode a key as VL
static void
addVLKey(Serializer& s, std::string const& str);
// Helper: encode a value as [SType marker][VL]
static void
addVLValue(Serializer& s, std::shared_ptr<STBase> const& value);
STBase*
copy(std::size_t n, void* buf) const override;
STBase*
move(std::size_t n, void* buf) override;
friend class detail::STVar;
};
} // namespace ripple
#endif

View File

@@ -31,6 +31,7 @@
#include <xrpl/protocol/STBase.h> #include <xrpl/protocol/STBase.h>
#include <xrpl/protocol/STCurrency.h> #include <xrpl/protocol/STCurrency.h>
#include <xrpl/protocol/STIssue.h> #include <xrpl/protocol/STIssue.h>
#include <xrpl/protocol/STJson.h>
#include <xrpl/protocol/STPathSet.h> #include <xrpl/protocol/STPathSet.h>
#include <xrpl/protocol/STVector256.h> #include <xrpl/protocol/STVector256.h>
#include <xrpl/protocol/Units.h> #include <xrpl/protocol/Units.h>
@@ -235,6 +236,10 @@ public:
getFieldI32(SField const& field) const; getFieldI32(SField const& field) const;
AccountID AccountID
getAccountID(SField const& field) const; getAccountID(SField const& field) const;
STData
getFieldData(SField const& field) const;
STDataType
getFieldDataType(SField const& field) const;
Blob Blob
getFieldVL(SField const& field) const; getFieldVL(SField const& field) const;
@@ -244,15 +249,14 @@ public:
getFieldPathSet(SField const& field) const; getFieldPathSet(SField const& field) const;
STVector256 const& STVector256 const&
getFieldV256(SField const& field) const; getFieldV256(SField const& field) const;
// If not found, returns an object constructed with the given field
STObject
getFieldObject(SField const& field) const;
STArray const& STArray const&
getFieldArray(SField const& field) const; getFieldArray(SField const& field) const;
STCurrency const& STCurrency const&
getFieldCurrency(SField const& field) const; getFieldCurrency(SField const& field) const;
STNumber const& STNumber const&
getFieldNumber(SField const& field) const; getFieldNumber(SField const& field) const;
STJson const&
getFieldJson(SField const& field) const;
/** Get the value of a field. /** Get the value of a field.
@param A TypedField built from an SField value representing the desired @param A TypedField built from an SField value representing the desired
@@ -357,6 +361,9 @@ public:
void void
set(STBase&& v); set(STBase&& v);
void
addFieldFromSlice(SField const& sfield, Slice const& data);
void void
setFieldU8(SField const& field, unsigned char); setFieldU8(SField const& field, unsigned char);
void void
@@ -394,7 +401,7 @@ public:
void void
setFieldArray(SField const& field, STArray const& v); setFieldArray(SField const& field, STArray const& v);
void void
setFieldObject(SField const& field, STObject const& v); setFieldJson(SField const& field, STJson const& v);
template <class Tag> template <class Tag>
void void
@@ -501,8 +508,6 @@ public:
value_type value_type
operator*() const; operator*() const;
/// Do not use operator->() unless the field is required, or you've checked
/// that it's set.
T const* T const*
operator->() const; operator->() const;
@@ -526,26 +531,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>
@@ -565,12 +551,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);
@@ -760,8 +744,6 @@ STObject::Proxy<T>::operator*() const -> value_type
return this->value(); return this->value();
} }
/// Do not use operator->() unless the field is required, or you've checked that
/// it's set.
template <class T> template <class T>
T const* T const*
STObject::Proxy<T>::operator->() const STObject::Proxy<T>::operator->() const
@@ -808,7 +790,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)
{ {
@@ -818,7 +799,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

@@ -87,14 +87,8 @@ public:
getFullText() const override; getFullText() const override;
// Outer transaction functions / signature functions. // Outer transaction functions / signature functions.
static Blob
getSignature(STObject const& sigObject);
Blob Blob
getSignature() const getSignature() const;
{
return getSignature(*this);
}
uint256 uint256
getSigningHash() const; getSigningHash() const;
@@ -125,20 +119,13 @@ public:
getJson(JsonOptions options, bool binary) const; getJson(JsonOptions options, bool binary) const;
void void
sign( sign(PublicKey const& publicKey, SecretKey const& secretKey);
PublicKey const& publicKey,
SecretKey const& secretKey,
std::optional<std::reference_wrapper<SField const>> signatureTarget =
{});
enum class RequireFullyCanonicalSig : bool { no, yes };
/** Check the signature. /** Check the signature.
@param requireCanonicalSig If `true`, check that the signature is fully
canonical. If `false`, only check that the signature is valid.
@param rules The current ledger rules.
@return `true` if valid signature. If invalid, the error message string. @return `true` if valid signature. If invalid, the error message string.
*/ */
enum class RequireFullyCanonicalSig : bool { no, yes };
Expected<void, std::string> Expected<void, std::string>
checkSign(RequireFullyCanonicalSig requireCanonicalSig, Rules const& rules) checkSign(RequireFullyCanonicalSig requireCanonicalSig, Rules const& rules)
const; const;
@@ -163,34 +150,17 @@ public:
char status, char status,
std::string const& escapedMetaData) const; std::string const& escapedMetaData) const;
std::vector<uint256> const& std::vector<uint256>
getBatchTransactionIDs() const; getBatchTransactionIDs() const;
private: private:
/** Check the signature.
@param requireCanonicalSig If `true`, check that the signature is fully
canonical. If `false`, only check that the signature is valid.
@param rules The current ledger rules.
@param sigObject Reference to object that contains the signature fields.
Will be *this more often than not.
@return `true` if valid signature. If invalid, the error message string.
*/
Expected<void, std::string> Expected<void, std::string>
checkSign( checkSingleSign(RequireFullyCanonicalSig requireCanonicalSig) const;
RequireFullyCanonicalSig requireCanonicalSig,
Rules const& rules,
STObject const& sigObject) const;
Expected<void, std::string>
checkSingleSign(
RequireFullyCanonicalSig requireCanonicalSig,
STObject const& sigObject) const;
Expected<void, std::string> Expected<void, std::string>
checkMultiSign( checkMultiSign(
RequireFullyCanonicalSig requireCanonicalSig, RequireFullyCanonicalSig requireCanonicalSig,
Rules const& rules, Rules const& rules) const;
STObject const& sigObject) const;
Expected<void, std::string> Expected<void, std::string>
checkBatchSingleSign( checkBatchSingleSign(
@@ -209,7 +179,7 @@ private:
move(std::size_t n, void* buf) override; move(std::size_t n, void* buf) override;
friend class detail::STVar; friend class detail::STVar;
mutable std::vector<uint256> batchTxnIds_; mutable std::vector<uint256> batch_txn_ids_;
}; };
bool bool

View File

@@ -141,6 +141,8 @@ enum TEMcodes : TERUnderlyingType {
temARRAY_TOO_LARGE, temARRAY_TOO_LARGE,
temBAD_TRANSFER_FEE, temBAD_TRANSFER_FEE,
temINVALID_INNER_BATCH, temINVALID_INNER_BATCH,
temBAD_WASM,
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -185,6 +187,8 @@ enum TEFcodes : TERUnderlyingType {
tefNO_TICKET, tefNO_TICKET,
tefNFTOKEN_IS_NOT_TRANSFERABLE, tefNFTOKEN_IS_NOT_TRANSFERABLE,
tefINVALID_LEDGER_FIX_TYPE, tefINVALID_LEDGER_FIX_TYPE,
tefNO_WASM,
tefWASM_FIELD_NOT_INCLUDED,
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -362,6 +366,8 @@ enum TECcodes : TERUnderlyingType {
tecPSEUDO_ACCOUNT = 196, tecPSEUDO_ACCOUNT = 196,
tecPRECISION_LOSS = 197, tecPRECISION_LOSS = 197,
tecNO_DELEGATE_PERMISSION = 198, tecNO_DELEGATE_PERMISSION = 198,
tecWASM_REJECTED = 199,
tecINVALID_PARAMETERS = 200,
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -673,8 +679,7 @@ isTerRetry(TER x) noexcept
inline bool inline bool
isTesSuccess(TER x) noexcept isTesSuccess(TER x) noexcept
{ {
// Makes use of TERSubset::operator bool() return (x == tesSUCCESS);
return !(x);
} }
inline bool inline bool

View File

@@ -156,14 +156,14 @@ constexpr std::uint32_t const tfMPTokenIssuanceCreateMask =
// MPTokenIssuanceCreate MutableFlags: // MPTokenIssuanceCreate MutableFlags:
// Indicating specific fields or flags may be changed after issuance. // Indicating specific fields or flags may be changed after issuance.
constexpr std::uint32_t const tmfMPTCanMutateCanLock = lsmfMPTCanMutateCanLock; constexpr std::uint32_t const tmfMPTCanMutateCanLock = lmfMPTCanMutateCanLock;
constexpr std::uint32_t const tmfMPTCanMutateRequireAuth = lsmfMPTCanMutateRequireAuth; constexpr std::uint32_t const tmfMPTCanMutateRequireAuth = lmfMPTCanMutateRequireAuth;
constexpr std::uint32_t const tmfMPTCanMutateCanEscrow = lsmfMPTCanMutateCanEscrow; constexpr std::uint32_t const tmfMPTCanMutateCanEscrow = lmfMPTCanMutateCanEscrow;
constexpr std::uint32_t const tmfMPTCanMutateCanTrade = lsmfMPTCanMutateCanTrade; constexpr std::uint32_t const tmfMPTCanMutateCanTrade = lmfMPTCanMutateCanTrade;
constexpr std::uint32_t const tmfMPTCanMutateCanTransfer = lsmfMPTCanMutateCanTransfer; constexpr std::uint32_t const tmfMPTCanMutateCanTransfer = lmfMPTCanMutateCanTransfer;
constexpr std::uint32_t const tmfMPTCanMutateCanClawback = lsmfMPTCanMutateCanClawback; constexpr std::uint32_t const tmfMPTCanMutateCanClawback = lmfMPTCanMutateCanClawback;
constexpr std::uint32_t const tmfMPTCanMutateMetadata = lsmfMPTCanMutateMetadata; constexpr std::uint32_t const tmfMPTCanMutateMetadata = lmfMPTCanMutateMetadata;
constexpr std::uint32_t const tmfMPTCanMutateTransferFee = lsmfMPTCanMutateTransferFee; constexpr std::uint32_t const tmfMPTCanMutateTransferFee = lmfMPTCanMutateTransferFee;
constexpr std::uint32_t const tmfMPTokenIssuanceCreateMutableMask = constexpr std::uint32_t const tmfMPTokenIssuanceCreateMutableMask =
~(tmfMPTCanMutateCanLock | tmfMPTCanMutateRequireAuth | tmfMPTCanMutateCanEscrow | tmfMPTCanMutateCanTrade ~(tmfMPTCanMutateCanLock | tmfMPTCanMutateRequireAuth | tmfMPTCanMutateCanEscrow | tmfMPTCanMutateCanTrade
| tmfMPTCanMutateCanTransfer | tmfMPTCanMutateCanClawback | tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee); | tmfMPTCanMutateCanTransfer | tmfMPTCanMutateCanClawback | tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee);
@@ -285,31 +285,19 @@ 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 an early
// full payment. It must pay the entire loan including close
// interest and fees, or it will fail. False: Not a full payment.
constexpr std::uint32_t const tfLoanFullPayment = 0x00020000;
// tfLoanLatePayment: True, indicates that the payment is late,
// and includes late iterest and fees. If the loan is not late,
// it will fail. False: not a late payment. If the current payment
// is overdue, the transaction will fail.
constexpr std::uint32_t const tfLoanLatePayment = 0x00040000;
constexpr std::uint32_t const tfLoanSetMask = ~(tfUniversal |
tfLoanOverpayment);
constexpr std::uint32_t const tfLoanPayMask = ~(tfUniversal |
tfLoanOverpayment | tfLoanFullPayment | tfLoanLatePayment);
// LoanManage flags: constexpr std::uint32_t tfImmutable = 0x00010000;
constexpr std::uint32_t const tfLoanDefault = 0x00010000; constexpr std::uint32_t tfCodeImmutable = 0x00020000;
constexpr std::uint32_t const tfLoanImpair = 0x00020000; constexpr std::uint32_t tfABIImmutable = 0x00040000;
constexpr std::uint32_t const tfLoanUnimpair = 0x00040000; constexpr std::uint32_t tfUndeletable = 0x00080000;
constexpr std::uint32_t const tfLoanManageMask = ~(tfUniversal | tfLoanDefault | tfLoanImpair | tfLoanUnimpair); constexpr std::uint32_t tfContractMask =
~(tfUniversal | tfImmutable | tfCodeImmutable | tfABIImmutable | tfUndeletable);
constexpr std::uint32_t tfSendAmount = 0x00010000;
constexpr std::uint32_t tfSendNFToken = 0x00020000;
constexpr std::uint32_t tfAuthorizeToken = 0x00040000;
constexpr std::uint32_t tfContractParameterMask =
~(tfSendAmount | tfSendNFToken | tfAuthorizeToken);
// clang-format on // clang-format on

View File

@@ -46,10 +46,7 @@ private:
CtorHelper); 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, std::string const&);
TxMeta(uint256 const& txID, std::uint32_t ledger, STObject const&); TxMeta(uint256 const& txID, std::uint32_t ledger, STObject const&);
@@ -136,7 +133,7 @@ public:
void void
setParentBatchId(uint256 const& parentBatchId) setParentBatchId(uint256 const& parentBatchId)
{ {
mParentBatchId = parentBatchId; parentBatchId_ = parentBatchId;
} }
uint256 uint256
@@ -145,13 +142,55 @@ public:
XRPL_ASSERT( XRPL_ASSERT(
hasParentBatchId(), hasParentBatchId(),
"ripple::TxMeta::getParentBatchId : non-null batch id"); "ripple::TxMeta::getParentBatchId : non-null batch id");
return *mParentBatchId; return *parentBatchId_;
} }
bool bool
hasParentBatchId() const hasParentBatchId() const
{ {
return static_cast<bool>(mParentBatchId); return static_cast<bool>(parentBatchId_);
}
void
setGasUsed(std::uint32_t const& gasUsed)
{
gasUsed_ = gasUsed;
}
std::uint32_t
getGasUsed() const
{
XRPL_ASSERT(
hasGasUsed(),
"ripple::TxMeta::getGasUsed : non-null gas used field");
return *gasUsed_;
}
bool
hasGasUsed() const
{
return static_cast<bool>(gasUsed_);
}
void
setWasmReturnCode(std::int32_t const& wasmReturnCode)
{
wasmReturnCode_ = wasmReturnCode;
}
std::int32_t
getWasmReturnCode() const
{
XRPL_ASSERT(
hasWasmReturnCode(),
"ripple::TxMeta::getWasmReturnCode : non-null wasm return code");
return *wasmReturnCode_;
}
bool
hasWasmReturnCode() const
{
return static_cast<bool>(wasmReturnCode_);
} }
private: private:
@@ -161,7 +200,9 @@ private:
int mResult; int mResult;
std::optional<STAmount> mDelivered; std::optional<STAmount> mDelivered;
std::optional<uint256> mParentBatchId; std::optional<uint256> parentBatchId_;
std::optional<std::uint32_t> gasUsed_;
std::optional<std::int32_t> wasmReturnCode_;
STArray mNodes; STArray mNodes;
}; };

View File

@@ -286,11 +286,12 @@ mulRatio(
bool roundUp) bool roundUp)
{ {
using namespace boost::multiprecision; using namespace boost::multiprecision;
using int128 = boost::multiprecision::int128_t;
if (!den) if (!den)
Throw<std::runtime_error>("division by zero"); Throw<std::runtime_error>("division by zero");
int128_t const amt128(amt.drops()); int128 const amt128(amt.drops());
auto const neg = amt.drops() < 0; auto const neg = amt.drops() < 0;
auto const m = amt128 * num; auto const m = amt128 * num;
auto r = m / den; auto r = m / den;

View File

@@ -129,12 +129,10 @@ inplace_bigint_div_rem(std::span<uint64_t> numerator, std::uint64_t divisor)
{ {
// should never happen, but if it does then it seems natural to define // should never happen, but if it does then it seems natural to define
// the a null set of numbers to be zero, so the remainder is also zero. // the a null set of numbers to be zero, so the remainder is also zero.
// LCOV_EXCL_START
UNREACHABLE( UNREACHABLE(
"ripple::b58_fast::detail::inplace_bigint_div_rem : empty " "ripple::b58_fast::detail::inplace_bigint_div_rem : empty "
"numerator"); "numerator");
return 0; return 0;
// LCOV_EXCL_STOP
} }
auto to_u128 = [](std::uint64_t high, auto to_u128 = [](std::uint64_t high,

View File

@@ -27,19 +27,19 @@
#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.
// If you add an amendment here, then do not forget to increment `numFeatures`
// in include/xrpl/protocol/Feature.h.
XRPL_FEATURE(LendingProtocol, Supported::no, VoteBehavior::DefaultNo) XRPL_FEATURE(SmartContract, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (DirectoryLimit, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(SmartEscrow, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (IncludeKeyletFields, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (IncludeKeyletFields, Supported::no, 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 (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::no, VoteBehavior::DefaultNo)
XRPL_FIX (AMMClawbackRounding, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (AMMClawbackRounding, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(TokenEscrow, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(TokenEscrow, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (EnforceNFTokenTrustlineV2, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (EnforceNFTokenTrustlineV2, Supported::yes, VoteBehavior::DefaultNo)
@@ -47,9 +47,8 @@ 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_FEATURE(PermissionDelegation, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo)
// Check flags in Credential transactions
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (FrozenLPTokenTransfer, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (FrozenLPTokenTransfer, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo)
@@ -158,5 +157,3 @@ XRPL_RETIRE(fix1512)
XRPL_RETIRE(fix1523) XRPL_RETIRE(fix1523)
XRPL_RETIRE(fix1528) XRPL_RETIRE(fix1528)
XRPL_RETIRE(FlowCross) XRPL_RETIRE(FlowCross)
// clang-format on

View File

@@ -168,7 +168,7 @@ 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 {sfContractID, soeOPTIONAL}, // pseudo-account designator
})) }))
/** A ledger object which contains a list of object identifiers. /** A ledger object which contains a list of object identifiers.
@@ -321,6 +321,11 @@ LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({
{sfBaseFeeDrops, soeOPTIONAL}, {sfBaseFeeDrops, soeOPTIONAL},
{sfReserveBaseDrops, soeOPTIONAL}, {sfReserveBaseDrops, soeOPTIONAL},
{sfReserveIncrementDrops, soeOPTIONAL}, {sfReserveIncrementDrops, soeOPTIONAL},
// Smart Escrow fields
{sfExtensionComputeLimit, soeOPTIONAL},
{sfExtensionSizeLimit, soeOPTIONAL},
{sfGasPrice, soeOPTIONAL},
{sfPreviousTxnID, soeOPTIONAL}, {sfPreviousTxnID, soeOPTIONAL},
{sfPreviousTxnLgrSeq, soeOPTIONAL}, {sfPreviousTxnLgrSeq, soeOPTIONAL},
})) }))
@@ -351,6 +356,8 @@ LEDGER_ENTRY(ltESCROW, 0x0075, Escrow, escrow, ({
{sfCondition, soeOPTIONAL}, {sfCondition, soeOPTIONAL},
{sfCancelAfter, soeOPTIONAL}, {sfCancelAfter, soeOPTIONAL},
{sfFinishAfter, soeOPTIONAL}, {sfFinishAfter, soeOPTIONAL},
{sfFinishFunction, soeOPTIONAL},
{sfData, soeOPTIONAL},
{sfSourceTag, soeOPTIONAL}, {sfSourceTag, soeOPTIONAL},
{sfDestinationTag, soeOPTIONAL}, {sfDestinationTag, soeOPTIONAL},
{sfOwnerNode, soeREQUIRED}, {sfOwnerNode, soeREQUIRED},
@@ -458,7 +465,7 @@ LEDGER_ENTRY(ltCREDENTIAL, 0x0081, Credential, credential, ({
{sfExpiration, soeOPTIONAL}, {sfExpiration, soeOPTIONAL},
{sfURI, soeOPTIONAL}, {sfURI, soeOPTIONAL},
{sfIssuerNode, soeREQUIRED}, {sfIssuerNode, soeREQUIRED},
{sfSubjectNode, soeOPTIONAL}, {sfSubjectNode, soeREQUIRED},
{sfPreviousTxnID, soeREQUIRED}, {sfPreviousTxnID, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED}, {sfPreviousTxnLgrSeq, soeREQUIRED},
})) }))
@@ -499,10 +506,10 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
{sfAccount, soeREQUIRED}, {sfAccount, soeREQUIRED},
{sfData, soeOPTIONAL}, {sfData, soeOPTIONAL},
{sfAsset, soeREQUIRED}, {sfAsset, soeREQUIRED},
{sfAssetsTotal, soeDEFAULT}, {sfAssetsTotal, soeREQUIRED},
{sfAssetsAvailable, soeDEFAULT}, {sfAssetsAvailable, soeREQUIRED},
{sfAssetsMaximum, soeDEFAULT}, {sfAssetsMaximum, soeDEFAULT},
{sfLossUnrealized, soeDEFAULT}, {sfLossUnrealized, soeREQUIRED},
{sfShareMPTID, soeREQUIRED}, {sfShareMPTID, soeREQUIRED},
{sfWithdrawalPolicy, soeREQUIRED}, {sfWithdrawalPolicy, soeREQUIRED},
{sfScale, soeDEFAULT}, {sfScale, soeDEFAULT},
@@ -510,116 +517,44 @@ 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 contract source.
\sa keylet::contractSource
/** A ledger object representing a loan broker
\sa keylet::loanbroker
*/ */
LEDGER_ENTRY(ltLOAN_BROKER, 0x0088, LoanBroker, loan_broker, ({ LEDGER_ENTRY(ltCONTRACT_SOURCE, 0x0085, ContractSource, contract_source, ({
{sfPreviousTxnID, soeREQUIRED}, {sfPreviousTxnID, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED}, {sfPreviousTxnLgrSeq, soeREQUIRED},
{sfSequence, soeREQUIRED}, {sfContractHash, soeREQUIRED},
{sfOwnerNode, soeREQUIRED}, {sfContractCode, soeREQUIRED},
{sfVaultNode, soeREQUIRED}, {sfFunctions, soeREQUIRED},
{sfVaultID, soeREQUIRED}, {sfInstanceParameters, soeOPTIONAL},
{sfAccount, soeREQUIRED}, {sfReferenceCount, 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 /** A ledger object representing a contract.
\sa keylet::contract
\sa keylet::loan
*/ */
LEDGER_ENTRY(ltLOAN, 0x0089, Loan, loan, ({ LEDGER_ENTRY(ltCONTRACT, 0x0086, Contract, contract, ({
{sfPreviousTxnID, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED},
{sfSequence, soeREQUIRED},
{sfOwnerNode, soeREQUIRED},
{sfOwner, soeREQUIRED},
{sfContractAccount, soeREQUIRED},
{sfContractHash, soeREQUIRED},
{sfInstanceParameterValues, soeOPTIONAL},
{sfURI, soeOPTIONAL},
}))
/** A ledger object representing a contract data.
\sa keylet::contractData
*/
LEDGER_ENTRY(ltCONTRACT_DATA, 0x0087, ContractData, contract_data, ({
{sfPreviousTxnID, soeREQUIRED}, {sfPreviousTxnID, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED}, {sfPreviousTxnLgrSeq, soeREQUIRED},
{sfOwnerNode, soeREQUIRED}, {sfOwnerNode, soeREQUIRED},
{sfLoanBrokerNode, soeREQUIRED}, {sfOwner, soeREQUIRED},
{sfLoanBrokerID, soeREQUIRED}, {sfContractAccount, soeREQUIRED},
{sfLoanSequence, soeREQUIRED}, {sfContractJson, 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, soeDEFAULT},
{sfPreviousPaymentDate, soeDEFAULT},
{sfNextPaymentDueDate, soeDEFAULT},
// 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 it 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

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)
@@ -42,9 +40,10 @@ TYPED_SFIELD(sfAssetScale, UINT8, 5)
// 8-bit integers (uncommon) // 8-bit integers (uncommon)
TYPED_SFIELD(sfTickSize, UINT8, 16) TYPED_SFIELD(sfTickSize, UINT8, 16)
TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17) TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17)
TYPED_SFIELD(sfHookResult, UINT8, 18) // 18 unused
TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19) TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19)
TYPED_SFIELD(sfWithdrawalPolicy, UINT8, 20) TYPED_SFIELD(sfWithdrawalPolicy, UINT8, 20)
TYPED_SFIELD(sfContractResult, UINT8, 21)
// 16-bit integers (common) // 16-bit integers (common)
TYPED_SFIELD(sfLedgerEntryType, UINT16, 1, SField::sMD_Never) TYPED_SFIELD(sfLedgerEntryType, UINT16, 1, SField::sMD_Never)
@@ -56,12 +55,8 @@ TYPED_SFIELD(sfDiscountedFee, UINT16, 6)
// 16-bit integers (uncommon) // 16-bit integers (uncommon)
TYPED_SFIELD(sfVersion, UINT16, 16) TYPED_SFIELD(sfVersion, UINT16, 16)
TYPED_SFIELD(sfHookStateChangeCount, UINT16, 17) // 17 to 20 unused
TYPED_SFIELD(sfHookEmitCount, UINT16, 18)
TYPED_SFIELD(sfHookExecutionIndex, UINT16, 19)
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)
@@ -110,29 +105,18 @@ TYPED_SFIELD(sfTicketSequence, UINT32, 41)
TYPED_SFIELD(sfNFTokenTaxon, UINT32, 42) TYPED_SFIELD(sfNFTokenTaxon, UINT32, 42)
TYPED_SFIELD(sfMintedNFTokens, UINT32, 43) TYPED_SFIELD(sfMintedNFTokens, UINT32, 43)
TYPED_SFIELD(sfBurnedNFTokens, UINT32, 44) TYPED_SFIELD(sfBurnedNFTokens, UINT32, 44)
TYPED_SFIELD(sfHookStateCount, UINT32, 45) // 45 to 47 unused
TYPED_SFIELD(sfEmitGeneration, UINT32, 46)
// 47 reserved for Hooks
TYPED_SFIELD(sfVoteWeight, UINT32, 48) TYPED_SFIELD(sfVoteWeight, UINT32, 48)
TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50) 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(sfExtensionComputeLimit, UINT32, 54)
TYPED_SFIELD(sfPaymentInterval, UINT32, 55) TYPED_SFIELD(sfExtensionSizeLimit, UINT32, 55)
TYPED_SFIELD(sfGracePeriod, UINT32, 56) TYPED_SFIELD(sfGasPrice, UINT32, 56)
TYPED_SFIELD(sfPreviousPaymentDate, UINT32, 57) TYPED_SFIELD(sfComputationAllowance, UINT32, 57)
TYPED_SFIELD(sfNextPaymentDueDate, UINT32, 58) TYPED_SFIELD(sfGasUsed, UINT32, 58)
TYPED_SFIELD(sfPaymentRemaining, UINT32, 59) TYPED_SFIELD(sfParameterFlag, 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)
@@ -150,9 +134,7 @@ TYPED_SFIELD(sfNFTokenOfferNode, UINT64, 12)
TYPED_SFIELD(sfEmitBurden, UINT64, 13) TYPED_SFIELD(sfEmitBurden, UINT64, 13)
// 64-bit integers (uncommon) // 64-bit integers (uncommon)
TYPED_SFIELD(sfHookOn, UINT64, 16) // 16 to 18 unused
TYPED_SFIELD(sfHookInstructionCount, UINT64, 17)
TYPED_SFIELD(sfHookReturnCode, UINT64, 18)
TYPED_SFIELD(sfReferenceCount, UINT64, 19) TYPED_SFIELD(sfReferenceCount, UINT64, 19)
TYPED_SFIELD(sfXChainClaimID, UINT64, 20) TYPED_SFIELD(sfXChainClaimID, UINT64, 20)
TYPED_SFIELD(sfXChainAccountCreateCount, UINT64, 21) TYPED_SFIELD(sfXChainAccountCreateCount, UINT64, 21)
@@ -164,8 +146,7 @@ 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(sfContractReturnCode, UINT64, 30)
TYPED_SFIELD(sfLoanBrokerNode, UINT64, 31)
// 128-bit // 128-bit
TYPED_SFIELD(sfEmailHash, UINT128, 1) TYPED_SFIELD(sfEmailHash, UINT128, 1)
@@ -212,17 +193,14 @@ TYPED_SFIELD(sfPreviousPageMin, UINT256, 26)
TYPED_SFIELD(sfNextPageMin, UINT256, 27) TYPED_SFIELD(sfNextPageMin, UINT256, 27)
TYPED_SFIELD(sfNFTokenBuyOffer, UINT256, 28) TYPED_SFIELD(sfNFTokenBuyOffer, UINT256, 28)
TYPED_SFIELD(sfNFTokenSellOffer, UINT256, 29) TYPED_SFIELD(sfNFTokenSellOffer, UINT256, 29)
TYPED_SFIELD(sfHookStateKey, UINT256, 30) // 30 to 33 unused
TYPED_SFIELD(sfHookHash, UINT256, 31)
TYPED_SFIELD(sfHookNamespace, UINT256, 32)
TYPED_SFIELD(sfHookSetTxnID, UINT256, 33)
TYPED_SFIELD(sfDomainID, UINT256, 34) 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, TYPED_SFIELD(sfContractHash, UINT256, 37)
TYPED_SFIELD(sfContractID, UINT256, 38,
SField::sMD_PseudoAccount | SField::sMD_Default) 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 +208,9 @@ 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 // 32-bit signed (common)
TYPED_SFIELD(sfLoanScale, INT32, 1) TYPED_SFIELD(sfWasmReturnCode, INT32, 1)
// currency amount (common) // currency amount (common)
TYPED_SFIELD(sfAmount, AMOUNT, 1) TYPED_SFIELD(sfAmount, AMOUNT, 1)
@@ -266,15 +232,13 @@ TYPED_SFIELD(sfMinimumOffer, AMOUNT, 16)
TYPED_SFIELD(sfRippleEscrow, AMOUNT, 17) TYPED_SFIELD(sfRippleEscrow, AMOUNT, 17)
TYPED_SFIELD(sfDeliveredAmount, AMOUNT, 18) TYPED_SFIELD(sfDeliveredAmount, AMOUNT, 18)
TYPED_SFIELD(sfNFTokenBrokerFee, AMOUNT, 19) TYPED_SFIELD(sfNFTokenBrokerFee, AMOUNT, 19)
// 20 to 21 unused
// Reserve 20 & 21 for Hooks.
// currency amount (fees) // currency amount (fees)
TYPED_SFIELD(sfBaseFeeDrops, AMOUNT, 22) TYPED_SFIELD(sfBaseFeeDrops, AMOUNT, 22)
TYPED_SFIELD(sfReserveBaseDrops, AMOUNT, 23) TYPED_SFIELD(sfReserveBaseDrops, AMOUNT, 23)
TYPED_SFIELD(sfReserveIncrementDrops, AMOUNT, 24) TYPED_SFIELD(sfReserveIncrementDrops, AMOUNT, 24)
// currency amount (AMM) // currency amount (more)
TYPED_SFIELD(sfLPTokenOut, AMOUNT, 25) TYPED_SFIELD(sfLPTokenOut, AMOUNT, 25)
TYPED_SFIELD(sfLPTokenIn, AMOUNT, 26) TYPED_SFIELD(sfLPTokenIn, AMOUNT, 26)
TYPED_SFIELD(sfEPrice, AMOUNT, 27) TYPED_SFIELD(sfEPrice, AMOUNT, 27)
@@ -306,16 +270,16 @@ TYPED_SFIELD(sfMasterSignature, VL, 18, SField::sMD_Default, SFi
TYPED_SFIELD(sfUNLModifyValidator, VL, 19) TYPED_SFIELD(sfUNLModifyValidator, VL, 19)
TYPED_SFIELD(sfValidatorToDisable, VL, 20) TYPED_SFIELD(sfValidatorToDisable, VL, 20)
TYPED_SFIELD(sfValidatorToReEnable, VL, 21) TYPED_SFIELD(sfValidatorToReEnable, VL, 21)
TYPED_SFIELD(sfHookStateData, VL, 22) // 22 to 25 unused
TYPED_SFIELD(sfHookReturnString, VL, 23)
TYPED_SFIELD(sfHookParameterName, VL, 24)
TYPED_SFIELD(sfHookParameterValue, VL, 25)
TYPED_SFIELD(sfDIDDocument, VL, 26) TYPED_SFIELD(sfDIDDocument, VL, 26)
TYPED_SFIELD(sfData, VL, 27) TYPED_SFIELD(sfData, VL, 27)
TYPED_SFIELD(sfAssetClass, VL, 28) TYPED_SFIELD(sfAssetClass, VL, 28)
TYPED_SFIELD(sfProvider, VL, 29) TYPED_SFIELD(sfProvider, VL, 29)
TYPED_SFIELD(sfMPTokenMetadata, VL, 30) TYPED_SFIELD(sfMPTokenMetadata, VL, 30)
TYPED_SFIELD(sfCredentialType, VL, 31) TYPED_SFIELD(sfCredentialType, VL, 31)
TYPED_SFIELD(sfFinishFunction, VL, 32)
TYPED_SFIELD(sfContractCode, VL, 33)
TYPED_SFIELD(sfFunctionName, VL, 34)
// account (common) // account (common)
TYPED_SFIELD(sfAccount, ACCOUNT, 1) TYPED_SFIELD(sfAccount, ACCOUNT, 1)
@@ -332,7 +296,7 @@ TYPED_SFIELD(sfHolder, ACCOUNT, 11)
TYPED_SFIELD(sfDelegate, ACCOUNT, 12) TYPED_SFIELD(sfDelegate, ACCOUNT, 12)
// account (uncommon) // account (uncommon)
TYPED_SFIELD(sfHookAccount, ACCOUNT, 16) // 16 unused
TYPED_SFIELD(sfOtherChainSource, ACCOUNT, 18) TYPED_SFIELD(sfOtherChainSource, ACCOUNT, 18)
TYPED_SFIELD(sfOtherChainDestination, ACCOUNT, 19) TYPED_SFIELD(sfOtherChainDestination, ACCOUNT, 19)
TYPED_SFIELD(sfAttestationSignerAccount, ACCOUNT, 20) TYPED_SFIELD(sfAttestationSignerAccount, ACCOUNT, 20)
@@ -340,8 +304,7 @@ 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(sfContractAccount, 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)
@@ -380,7 +343,7 @@ UNTYPED_SFIELD(sfMemo, OBJECT, 10)
UNTYPED_SFIELD(sfSignerEntry, OBJECT, 11) UNTYPED_SFIELD(sfSignerEntry, OBJECT, 11)
UNTYPED_SFIELD(sfNFToken, OBJECT, 12) UNTYPED_SFIELD(sfNFToken, OBJECT, 12)
UNTYPED_SFIELD(sfEmitDetails, OBJECT, 13) UNTYPED_SFIELD(sfEmitDetails, OBJECT, 13)
UNTYPED_SFIELD(sfHook, OBJECT, 14) // 14 unused
UNTYPED_SFIELD(sfPermission, OBJECT, 15) UNTYPED_SFIELD(sfPermission, OBJECT, 15)
// inner object (uncommon) // inner object (uncommon)
@@ -388,11 +351,7 @@ UNTYPED_SFIELD(sfSigner, OBJECT, 16)
// 17 unused // 17 unused
UNTYPED_SFIELD(sfMajority, OBJECT, 18) UNTYPED_SFIELD(sfMajority, OBJECT, 18)
UNTYPED_SFIELD(sfDisabledValidator, OBJECT, 19) UNTYPED_SFIELD(sfDisabledValidator, OBJECT, 19)
UNTYPED_SFIELD(sfEmittedTxn, OBJECT, 20) // 20 to 24 unused
UNTYPED_SFIELD(sfHookExecution, OBJECT, 21)
UNTYPED_SFIELD(sfHookDefinition, OBJECT, 22)
UNTYPED_SFIELD(sfHookParameter, OBJECT, 23)
UNTYPED_SFIELD(sfHookGrant, OBJECT, 24)
UNTYPED_SFIELD(sfVoteEntry, OBJECT, 25) UNTYPED_SFIELD(sfVoteEntry, OBJECT, 25)
UNTYPED_SFIELD(sfAuctionSlot, OBJECT, 26) UNTYPED_SFIELD(sfAuctionSlot, OBJECT, 26)
UNTYPED_SFIELD(sfAuthAccount, OBJECT, 27) UNTYPED_SFIELD(sfAuthAccount, OBJECT, 27)
@@ -405,7 +364,10 @@ 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) UNTYPED_SFIELD(sfFunction, OBJECT, 37)
UNTYPED_SFIELD(sfInstanceParameter, OBJECT, 38)
UNTYPED_SFIELD(sfInstanceParameterValue, OBJECT, 39)
UNTYPED_SFIELD(sfParameter, OBJECT, 40)
// array of objects (common) // array of objects (common)
// ARRAY/1 is reserved for end of array // ARRAY/1 is reserved for end of array
@@ -419,16 +381,14 @@ UNTYPED_SFIELD(sfSufficient, ARRAY, 7)
UNTYPED_SFIELD(sfAffectedNodes, ARRAY, 8) UNTYPED_SFIELD(sfAffectedNodes, ARRAY, 8)
UNTYPED_SFIELD(sfMemos, ARRAY, 9) UNTYPED_SFIELD(sfMemos, ARRAY, 9)
UNTYPED_SFIELD(sfNFTokens, ARRAY, 10) UNTYPED_SFIELD(sfNFTokens, ARRAY, 10)
UNTYPED_SFIELD(sfHooks, ARRAY, 11) // 11 unused
UNTYPED_SFIELD(sfVoteSlots, ARRAY, 12) UNTYPED_SFIELD(sfVoteSlots, ARRAY, 12)
UNTYPED_SFIELD(sfAdditionalBooks, ARRAY, 13) UNTYPED_SFIELD(sfAdditionalBooks, ARRAY, 13)
// array of objects (uncommon) // array of objects (uncommon)
UNTYPED_SFIELD(sfMajorities, ARRAY, 16) UNTYPED_SFIELD(sfMajorities, ARRAY, 16)
UNTYPED_SFIELD(sfDisabledValidators, ARRAY, 17) UNTYPED_SFIELD(sfDisabledValidators, ARRAY, 17)
UNTYPED_SFIELD(sfHookExecutions, ARRAY, 18) // 18 to 20 unused
UNTYPED_SFIELD(sfHookParameters, ARRAY, 19)
UNTYPED_SFIELD(sfHookGrants, ARRAY, 20)
UNTYPED_SFIELD(sfXChainClaimAttestations, ARRAY, 21) UNTYPED_SFIELD(sfXChainClaimAttestations, ARRAY, 21)
UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22) UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22)
// 23 unused // 23 unused
@@ -440,5 +400,16 @@ 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)
UNTYPED_SFIELD(sfFunctions, ARRAY, 33)
UNTYPED_SFIELD(sfInstanceParameters, ARRAY, 34)
UNTYPED_SFIELD(sfInstanceParameterValues, ARRAY, 35)
UNTYPED_SFIELD(sfParameters, ARRAY, 36)
// clang-format on // data
TYPED_SFIELD(sfParameterValue, DATA, 1, SField::sMD_Default)
// data type
TYPED_SFIELD(sfParameterType, DATATYPE, 1)
// json
TYPED_SFIELD(sfContractJson, JSON, 1)

View File

@@ -69,11 +69,13 @@ TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate,
noPriv, noPriv,
({ ({
{sfDestination, soeREQUIRED}, {sfDestination, soeREQUIRED},
{sfDestinationTag, soeOPTIONAL},
{sfAmount, soeREQUIRED, soeMPTSupported}, {sfAmount, soeREQUIRED, soeMPTSupported},
{sfCondition, soeOPTIONAL}, {sfCondition, soeOPTIONAL},
{sfCancelAfter, soeOPTIONAL}, {sfCancelAfter, soeOPTIONAL},
{sfFinishAfter, soeOPTIONAL}, {sfFinishAfter, soeOPTIONAL},
{sfDestinationTag, soeOPTIONAL}, {sfFinishFunction, soeOPTIONAL},
{sfData, soeOPTIONAL},
})) }))
/** This transaction type completes an existing escrow. */ /** This transaction type completes an existing escrow. */
@@ -87,6 +89,7 @@ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish,
{sfFulfillment, soeOPTIONAL}, {sfFulfillment, soeOPTIONAL},
{sfCondition, soeOPTIONAL}, {sfCondition, soeOPTIONAL},
{sfCredentialIDs, soeOPTIONAL}, {sfCredentialIDs, soeOPTIONAL},
{sfComputationAllowance, soeOPTIONAL},
})) }))
@@ -851,7 +854,7 @@ TRANSACTION(ttDELEGATE_SET, 64, DelegateSet,
TRANSACTION(ttVAULT_CREATE, 65, VaultCreate, TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
Delegation::delegatable, Delegation::delegatable,
featureSingleAssetVault, featureSingleAssetVault,
createPseudoAcct | createMPTIssuance | mustModifyVault, createPseudoAcct | createMPTIssuance,
({ ({
{sfAsset, soeREQUIRED, soeMPTSupported}, {sfAsset, soeREQUIRED, soeMPTSupported},
{sfAssetsMaximum, soeOPTIONAL}, {sfAssetsMaximum, soeOPTIONAL},
@@ -869,7 +872,7 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
TRANSACTION(ttVAULT_SET, 66, VaultSet, TRANSACTION(ttVAULT_SET, 66, VaultSet,
Delegation::delegatable, Delegation::delegatable,
featureSingleAssetVault, featureSingleAssetVault,
mustModifyVault, noPriv,
({ ({
{sfVaultID, soeREQUIRED}, {sfVaultID, soeREQUIRED},
{sfAssetsMaximum, soeOPTIONAL}, {sfAssetsMaximum, soeOPTIONAL},
@@ -884,7 +887,7 @@ TRANSACTION(ttVAULT_SET, 66, VaultSet,
TRANSACTION(ttVAULT_DELETE, 67, VaultDelete, TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
Delegation::delegatable, Delegation::delegatable,
featureSingleAssetVault, featureSingleAssetVault,
mustDeleteAcct | destroyMPTIssuance | mustModifyVault, mustDeleteAcct | destroyMPTIssuance,
({ ({
{sfVaultID, soeREQUIRED}, {sfVaultID, soeREQUIRED},
})) }))
@@ -896,7 +899,7 @@ TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit, TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit,
Delegation::delegatable, Delegation::delegatable,
featureSingleAssetVault, featureSingleAssetVault,
mayAuthorizeMPT | mustModifyVault, mayAuthorizeMPT,
({ ({
{sfVaultID, soeREQUIRED}, {sfVaultID, soeREQUIRED},
{sfAmount, soeREQUIRED, soeMPTSupported}, {sfAmount, soeREQUIRED, soeMPTSupported},
@@ -909,7 +912,7 @@ TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit,
TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw, TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
Delegation::delegatable, Delegation::delegatable,
featureSingleAssetVault, featureSingleAssetVault,
mayDeleteMPT | mayAuthorizeMPT | mustModifyVault, mayDeleteMPT,
({ ({
{sfVaultID, soeREQUIRED}, {sfVaultID, soeREQUIRED},
{sfAmount, soeREQUIRED, soeMPTSupported}, {sfAmount, soeREQUIRED, soeMPTSupported},
@@ -924,7 +927,7 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback, TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback,
Delegation::delegatable, Delegation::delegatable,
featureSingleAssetVault, featureSingleAssetVault,
mayDeleteMPT | mustModifyVault, mayDeleteMPT,
({ ({
{sfVaultID, soeREQUIRED}, {sfVaultID, soeREQUIRED},
{sfHolder, soeREQUIRED}, {sfHolder, soeREQUIRED},
@@ -944,139 +947,96 @@ TRANSACTION(ttBATCH, 71, Batch,
{sfBatchSigners, soeOPTIONAL}, {sfBatchSigners, soeOPTIONAL},
})) }))
/** Reserve 72-73 for future Vault-related transactions */ /** This transaction type creates the smart contract. */
/** This transaction creates and updates a Loan Broker */
#if TRANSACTION_INCLUDE #if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanBrokerSet.h> # include <xrpld/app/tx/detail/ContractCreate.h>
#endif #endif
TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet, TRANSACTION(ttCONTRACT_CREATE, 72, ContractCreate,
Delegation::delegatable, Delegation::delegatable,
featureLendingProtocol, featureSmartContract,
createPseudoAcct | mayAuthorizeMPT, ({ createPseudoAcct,
{sfVaultID, soeREQUIRED}, ({
{sfLoanBrokerID, soeOPTIONAL}, {sfContractCode, soeOPTIONAL},
{sfData, soeOPTIONAL}, {sfContractHash, soeOPTIONAL},
{sfManagementFeeRate, soeOPTIONAL}, {sfFunctions, soeOPTIONAL},
{sfDebtMaximum, soeOPTIONAL}, {sfInstanceParameters, soeOPTIONAL},
{sfCoverRateMinimum, soeOPTIONAL}, {sfInstanceParameterValues, soeOPTIONAL},
{sfCoverRateLiquidation, soeOPTIONAL}, {sfURI, soeOPTIONAL},
})) }))
/** This transaction deletes a Loan Broker */ /** This transaction type modifies the smart contract. */
#if TRANSACTION_INCLUDE #if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanBrokerDelete.h> # include <xrpld/app/tx/detail/ContractModify.h>
#endif #endif
TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete, TRANSACTION(ttCONTRACT_MODIFY, 73, ContractModify,
Delegation::delegatable, Delegation::delegatable,
featureLendingProtocol, featureSmartContract,
mustDeleteAcct | mayAuthorizeMPT, ({ noPriv,
{sfLoanBrokerID, soeREQUIRED}, ({
{sfContractAccount, soeOPTIONAL},
{sfOwner, soeOPTIONAL},
{sfContractCode, soeOPTIONAL},
{sfContractHash, soeOPTIONAL},
{sfFunctions, soeOPTIONAL},
{sfInstanceParameters, soeOPTIONAL},
{sfInstanceParameterValues, soeOPTIONAL},
{sfURI, soeOPTIONAL},
})) }))
/** This transaction deposits First Loss Capital into a Loan Broker */ /** This transaction type deletes the smart contract. */
#if TRANSACTION_INCLUDE #if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanBrokerCoverDeposit.h> # include <xrpld/app/tx/detail/ContractDelete.h>
#endif #endif
TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit, TRANSACTION(ttCONTRACT_DELETE, 74, ContractDelete,
Delegation::delegatable, Delegation::delegatable,
featureLendingProtocol, featureSmartContract,
noPriv, ({ mustDeleteAcct,
{sfLoanBrokerID, soeREQUIRED}, ({
{sfContractAccount, soeREQUIRED},
}))
/** This transaction type claws back funds from the contract. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/ContractClawback.h>
#endif
TRANSACTION(ttCONTRACT_CLAWBACK, 75, ContractClawback,
Delegation::delegatable,
featureSmartContract,
noPriv,
({
{sfContractAccount, soeOPTIONAL},
{sfAmount, soeREQUIRED, soeMPTSupported}, {sfAmount, soeREQUIRED, soeMPTSupported},
})) }))
/** This transaction withdraws First Loss Capital from a Loan Broker */ /** This transaction type deletes user data. */
#if TRANSACTION_INCLUDE #if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanBrokerCoverWithdraw.h> # include <xrpld/app/tx/detail/ContractUserDelete.h>
#endif #endif
TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw, TRANSACTION(ttCONTRACT_USER_DELETE, 76, ContractUserDelete,
Delegation::delegatable, Delegation::delegatable,
featureLendingProtocol, featureSmartContract,
mayAuthorizeMPT, ({ noPriv,
{sfLoanBrokerID, soeREQUIRED}, ({
{sfAmount, soeREQUIRED, soeMPTSupported}, {sfContractAccount, soeREQUIRED},
{sfDestination, soeOPTIONAL}, {sfFunctionName, soeREQUIRED},
{sfDestinationTag, soeOPTIONAL}, {sfParameters, soeOPTIONAL},
{sfComputationAllowance, soeREQUIRED},
})) }))
/** This transaction claws back First Loss Capital from a Loan Broker to /** This transaction type calls the smart contract. */
the issuer of the capital */
#if TRANSACTION_INCLUDE #if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LoanBrokerCoverClawback.h> # include <xrpld/app/tx/detail/ContractCall.h>
#endif #endif
TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback, TRANSACTION(ttCONTRACT_CALL, 77, ContractCall,
Delegation::delegatable, Delegation::delegatable,
featureLendingProtocol, featureSmartContract,
noPriv, ({ noPriv,
{sfLoanBrokerID, soeOPTIONAL}, ({
{sfAmount, soeOPTIONAL, soeMPTSupported}, {sfContractAccount, soeREQUIRED},
{sfFunctionName, soeREQUIRED},
{sfParameters, soeOPTIONAL},
{sfComputationAllowance, soeREQUIRED},
})) }))
/** 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
@@ -1111,6 +1071,10 @@ TRANSACTION(ttFEE, 101, SetFee,
{sfBaseFeeDrops, soeOPTIONAL}, {sfBaseFeeDrops, soeOPTIONAL},
{sfReserveBaseDrops, soeOPTIONAL}, {sfReserveBaseDrops, soeOPTIONAL},
{sfReserveIncrementDrops, soeOPTIONAL}, {sfReserveIncrementDrops, soeOPTIONAL},
// Smart Escrow fields
{sfExtensionComputeLimit, soeOPTIONAL},
{sfExtensionSizeLimit, soeOPTIONAL},
{sfGasPrice, soeOPTIONAL},
})) }))
/** This system-generated transaction type is used to update the network's negative UNL /** This system-generated transaction type is used to update the network's negative UNL

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.
@@ -210,6 +208,7 @@ JSS(command); // in: RPCHandler
JSS(complete); // out: NetworkOPs, InboundLedger JSS(complete); // out: NetworkOPs, InboundLedger
JSS(complete_ledgers); // out: NetworkOPs, PeerImp JSS(complete_ledgers); // out: NetworkOPs, PeerImp
JSS(consensus); // out: NetworkOPs, LedgerConsensus JSS(consensus); // out: NetworkOPs, LedgerConsensus
JSS(contract_account); // out: ContractInfo
JSS(converge_time); // out: NetworkOPs JSS(converge_time); // out: NetworkOPs
JSS(converge_time_s); // out: NetworkOPs JSS(converge_time_s); // out: NetworkOPs
JSS(cookie); // out: NetworkOPs JSS(cookie); // out: NetworkOPs
@@ -274,6 +273,9 @@ JSS(expected_date_UTC); // out: any (warnings)
JSS(expected_ledger_size); // out: TxQ JSS(expected_ledger_size); // out: TxQ
JSS(expiration); // out: AccountOffers, AccountChannels, JSS(expiration); // out: AccountOffers, AccountChannels,
// ValidatorList, amm_info // ValidatorList, amm_info
JSS(extension_compute); // out: NetworkOps
JSS(extension_size); // out: NetworkOps
JSS(gas_price); // out: NetworkOps
JSS(fail_hard); // in: Sign, Submit JSS(fail_hard); // in: Sign, Submit
JSS(failed); // out: InboundLedger JSS(failed); // out: InboundLedger
JSS(feature); // in: Feature JSS(feature); // in: Feature
@@ -294,6 +296,8 @@ JSS(flags); // out: AccountOffers,
JSS(forward); // in: AccountTx JSS(forward); // in: AccountTx
JSS(freeze); // out: AccountLines JSS(freeze); // out: AccountLines
JSS(freeze_peer); // out: AccountLines JSS(freeze_peer); // out: AccountLines
JSS(function); // in: ContractInfo
JSS(functions); // out: ContractInfo
JSS(deep_freeze); // out: AccountLines JSS(deep_freeze); // out: AccountLines
JSS(deep_freeze_peer); // out: AccountLines JSS(deep_freeze_peer); // out: AccountLines
JSS(frozen_balances); // out: GatewayBalances JSS(frozen_balances); // out: GatewayBalances
@@ -394,8 +398,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 +510,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
@@ -574,7 +575,6 @@ JSS(settle_delay); // out: AccountChannels
JSS(severity); // in: LogLevel JSS(severity); // in: LogLevel
JSS(shares); // out: VaultInfo JSS(shares); // out: VaultInfo
JSS(signature); // out: NetworkOPs, ChannelAuthorize JSS(signature); // out: NetworkOPs, ChannelAuthorize
JSS(signature_target); // in: TransactionSign
JSS(signature_verified); // out: ChannelVerify JSS(signature_verified); // out: ChannelVerify
JSS(signing_key); // out: NetworkOPs JSS(signing_key); // out: NetworkOPs
JSS(signing_keys); // out: ValidatorList JSS(signing_keys); // out: ValidatorList
@@ -584,6 +584,7 @@ JSS(size); // out: get_aggregate_price
JSS(snapshot); // in: Subscribe JSS(snapshot); // in: Subscribe
JSS(source_account); // in: PathRequest, RipplePathFind JSS(source_account); // in: PathRequest, RipplePathFind
JSS(source_amount); // in: PathRequest, RipplePathFind JSS(source_amount); // in: PathRequest, RipplePathFind
JSS(source_code_uri); // out: ContractInfo
JSS(source_currencies); // in: PathRequest, RipplePathFind JSS(source_currencies); // in: PathRequest, RipplePathFind
JSS(source_tag); // out: AccountChannels JSS(source_tag); // out: AccountChannels
JSS(stand_alone); // out: NetworkOPs JSS(stand_alone); // out: NetworkOPs
@@ -681,6 +682,7 @@ JSS(url_password); // in: Subscribe
JSS(url_username); // in: Subscribe JSS(url_username); // in: Subscribe
JSS(urlgravatar); // JSS(urlgravatar); //
JSS(username); // in: Subscribe JSS(username); // in: Subscribe
JSS(user_data); // out: ContractInfo
JSS(validated); // out: NetworkOPs, RPCHelpers, AccountTx* JSS(validated); // out: NetworkOPs, RPCHelpers, AccountTx*
// Tx // Tx
JSS(validator_list_expires); // out: NetworkOps, ValidatorList JSS(validator_list_expires); // out: NetworkOps, ValidatorList
@@ -728,11 +730,11 @@ JSS(write_load); // out: GetCounts
#pragma push_macro("LEDGER_ENTRY_DUPLICATE") #pragma push_macro("LEDGER_ENTRY_DUPLICATE")
#undef LEDGER_ENTRY_DUPLICATE #undef LEDGER_ENTRY_DUPLICATE
#define LEDGER_ENTRY(tag, value, name, rpcName, ...) \ #define LEDGER_ENTRY(tag, value, name, rpcName, fields) \
JSS(name); \ JSS(name); \
JSS(rpcName); JSS(rpcName);
#define LEDGER_ENTRY_DUPLICATE(tag, value, name, rpcName, ...) JSS(rpcName); #define LEDGER_ENTRY_DUPLICATE(tag, value, name, rpcName, fields) JSS(rpcName);
#include <xrpl/protocol/detail/ledger_entries.macro> #include <xrpl/protocol/detail/ledger_entries.macro>

View File

@@ -436,12 +436,10 @@ public:
admin_.erase(admin_.iterator_to(entry)); admin_.erase(admin_.iterator_to(entry));
break; break;
default: default:
// LCOV_EXCL_START
UNREACHABLE( UNREACHABLE(
"ripple::Resource::Logic::release : invalid entry " "ripple::Resource::Logic::release : invalid entry "
"kind"); "kind");
break; break;
// LCOV_EXCL_STOP
} }
inactive_.push_back(entry); inactive_.push_back(entry);
entry.whenExpires = m_clock.now() + secondsUntilExpiration; entry.whenExpires = m_clock.now() + secondsUntilExpiration;

View File

@@ -25,7 +25,7 @@
#include <xrpl/server/Port.h> #include <xrpl/server/Port.h>
#include <xrpl/server/detail/ServerImpl.h> #include <xrpl/server/detail/ServerImpl.h>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
namespace ripple { namespace ripple {
@@ -34,10 +34,10 @@ template <class Handler>
std::unique_ptr<Server> std::unique_ptr<Server>
make_Server( make_Server(
Handler& handler, Handler& handler,
boost::asio::io_service& io_service, boost::asio::io_context& io_context,
beast::Journal journal) beast::Journal journal)
{ {
return std::make_unique<ServerImpl<Handler>>(handler, io_service, journal); return std::make_unique<ServerImpl<Handler>>(handler, io_context, journal);
} }
} // namespace ripple } // namespace ripple

View File

@@ -88,9 +88,7 @@ public:
++iter) ++iter)
{ {
typename BufferSequence::value_type const& buffer(*iter); typename BufferSequence::value_type const& buffer(*iter);
write( write(buffer.data(), boost::asio::buffer_size(buffer));
boost::asio::buffer_cast<void const*>(buffer),
boost::asio::buffer_size(buffer));
} }
} }
@@ -104,7 +102,7 @@ public:
/** Detach the session. /** Detach the session.
This holds the session open so that the response can be sent This holds the session open so that the response can be sent
asynchronously. Calls to io_service::run made by the server asynchronously. Calls to io_context::run made by the server
will not return until all detached sessions are closed. will not return until all detached sessions are closed.
*/ */
virtual std::shared_ptr<Session> virtual std::shared_ptr<Session>

View File

@@ -24,11 +24,13 @@
#include <xrpl/beast/net/IPAddressConversion.h> #include <xrpl/beast/net/IPAddressConversion.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/server/Session.h> #include <xrpl/server/Session.h>
#include <xrpl/server/detail/Spawn.h>
#include <xrpl/server/detail/io_list.h> #include <xrpl/server/detail/io_list.h>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp> #include <boost/asio/spawn.hpp>
#include <boost/asio/ssl/stream.hpp> #include <boost/asio/ssl/stream.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/streambuf.hpp> #include <boost/asio/streambuf.hpp>
#include <boost/beast/core/stream_traits.hpp> #include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/http/dynamic_body.hpp> #include <boost/beast/http/dynamic_body.hpp>
@@ -215,8 +217,8 @@ BaseHTTPPeer<Handler, Impl>::BaseHTTPPeer(
ConstBufferSequence const& buffers) ConstBufferSequence const& buffers)
: port_(port) : port_(port)
, handler_(handler) , handler_(handler)
, work_(executor) , work_(boost::asio::make_work_guard(executor))
, strand_(executor) , strand_(boost::asio::make_strand(executor))
, remote_address_(remote_address) , remote_address_(remote_address)
, journal_(journal) , journal_(journal)
{ {
@@ -356,7 +358,7 @@ BaseHTTPPeer<Handler, Impl>::on_write(
return; return;
if (graceful_) if (graceful_)
return do_close(); return do_close();
boost::asio::spawn( util::spawn(
strand_, strand_,
std::bind( std::bind(
&BaseHTTPPeer<Handler, Impl>::do_read, &BaseHTTPPeer<Handler, Impl>::do_read,
@@ -375,7 +377,7 @@ BaseHTTPPeer<Handler, Impl>::do_writer(
{ {
auto const p = impl().shared_from_this(); auto const p = impl().shared_from_this();
resume = std::function<void(void)>([this, p, writer, keep_alive]() { resume = std::function<void(void)>([this, p, writer, keep_alive]() {
boost::asio::spawn( util::spawn(
strand_, strand_,
std::bind( std::bind(
&BaseHTTPPeer<Handler, Impl>::do_writer, &BaseHTTPPeer<Handler, Impl>::do_writer,
@@ -406,7 +408,7 @@ BaseHTTPPeer<Handler, Impl>::do_writer(
if (!keep_alive) if (!keep_alive)
return do_close(); return do_close();
boost::asio::spawn( util::spawn(
strand_, strand_,
std::bind( std::bind(
&BaseHTTPPeer<Handler, Impl>::do_read, &BaseHTTPPeer<Handler, Impl>::do_read,
@@ -448,14 +450,14 @@ BaseHTTPPeer<Handler, Impl>::write(
std::shared_ptr<Writer> const& writer, std::shared_ptr<Writer> const& writer,
bool keep_alive) bool keep_alive)
{ {
boost::asio::spawn(bind_executor( util::spawn(
strand_, strand_,
std::bind( std::bind(
&BaseHTTPPeer<Handler, Impl>::do_writer, &BaseHTTPPeer<Handler, Impl>::do_writer,
impl().shared_from_this(), impl().shared_from_this(),
writer, writer,
keep_alive, keep_alive,
std::placeholders::_1))); std::placeholders::_1));
} }
// DEPRECATED // DEPRECATED
@@ -490,12 +492,12 @@ BaseHTTPPeer<Handler, Impl>::complete()
} }
// keep-alive // keep-alive
boost::asio::spawn(bind_executor( util::spawn(
strand_, strand_,
std::bind( std::bind(
&BaseHTTPPeer<Handler, Impl>::do_read, &BaseHTTPPeer<Handler, Impl>::do_read,
impl().shared_from_this(), impl().shared_from_this(),
std::placeholders::_1))); std::placeholders::_1));
} }
// DEPRECATED // DEPRECATED

View File

@@ -91,8 +91,8 @@ BasePeer<Handler, Impl>::BasePeer(
return "##" + std::to_string(++id) + " "; return "##" + std::to_string(++id) + " ";
}()) }())
, j_(sink_) , j_(sink_)
, work_(executor) , work_(boost::asio::make_work_guard(executor))
, strand_(executor) , strand_(boost::asio::make_strand(executor))
{ {
} }

View File

@@ -29,6 +29,7 @@
#include <xrpl/server/detail/BasePeer.h> #include <xrpl/server/detail/BasePeer.h>
#include <xrpl/server/detail/LowestLayer.h> #include <xrpl/server/detail/LowestLayer.h>
#include <boost/asio/error.hpp>
#include <boost/beast/core/multi_buffer.hpp> #include <boost/beast/core/multi_buffer.hpp>
#include <boost/beast/http/message.hpp> #include <boost/beast/http/message.hpp>
#include <boost/beast/websocket.hpp> #include <boost/beast/websocket.hpp>
@@ -420,11 +421,17 @@ BaseWSPeer<Handler, Impl>::start_timer()
// Max seconds without completing a message // Max seconds without completing a message
static constexpr std::chrono::seconds timeout{30}; static constexpr std::chrono::seconds timeout{30};
static constexpr std::chrono::seconds timeoutLocal{3}; static constexpr std::chrono::seconds timeoutLocal{3};
error_code ec;
timer_.expires_from_now( try
remote_endpoint().address().is_loopback() ? timeoutLocal : timeout, ec); {
if (ec) timer_.expires_after(
return fail(ec, "start_timer"); remote_endpoint().address().is_loopback() ? timeoutLocal : timeout);
}
catch (boost::system::system_error const& e)
{
return fail(e.code(), "start_timer");
}
timer_.async_wait(bind_executor( timer_.async_wait(bind_executor(
strand_, strand_,
std::bind( std::bind(
@@ -438,8 +445,14 @@ template <class Handler, class Impl>
void void
BaseWSPeer<Handler, Impl>::cancel_timer() BaseWSPeer<Handler, Impl>::cancel_timer()
{ {
error_code ec; try
timer_.cancel(ec); {
timer_.cancel();
}
catch (boost::system::system_error const&)
{
// ignored
}
} }
template <class Handler, class Impl> template <class Handler, class Impl>

View File

@@ -69,7 +69,7 @@ private:
stream_type stream_; stream_type stream_;
socket_type& socket_; socket_type& socket_;
endpoint_type remote_address_; endpoint_type remote_address_;
boost::asio::io_context::strand strand_; boost::asio::strand<boost::asio::io_context::executor_type> strand_;
beast::Journal const j_; beast::Journal const j_;
public: public:
@@ -95,7 +95,7 @@ private:
Handler& handler_; Handler& handler_;
boost::asio::io_context& ioc_; boost::asio::io_context& ioc_;
acceptor_type acceptor_; acceptor_type acceptor_;
boost::asio::io_context::strand strand_; boost::asio::strand<boost::asio::io_context::executor_type> strand_;
bool ssl_; bool ssl_;
bool plain_; bool plain_;
@@ -155,7 +155,7 @@ Door<Handler>::Detector::Detector(
, stream_(std::move(stream)) , stream_(std::move(stream))
, socket_(stream_.socket()) , socket_(stream_.socket())
, remote_address_(remote_address) , remote_address_(remote_address)
, strand_(ioc_) , strand_(boost::asio::make_strand(ioc_))
, j_(j) , j_(j)
{ {
} }
@@ -164,7 +164,7 @@ template <class Handler>
void void
Door<Handler>::Detector::run() Door<Handler>::Detector::run()
{ {
boost::asio::spawn( util::spawn(
strand_, strand_,
std::bind( std::bind(
&Detector::do_detect, &Detector::do_detect,
@@ -269,7 +269,7 @@ Door<Handler>::reOpen()
Throw<std::exception>(); Throw<std::exception>();
} }
acceptor_.listen(boost::asio::socket_base::max_connections, ec); acceptor_.listen(boost::asio::socket_base::max_listen_connections, ec);
if (ec) if (ec)
{ {
JLOG(j_.error()) << "Listen on port '" << port_.name JLOG(j_.error()) << "Listen on port '" << port_.name
@@ -291,7 +291,7 @@ Door<Handler>::Door(
, handler_(handler) , handler_(handler)
, ioc_(io_context) , ioc_(io_context)
, acceptor_(io_context) , acceptor_(io_context)
, strand_(io_context) , strand_(boost::asio::make_strand(io_context))
, ssl_( , ssl_(
port_.protocol.count("https") > 0 || port_.protocol.count("https") > 0 ||
port_.protocol.count("wss") > 0 || port_.protocol.count("wss2") > 0 || port_.protocol.count("wss") > 0 || port_.protocol.count("wss2") > 0 ||
@@ -307,7 +307,7 @@ template <class Handler>
void void
Door<Handler>::run() Door<Handler>::run()
{ {
boost::asio::spawn( util::spawn(
strand_, strand_,
std::bind( std::bind(
&Door<Handler>::do_accept, &Door<Handler>::do_accept,
@@ -320,7 +320,8 @@ void
Door<Handler>::close() Door<Handler>::close()
{ {
if (!strand_.running_in_this_thread()) if (!strand_.running_in_this_thread())
return strand_.post( return boost::asio::post(
strand_,
std::bind(&Door<Handler>::close, this->shared_from_this())); std::bind(&Door<Handler>::close, this->shared_from_this()));
error_code ec; error_code ec;
acceptor_.close(ec); acceptor_.close(ec);

View File

@@ -105,7 +105,7 @@ PlainHTTPPeer<Handler>::run()
{ {
if (!this->handler_.onAccept(this->session(), this->remote_address_)) if (!this->handler_.onAccept(this->session(), this->remote_address_))
{ {
boost::asio::spawn( util::spawn(
this->strand_, this->strand_,
std::bind(&PlainHTTPPeer::do_close, this->shared_from_this())); std::bind(&PlainHTTPPeer::do_close, this->shared_from_this()));
return; return;
@@ -114,7 +114,7 @@ PlainHTTPPeer<Handler>::run()
if (!socket_.is_open()) if (!socket_.is_open())
return; return;
boost::asio::spawn( util::spawn(
this->strand_, this->strand_,
std::bind( std::bind(
&PlainHTTPPeer::do_read, &PlainHTTPPeer::do_read,

View File

@@ -115,14 +115,14 @@ SSLHTTPPeer<Handler>::run()
{ {
if (!this->handler_.onAccept(this->session(), this->remote_address_)) if (!this->handler_.onAccept(this->session(), this->remote_address_))
{ {
boost::asio::spawn( util::spawn(
this->strand_, this->strand_,
std::bind(&SSLHTTPPeer::do_close, this->shared_from_this())); std::bind(&SSLHTTPPeer::do_close, this->shared_from_this()));
return; return;
} }
if (!socket_.is_open()) if (!socket_.is_open())
return; return;
boost::asio::spawn( util::spawn(
this->strand_, this->strand_,
std::bind( std::bind(
&SSLHTTPPeer::do_handshake, &SSLHTTPPeer::do_handshake,
@@ -164,7 +164,7 @@ SSLHTTPPeer<Handler>::do_handshake(yield_context do_yield)
this->port().protocol.count("https") > 0; this->port().protocol.count("https") > 0;
if (http) if (http)
{ {
boost::asio::spawn( util::spawn(
this->strand_, this->strand_,
std::bind( std::bind(
&SSLHTTPPeer::do_read, &SSLHTTPPeer::do_read,

View File

@@ -26,6 +26,8 @@
#include <xrpl/server/detail/io_list.h> #include <xrpl/server/detail/io_list.h>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/io_context.hpp>
#include <array> #include <array>
#include <chrono> #include <chrono>
@@ -85,9 +87,11 @@ private:
Handler& handler_; Handler& handler_;
beast::Journal const j_; beast::Journal const j_;
boost::asio::io_service& io_service_; boost::asio::io_context& io_context_;
boost::asio::io_service::strand strand_; boost::asio::strand<boost::asio::io_context::executor_type> strand_;
std::optional<boost::asio::io_service::work> work_; std::optional<boost::asio::executor_work_guard<
boost::asio::io_context::executor_type>>
work_;
std::mutex m_; std::mutex m_;
std::vector<Port> ports_; std::vector<Port> ports_;
@@ -100,7 +104,7 @@ private:
public: public:
ServerImpl( ServerImpl(
Handler& handler, Handler& handler,
boost::asio::io_service& io_service, boost::asio::io_context& io_context,
beast::Journal journal); beast::Journal journal);
~ServerImpl(); ~ServerImpl();
@@ -123,10 +127,10 @@ public:
return ios_; return ios_;
} }
boost::asio::io_service& boost::asio::io_context&
get_io_service() get_io_context()
{ {
return io_service_; return io_context_;
} }
bool bool
@@ -140,13 +144,13 @@ private:
template <class Handler> template <class Handler>
ServerImpl<Handler>::ServerImpl( ServerImpl<Handler>::ServerImpl(
Handler& handler, Handler& handler,
boost::asio::io_service& io_service, boost::asio::io_context& io_context,
beast::Journal journal) beast::Journal journal)
: handler_(handler) : handler_(handler)
, j_(journal) , j_(journal)
, io_service_(io_service) , io_context_(io_context)
, strand_(io_service_) , strand_(boost::asio::make_strand(io_context_))
, work_(io_service_) , work_(std::in_place, boost::asio::make_work_guard(io_context_))
{ {
} }
@@ -173,7 +177,7 @@ ServerImpl<Handler>::ports(std::vector<Port> const& ports)
ports_.push_back(port); ports_.push_back(port);
auto& internalPort = ports_.back(); auto& internalPort = ports_.back();
if (auto sp = ios_.emplace<Door<Handler>>( if (auto sp = ios_.emplace<Door<Handler>>(
handler_, io_service_, internalPort, j_)) handler_, io_context_, internalPort, j_))
{ {
list_.push_back(sp); list_.push_back(sp);

View File

@@ -0,0 +1,108 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright(c) 2025 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_SERVER_SPAWN_H_INCLUDED
#define RIPPLE_SERVER_SPAWN_H_INCLUDED
#include <xrpl/basics/Log.h>
#include <boost/asio/spawn.hpp>
#include <boost/asio/strand.hpp>
#include <concepts>
#include <type_traits>
namespace ripple::util {
namespace impl {
template <typename T>
concept IsStrand = std::same_as<
std::decay_t<T>,
boost::asio::strand<typename std::decay_t<T>::inner_executor_type>>;
/**
* @brief A completion handler that restores `boost::asio::spawn`'s behaviour
* from Boost 1.83
*
* This is intended to be passed as the third argument to `boost::asio::spawn`
* so that exceptions are not ignored but propagated to `io_context.run()` call
* site.
*
* @param ePtr The exception that was caught on the coroutine
*/
inline constexpr auto kPROPAGATE_EXCEPTIONS = [](std::exception_ptr ePtr) {
if (ePtr)
{
try
{
std::rethrow_exception(ePtr);
}
catch (std::exception const& e)
{
JLOG(debugLog().warn()) << "Spawn exception: " << e.what();
throw;
}
catch (...)
{
JLOG(debugLog().warn()) << "Spawn exception: Unknown";
throw;
}
}
};
} // namespace impl
/**
* @brief Spawns a coroutine using `boost::asio::spawn`
*
* @note This uses kPROPAGATE_EXCEPTIONS to force asio to propagate exceptions
* through `io_context`
* @note Since implicit strand was removed from boost::asio::spawn this helper
* function adds the strand back
*
* @tparam Ctx The type of the context/strand
* @tparam F The type of the function to execute
* @param ctx The execution context
* @param func The function to execute. Must return `void`
*/
template <typename Ctx, typename F>
requires std::is_invocable_r_v<void, F, boost::asio::yield_context>
void
spawn(Ctx&& ctx, F&& func)
{
if constexpr (impl::IsStrand<Ctx>)
{
boost::asio::spawn(
std::forward<Ctx>(ctx),
std::forward<F>(func),
impl::kPROPAGATE_EXCEPTIONS);
}
else
{
boost::asio::spawn(
boost::asio::make_strand(
boost::asio::get_associated_executor(std::forward<Ctx>(ctx))),
std::forward<F>(func),
impl::kPROPAGATE_EXCEPTIONS);
}
}
} // namespace ripple::util
#endif

View File

@@ -166,7 +166,7 @@ public:
May be called concurrently. May be called concurrently.
Preconditions: Preconditions:
No call to io_service::run on any io_service No call to io_context::run on any io_context
used by work objects associated with this io_list used by work objects associated with this io_list
exists in the caller's call stack. exists in the caller's call stack.
*/ */

View File

@@ -49,7 +49,7 @@ Section::append(std::vector<std::string> const& lines)
// <key> '=' <value> // <key> '=' <value>
static boost::regex const re1( static boost::regex const re1(
"^" // start of line "^" // start of line
"(?:\\s*)" // whitespace (optional) "(?:\\s*)" // whitespace (optonal)
"([a-zA-Z][_a-zA-Z0-9]*)" // <key> "([a-zA-Z][_a-zA-Z0-9]*)" // <key>
"(?:\\s*)" // whitespace (optional) "(?:\\s*)" // whitespace (optional)
"(?:=)" // '=' "(?:=)" // '='

View File

@@ -239,11 +239,9 @@ Logs::fromSeverity(beast::severities::Severity level)
case kError: case kError:
return lsERROR; return lsERROR;
// LCOV_EXCL_START
default: default:
UNREACHABLE("ripple::Logs::fromSeverity : invalid severity"); UNREACHABLE("ripple::Logs::fromSeverity : invalid severity");
[[fallthrough]]; [[fallthrough]];
// LCOV_EXCL_STOP
case kFatal: case kFatal:
break; break;
} }
@@ -267,11 +265,9 @@ Logs::toSeverity(LogSeverity level)
return kWarning; return kWarning;
case lsERROR: case lsERROR:
return kError; return kError;
// LCOV_EXCL_START
default: default:
UNREACHABLE("ripple::Logs::toSeverity : invalid severity"); UNREACHABLE("ripple::Logs::toSeverity : invalid severity");
[[fallthrough]]; [[fallthrough]];
// LCOV_EXCL_STOP
case lsFATAL: case lsFATAL:
break; break;
} }
@@ -296,11 +292,9 @@ Logs::toString(LogSeverity s)
return "Error"; return "Error";
case lsFATAL: case lsFATAL:
return "Fatal"; return "Fatal";
// LCOV_EXCL_START
default: default:
UNREACHABLE("ripple::Logs::toString : invalid severity"); UNREACHABLE("ripple::Logs::toString : invalid severity");
return "Unknown"; return "Unknown";
// LCOV_EXCL_STOP
} }
} }
@@ -362,11 +356,9 @@ Logs::format(
case kError: case kError:
output += "ERR "; output += "ERR ";
break; break;
// LCOV_EXCL_START
default: default:
UNREACHABLE("ripple::Logs::format : invalid severity"); UNREACHABLE("ripple::Logs::format : invalid severity");
[[fallthrough]]; [[fallthrough]];
// LCOV_EXCL_STOP
case kFatal: case kFatal:
output += "FTL "; output += "FTL ";
break; break;

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