Compare commits

..

345 Commits

Author SHA1 Message Date
tequ
8f244d888d Merge remote-tracking branch 'upstream/sync-2.4.0' into HookAPISerializedType240 2026-02-18 10:39:29 +09:00
tequ
3c49f80013 Add new keylets to util_keylet (#533) 2026-02-18 11:18:59 +10:00
Niq Dudfield
090e4ad25e Merge dev (309e517e7) into sync-2.4.0: docs + guard checker CI (#683)
* Hook API Refactor2: Amendment Guards (#621)

* Hook API Refactor3: Consolidate the Hook API definitions from Enum.h and ApplyHook.h into a single file. (#622)

* Hook API Refactoring / Unit Testing (#581)

* fix `Xahau Ledger` to `Xahau Network` (#651)

* Add GitHub Actions workflow for Guard Checker Build (#658)

* fix `Xahau Ledger` to `Xahau Network` (#651)

* Add GitHub Actions workflow for Guard Checker Build (#658)

* fix: update guard checker build path for directory restructure

* fix: update stale ripple include paths in hook headers

* fix(test): avoid deleted PublicKey default ctor in HookAPI test

* chore(levelization): update ordering after hook/protocol dependency change

---------

Co-authored-by: tequ <git@tequ.dev>
2026-02-18 11:17:27 +10:00
Niq Dudfield
7a0c914ce9 Merge dev (d20927237) into sync-2.4.0: HookAPI refactor (#681)
* Hook API Refactor2: Amendment Guards (#621)

* Hook API Refactor3: Consolidate the Hook API definitions from Enum.h and ApplyHook.h into a single file. (#622)

* Hook API Refactoring / Unit Testing (#581)

* Hook API Refactor2: Amendment Guards (#621)

* Hook API Refactor3: Consolidate the Hook API definitions from Enum.h and ApplyHook.h into a single file. (#622)

* Hook API Refactoring / Unit Testing (#581)

* fix: update clang-format to v18 and fix include ordering

- Update verify-generated-headers CI to use clang-format 18 (matching
  clang-format.yml) instead of stale v10 which can't parse .clang-format
- Add .mise.toml for local clang-format 18 tooling
- Fix include ordering in cherry-picked files per clang-format 18

* chore: update levelization results for HookAPI changes

New loop: xrpl.hook <-> xrpld.app due to HookAPI.h including
Transaction.h from xrpld.app.

---------

Co-authored-by: tequ <git@tequ.dev>
2026-02-16 18:51:04 +10:00
tequ
d712345c84 Merge branch 'dev' into sync-2.4.0 2026-02-09 11:34:26 +09:00
tequ
cc70d48e91 Merge remote-tracking branch 'upstream/dev' into sync-2.4.0 2026-01-06 23:18:18 +09:00
tequ
01e7ee4f03 fix: update comment for HookParameterValue size limit 2026-01-06 23:17:43 +09:00
tequ
222772d99b fix get_stobject_length to work STI_PATHSET correctly 2026-01-06 23:14:47 +09:00
tequ
9e6135ba42 refactor get_stobject_length 2026-01-06 20:21:12 +09:00
tequ
f0329b4054 Merge branch 'dev' into HookAPISerializedType240 2026-01-06 18:21:01 +09:00
tequ
5a9baed9d0 HookAPISerializedType240 Amendment 2025-12-17 19:39:31 +09:00
tequ
8d1aadd23d Update CMake version to 3.25.3 in macOS workflow 2025-12-17 12:53:20 +09:00
tequ
8d2a5e3c4e Merge branch 'dev' into sync-2.4.0 2025-12-17 12:38:43 +09:00
tequ
f6fe33103c Fix differences such as LedgerHash that occurred due to NetworkID in ltFeeSettings 2025-12-01 19:28:23 +09:00
tequ
b9d966dd32 Merge remote-tracking branch 'upstream/dev' into sync-2.4.0 2025-12-01 18:08:31 +09:00
tequ
7e92374436 Merge remote-tracking branch 'upstream/dev' into sync-2.4.0 2025-12-01 13:06:58 +09:00
tequ
7ef8473c85 Merge remote-tracking branch 'upstream/dev' into sync-2.4.0 2025-12-01 12:53:49 +09:00
tequ
64fb39d033 Merge remote-tracking branch 'upstream/dev' into sync-2.4.0 2025-11-30 13:53:35 +09:00
tequ
859391327d Merge branch 'dev' into sync-2.4.0 2025-11-20 10:47:16 +09:00
tequ
9ec631b1d8 Merge remote-tracking branch 'upstream/dev' into sync-2.4.0 2025-11-06 14:46:53 +09:00
tequ
b9ed90e08b fix InvalidTxFlags Amendment to default Yes 2025-10-29 16:49:37 +09:00
tequ
066f8ed9ef Merge branch 'dev' into sync-2.4.0 2025-10-27 15:38:14 +09:00
tequ
3487e2de67 Merge branch 'dev' into sync-2.4.0 2025-10-17 13:21:01 +09:00
tequ
1da00892d3 Merge remote-tracking branch 'upstream/dev' into sync-2.4.0 2025-10-14 17:22:41 +09:00
tequ
75636ee5c4 Merge branch 'dev' into sync-2.4.0 2025-08-20 14:11:26 +09:00
tequ
d1528021e2 Add ltORACLE for Remarks target (#562) 2025-08-18 16:17:49 +09:00
tequ
d1395d0f41 Merge remote-tracking branch 'upstream/dev' into sync-2.4.0 2025-08-14 15:45:50 +09:00
tequ
b4f79257cb Conan Release Builder (2.4.0 sync) (#528) 2025-08-14 15:29:04 +09:00
tequ
43a4a3a3e2 Add Remit test to AMM Account 2025-07-19 19:18:03 +09:00
tequ
117bdb1c42 Optimize AccountDelete and Creadentials tests, Update tests priority 2025-07-19 04:49:25 +09:00
tequ
87e41a7888 Update Hook headers 2025-07-16 19:38:51 +09:00
tequ
df3bf8a958 VoteBehavior::DefaultYes for new fix Amendments
- NFToken related fix Amendments remains as `DefaultNo`.
2025-07-14 19:27:09 +09:00
tequ
c5fa112e16 Add TSH processing for AMM, AMMClawback, Clawback, Oracle (#532)
* Add TSH processing for `AMM`, `AMMClawback`, `Oracle`, `Clawback`

* Add empty TSH processing for other transaction types

* Add AMMTsh tests
2025-07-10 23:26:32 +09:00
tequ
d2e21da7a3 Merge branch 'dev' into sync-2.4.0 2025-07-09 13:38:41 +09:00
tequ
1f0bbdb288 Merge branch 'dev' into sync-2.4.0 2025-07-08 18:12:35 +09:00
tequ
5cc56d5f15 Support Hook execution in simulate RPC (#531) 2025-07-05 14:32:42 +09:00
tequ
0a9d3d3d75 Merge branch 'dev' into sync-2.4.0 2025-07-03 10:14:42 +09:00
tequ
0d192d48ce add tests for DeepFreeze 2025-07-01 19:35:35 +09:00
tequ
574dc20641 Supported::No for featurePermissionedDomains 2025-07-01 16:08:01 +09:00
tequ
3367f40ef5 Supported::No for featureDynamicNFT 2025-07-01 16:01:27 +09:00
tequ
7080d292e6 Supported::No for featureCredentials 2025-07-01 15:54:07 +09:00
tequ
85a1eb5dba Supported::No for featureMPTokensV1 2025-07-01 15:22:52 +09:00
tequ
534ed875a2 Supported::No for featureNFTokenMintOffer 2025-07-01 15:14:08 +09:00
tequ
72b85d75c9 Supported::No for featureDID 2025-07-01 15:09:00 +09:00
tequ
9229ed779f Supported::No for featureXChainBridge 2025-07-01 14:52:24 +09:00
tequ
e9f671043d Combine AMM Amendments (#521)
* fixAMMv1_2
* fixAMMv1_1
* fixAMMOverflowOffer
* fixLPTokenTransfer
* suppress AMM test logs
* exclude `ltAMM` from `fixPreviousTxnID` Amendment
    - make `sfPreviousTxnID` and `sfPreviousTxnLgrSeq` required for ltAMM
2025-07-01 13:51:32 +09:00
tequ
37669452f6 Combine XChainBridge Amendments (#523) 2025-06-30 19:12:33 +09:00
tequ
d4fd40c471 Combine fixInnerObjTemplate Amendments (#524) 2025-06-30 18:14:04 +09:00
tequ
51aae2ce36 fix to DefaultNo for featureDeletableAccounts 2025-06-30 17:15:46 +09:00
tequ
c4106a2752 Disable instrumentation-build workflow (#530) 2025-06-30 16:54:11 +09:00
tequ
e955909a40 Merge branch 'dev' into sync-2.4.0 2025-06-30 13:33:12 +09:00
Niq Dudfield
396587c160 fix: prevent SOCI from linking ALL boost libraries (#529)
SOCI's vendored conanfile was using boost::boost which links against
every single Boost library (40+ libraries) when only boost::headers
is needed for SOCI's template specializations (boost::optional and
boost::gregorian::date support).

This was causing excessive linking and potential symbol conflicts,
particularly on Linux CI where boost_stacktrace_from_exception was
causing multiple definition errors with libstdc++.

Changed SOCI's boost dependency from boost::boost to boost::headers
since SOCI only needs Boost headers for its template specializations,
not the compiled libraries. The project already provides all necessary
Boost libraries through the ripple_boost target.

This reduces the linked libraries from 40+ down to just the ~14 that
the project actually uses, fixing the Linux CI build failures and
reducing binary size.

Note: The SOCI Conan recipe for Conan 2.0 already implements this
fix correctly.
2025-06-30 13:16:10 +09:00
tequ
c065bc4938 Reduce numFeatures for DID Amendments combine 2025-06-28 21:36:25 +09:00
Niq Dudfield
2470926a1d fix: remove vestigial -DBOOST_ASIO_DISABLE_CONCEPTS usage (#526) 2025-06-27 16:41:30 +09:00
Denis Angell
c35890d5f8 fix cmake & xrpl_core 2025-06-25 10:30:30 +02:00
Denis Angell
248d485aed Update build-full.sh 2025-06-25 10:03:13 +02:00
Denis Angell
846965e77c fix cmake 2025-06-25 09:52:53 +02:00
Denis Angell
bf1f4e1a6f Update build-full.sh 2025-06-25 09:26:48 +02:00
Denis Angell
f8c4639ff4 add DeepFreeze to trustTransferAllowed 2025-06-25 09:15:05 +02:00
tequ
2451d78ae0 fix release-builder, workflow building 2025-06-24 21:27:20 +09:00
tequ
092f907724 remove checkpatterns workflow 2025-06-24 19:57:41 +09:00
tequ
33d4a989a2 Merge branch 'dev' into sync-2.4.0 2025-06-24 19:33:30 +09:00
tequ
348dab7491 Combine DID Amendments (#522)
fixEmptyDID -> featureDID
2025-06-23 21:13:52 +09:00
tequ
6728221831 Additional support for HookDefinition, HookState, ImportVLSequence at fixPreviousTxnID Amendment 2025-06-23 17:59:40 +09:00
Mark Travis
65f4945f22 Log detailed correlated consensus data together (#5302)
Combine multiple related debug log data points into a single
message. Allows quick correlation of events that
previously were either not logged or, if logged, strewn
across multiple lines, making correlation difficult.
The Heartbeat Timer and consensus ledger accept processing
each have this capability.

Also guarantees that log entries will be written if the
node is a validator, regardless of log severity level.
Otherwise, the level of these messages is at INFO severity.
2025-06-20 15:30:36 +09:00
Mark Travis
aff89c3457 fix: Acquire previously failed transaction set from network as new proposal arrives (#5318)
Reset the failure variable.
2025-06-20 15:12:58 +09:00
Bronek Kozicki
52e1766fb3 Fix Replace assert with XRPL_ASSERT (#5312) 2025-06-20 15:12:20 +09:00
Bronek Kozicki
3166ddc460 fix: Remove 'new parent hash' assert (#5313)
This assert is known to occasionally trigger, without causing errors
downstream. It is replaced with a log message.
2025-06-20 14:58:59 +09:00
Ed Hennis
db1591950d Add logging and improve counting of amendment votes from UNL (#5173)
* Add logging for amendment voting decision process
* When counting "received validations" to determine quorum, count the number of validators actually voting, not the total number of possible votes.
2025-06-20 14:58:48 +09:00
Bart
0d8c997867 docs: Revert peer port to 51235 (#5299)
Reverts the [port_peer] back to the legacy port 51235 rather than to the default port 2459, to avoid potentially inconveniencing existing operators.
2025-06-20 14:58:32 +09:00
Olek
41405706b0 fix: Switch Permissioned Domain to Supported::yes (#5287)
Switch Permissioned Domain feature's supported flag from Supported::no to Supported::yes for it to be votable.
2025-06-20 14:58:20 +09:00
Bart
d7480c6474 docs: Clarifies default port of hosts (#5290)
The current comment in the example cfg file incorrectly mentions both "may" and "must". This change fixes this comment to clarify that the default port of hosts is 2459 and that specifying it is therefore optional. It further sets the default port to 2459 instead of the legacy 51235.
2025-06-20 14:58:07 +09:00
Mark Travis
7b46e26d78 Log proposals and validations (#5291)
Adds detailed log messages for each validation and proposal received from the network.
2025-06-20 14:57:59 +09:00
Bart
5f5a73acbc Support canonical ledger entry names (#5271)
This change enhances the filtering in the ledger, ledger_data, and account_objects methods by also supporting filtering by the canonical name of the LedgerEntryType using case-insensitive matching.
2025-06-20 14:18:08 +09:00
Ed Hennis
c24f5b10b8 refactor: Change recursive_mutex to mutex in DatabaseRotatingImp (#5276)
Rewrites the code so that the lock is not held during the callback. Instead it locks twice, once before, and once after. This is safe due to the structure of the code, but is checked after the second lock. This allows mutex_ to be changed back to a regular mutex.
2025-06-20 14:17:06 +09:00
Bart
601bb7ed0f fix: Replace charge() by fee_.update() in OnMessage functions (#5269)
In PeerImpl.cpp, if the function is a message handler (onMessage) or called directly from a message handler, then it should use fee_, since when the handler returns (OnMessageEnd) then the charge function is called. If the function is not a message handler, such as a job queue item, it should remain charge.
2025-06-20 13:44:30 +09:00
Elliot Lee
0d3dd400f0 docs: ensure build_type and CMAKE_BUILD_TYPE match (#5274) 2025-06-20 13:43:59 +09:00
code0xff
4d763b7340 chore: Fix small typos in protocol files (#5279) 2025-06-20 13:43:42 +09:00
Ed Hennis
63665a6673 docs: Add a summary of the git commit message rules (#5283) 2025-06-20 13:43:03 +09:00
Olek
cbd7d5dc3a fix: Amendment to add transaction flag checking functionality for Credentials (#5250)
CredentialCreate / CredentialAccept / CredentialDelete transactions will check sfFlags field in preflight() when the amendment is enabled.
2025-06-20 13:42:18 +09:00
Donovan Hide
3e49ee604e fix: Omit superfluous setCurrentThreadName call in GRPCServer.cpp (#5280) 2025-06-20 11:21:55 +09:00
Bronek Kozicki
5e542f5215 fix: Do not allow creating Permissioned Domains if credentials are not enabled (#5275)
If the permissioned domains amendment XLS-80 is enabled before credentials XLS-70, then the permissioned domain users will not be able to match any credentials. The changes here prevent the creation of any permissioned domain objects if credentials are not enabled.
2025-06-20 11:21:45 +09:00
Mayukha Vadari
bdc404837c fix: issues in simulate RPC (#5265)
Make `simulate` RPC easier to use:
* Prevent the use of `seed`, `secret`, `seed_hex`, and `passphrase` fields (to avoid confusing with the signing methods).
* Add autofilling of the `NetworkID` field.
2025-06-20 11:21:33 +09:00
Bart
a62919a9cc Updates Conan dependencies (#5256)
This PR updates several Conan dependencies:
* boost
* date
* libarchive
* libmysqlclient
* libpq
* lz4
* onetbb
* openssl
* sqlite3
* zlib
* zstd
2025-06-20 11:21:21 +09:00
Shawn Xie
41dcc0fb23 Amendment fixFrozenLPTokenTransfer (#5227)
Prohibits LPToken holders from sending LPToken to others if they have been frozen by one of the assets in AMM pool.
2025-06-20 11:04:00 +09:00
Ed Hennis
b109dbf10f Improve git commit hash lookup (#5225)
- Also get the branch name.
- Use rev-parse instead of describe to get a clean hash.
- Return the git hash and branch name in server_info for admin
  connections.
- Include git hash and branch name on separate lines in --version.
2025-06-20 10:58:40 +09:00
Vlad
01372a67a8 Add deep freeze feature (XLS-77d) (#5187)
- spec: XRPLF/XRPL-Standards#220
- amendment: "DeepFreeze"
- implemented deep freeze spec to allow token issuers to prevent currency holders from being able to acquire more of these tokens.
- in combination with normal freeze, deep freeze effectively prevents any balance trust line balance change of a currency holder (except direct issuer <-> holder payments).
- added 2 new invariant checks to verify that deep freeze cannot be enacted without normal freeze and transfer is not frozen.
- made some fixes to existing freeze handling.

Co-authored-by: Ed Hennis <ed@ripple.com>
Co-authored-by: Howard Hinnant <howard.hinnant@gmail.com>
2025-06-20 10:52:31 +09:00
Mayukha Vadari
2b59176cfd Add RPC "simulate" to execute a dry run of a transaction (#5069)
- Spec: https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069d-simulate
- Also update signing methods to autofill fees better and properly handle transactions that require a non-standard fee.
2025-06-20 10:03:49 +09:00
Olek
a0505ce47d Fix CI unit tests (#5196)
- Add retries for rpc client
- Add dynamic port allocation for rpc servers
2025-06-20 02:28:17 +09:00
Michael Legleux
91aabaa4aa Update secp256k1 library to 0.6.0 (#5254) 2025-06-20 01:35:15 +09:00
Bronek Kozicki
a63008b1be Add [validator_list_threshold] to validators.txt to improve UNL security (#5112) 2025-06-20 01:34:38 +09:00
Bronek Kozicki
33b5ed931c Switch from assert to XRPL_ASSERT (#5245) 2025-06-20 01:29:51 +09:00
tequ
ce5c3c98c9 Add missing space character to a log message (#5251) 2025-06-20 01:29:43 +09:00
Bronek Kozicki
aeadad26cb Cleanup API-CHANGELOG.md (#5207) 2025-06-20 01:29:24 +09:00
Ed Hennis
74c50ebdab test: Unit tests to recreate invalid index logic error (#5242)
* One hits the global cache, one does not.
* Also some extra checking.

Co-authored-by: Bronek Kozicki <brok@incorrekt.com>
2025-06-20 01:29:02 +09:00
Sergey Kuznetsov
1e2c92290d fix: Error consistency in LedgerEntry::parsePermissionedDomains() (#5252)
Update errors for parsing permissioned domains in the LedgerEntry handler to make them consistent with other parsers.
2025-06-20 00:56:42 +09:00
Ed Hennis
0617dc221d fix: Use consistent CMake settings for all modules (#5228)
* Resolves an issue introduced in #5111, which inadvertently removed the
  -Wno-maybe-uninitialized compiler option from some xrpl.libxrpl
  modules. This resulted in new "may be used uninitialized" build
  warnings, first noticed in the "protocol" module. When compiling with
  derr=TRUE, those warnings became errors, which made the build fail.
* Github CI actions will build with the assert and werr options turned
  on. This will cause CI jobs to fail if a developer introduces a new
  compiler warning, or causes an assert to fail in release builds.
* Includes the OS and compiler version in the linux dependencies jobs in
  the "check environment" step.
* Translates the `unity` build option into `CMAKE_UNITY_BUILD` setting.
2025-06-20 00:56:18 +09:00
Valentin Balaschenko
a4a8295567 Fix levelization script to ignore commented includes (#5194)
Check to ignore single-line comments during dependency analysis.
2025-06-20 00:45:59 +09:00
tequ
2a836cbbb8 Fix the flag processing of NFTokenModify (#5246)
Adds checks for invalid flags.
2025-06-20 00:45:51 +09:00
Mayukha Vadari
79935d4db8 Fix failing assert in connect RPC (#5235) 2025-06-20 00:45:43 +09:00
Olek
7088c64427 Permissioned Domains (XLS-80d) (#5161) 2025-06-20 00:45:28 +09:00
tequ
27ddfae5e1 XLS-46: DynamicNFT (#5048)
This Amendment adds functionality to update the URI of NFToken objects as described in the XLS-46d: Dynamic Non Fungible Tokens (dNFTs) spec.
2025-06-20 00:27:50 +09:00
Shawn Xie
cf957db8da prefix Uint384 and Uint512 with Hash in server_definitions (#5231) 2025-06-20 00:10:23 +09:00
Mayukha Vadari
ac532d9d16 refactor: add rpcName to LEDGER_ENTRY macro (#5202)
The LEDGER_ENTRY macro now takes an additional parameter, which makes it easier to avoid missing including the new field in jss.h and to the list of account_objects/ledger_data filters.
2025-06-20 00:08:47 +09:00
Michael Legleux
37614773bb fix: Add header for set_difference (#5197)
Fix `error C2039: 'set_difference': is not a member of 'std'`
2025-06-19 23:42:21 +09:00
Mayukha Vadari
c329d71717 fix: allow overlapping types in Expected (#5218)
For example, Expected<std::uint32_t, Json::Value>, will now build even though there is animplicit conversion from unsigned int to Json::Value.
2025-06-19 23:42:12 +09:00
Gregory Tsipenyuk
7de6a70221 Add MPTIssue to STIssue (#5200)
Replace Issue in STIssue with Asset. STIssue with MPTIssue is only used in MPT tests.
Will be used in Vault and in transactions with STIssue fields once MPT is integrated into DEX.
2025-06-19 23:41:59 +09:00
Bronek Kozicki
0fa542f672 Antithesis instrumentation improvements (#5213)
* Rename ASSERT to XRPL_ASSERT
* Upgrade to Anthithesis SDK 0.4.4, and use new 0.4.4 features
  * automatic cast to bool, like assert
* Add instrumentation workflow to verify build with instrumentation enabled
2025-06-19 23:27:49 +09:00
John Freeman
68705eee2c Enforce levelization in libxrpl with CMake (#5111)
Adds two CMake functions:

* add_module(library subdirectory): Declares an OBJECT "library" (a CMake abstraction for a collection of object files) with sources from the given subdirectory of the given library, representing a module. Isolates the module's headers by creating a subdirectory in the build directory, e.g. .build/tmp123, that contains just a symlink, e.g. .build/tmp123/basics, to the module's header directory, e.g. include/xrpl/basics, in the source directory, and putting .build/tmp123 (but not include/xrpl) on the include path of the module sources. This prevents the module sources from including headers not explicitly linked to the module in CMake with target_link_libraries.
* target_link_modules(library scope modules...): Links the library target to each of the module targets, and removes their sources from its source list (so they are not compiled and linked twice).

Uses these functions to separate and explicitly link modules in libxrpl:

    Level 01: beast
    Level 02: basics
    Level 03: json, crypto
    Level 04: protocol
    Level 05: resource, server
2025-06-19 23:06:46 +09:00
Mayukha Vadari
fdbb24d898 refactor: clean up LedgerEntry.cpp (#5199)
Refactors LedgerEntry to make it easier to read and understand.
2025-06-19 21:49:47 +09:00
Ed Hennis
60a8f3c05b test: Add more test cases for Base58 parser (#5174)
---------
Co-authored-by: John Freeman <jfreeman08@gmail.com>
2025-06-19 19:57:12 +09:00
Ed Hennis
5a3a71ecb8 test: Check for some unlikely null dereferences in tests (#5004) 2025-06-19 19:57:04 +09:00
Bronek Kozicki
16b3221f80 Add Antithesis intrumentation (#5042)
* Copy Antithesis SDK version 0.4.0 to directory external/
* Add build option `voidstar` to enable instrumentation with Antithesis SDK
* Define instrumentation macros ASSERT and UNREACHABLE in terms of regular C assert
* Replace asserts with named ASSERT or UNREACHABLE
* Add UNREACHABLE to LogicError
* Document instrumentation macros in CONTRIBUTING.md
2025-06-19 19:56:21 +09:00
Valentin Balaschenko
dd4b060f09 Reduce the peer charges for well-behaved peers:
- Fix an erroneous high fee penalty that peers could incur for sending
  older transactions.
- Update to the fees charged for imposing a load on the server.
- Prevent the relaying of internal pseudo-transactions.
  - Before: Pseudo-transactions received from a peer will fail the signature
    check, even if they were requested (using TMGetObjectByHash), because
    they have no signature. This causes the peer to be charge for an
    invalid signature.
  - After: Pseudo-transactions, are put into the global cache
    (TransactionMaster) only. If the transaction is not part of
    a TMTransactions batch, the peer is charged an unwanted data fee.
    These fees will not be a problem in the normal course of operations,
    but should dissuade peers from behaving badly by sending a bunch of
    junk.
- Improve logging: include the reason for fees charged to a peer.

Co-authored-by: Ed Hennis <ed@ripple.com>
2025-06-19 17:05:23 +09:00
tequ
ee78f8d566 update actions/upload-artifact to v4
https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/
2025-06-19 16:11:34 +09:00
tequ
952ce55223 levelization 2025-06-19 16:05:02 +09:00
tequ
e6893a9422 clang-format, ignore magic_enum.h 2025-06-19 15:56:33 +09:00
tequ
0ba16ef3d6 fix ltDID type ID 2025-06-19 15:50:17 +09:00
tequ
479dd8b57b Update ServerDefinition 2025-06-19 15:05:42 +09:00
Elliot Lee
e626b096a3 refactor(AMMClawback): move tfClawTwoAssets check (#5201)
Move tfClawTwoAssets check to preflight and return
error temINVALID_FLAG

---------

Co-authored-by: yinyiqian1 <yqian@ripple.com>
2025-06-19 10:21:18 +09:00
Elliot Lee
329c0ab1e1 Add a new serialized type: STNumber (#5121)
`STNumber` lets objects and transactions contain multiple fields for
quantities of XRP, IOU, or MPT without duplicating information about the
"issue" (represented by `STIssue`). It is a straightforward serialization of
the `Number` type that uniformly represents those quantities.

---------

Co-authored-by: John Freeman <jfreeman08@gmail.com>
Co-authored-by: Howard Hinnant <howard.hinnant@gmail.com>
2025-06-19 10:21:07 +09:00
Olek
997836906c fix: check for valid ammID field in amm_info RPC (#5188) 2025-06-19 10:20:59 +09:00
Mayukha Vadari
71554dce3a fix: include index in server_definitions RPC (#5190) 2025-06-19 10:20:44 +09:00
Bronek Kozicki
2395d17a1f Fix ledger_entry crash on invalid credentials request (#5189) 2025-06-19 10:19:13 +09:00
Shawn Xie
e862f40636 Replace Uint192 with Hash192 in server_definitions response (#5177) 2025-06-19 10:17:50 +09:00
Bronek Kozicki
4f8096f378 Fix potential deadlock (#5124)
* 2.2.2 changed functions acquireAsync and NetworkOPsImp::recvValidation to add an item to a collection under lock, unlock, do some work, then lock again to do remove the item. It will deadlock if an exception is thrown while adding the item - before unlocking.
* Replace ScopedUnlock with scope_unlock.
2025-06-19 10:14:43 +09:00
Olek
d8a3e65d78 Introduce Credentials support (XLS-70d): (#5103)
Amendment:
    - Credentials

    New Transactions:
    - CredentialCreate
    - CredentialAccept
    - CredentialDelete

    Modified Transactions:
    - DepositPreauth
    - Payment
    - EscrowFinish
    - PaymentChannelClaim
    - AccountDelete

    New Object:
    - Credential

    Modified Object:
    - DepositPreauth

    API updates:
    - ledger_entry
    - account_objects
    - ledger_data
    - deposit_authorized

    Read full spec: https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0070d-credentials
2025-06-19 10:14:24 +09:00
Gregory Tsipenyuk
c3cc6494dd Fix token comparison in Payment (#5172)
* Checks only Currency or MPT Issuance ID part of the Asset object.
* Resolves temREDUNDANT regression detected in testing.
2025-06-19 00:21:21 +09:00
Gregory Tsipenyuk
76397fea5c Add fixAMMv1_2 amendment (#5176)
* Add reserve check on AMM Withdraw
* Try AMM max offer if changeSpotPriceQuality() fails
2025-06-19 00:21:00 +09:00
Gregory Tsipenyuk
291fb21d45 Fix unity build (#5179) 2025-06-19 00:00:06 +09:00
yinyiqian1
727fc8e084 Add AMMClawback Transaction (XLS-0073d) (#5142)
Amendment:
- AMMClawback

New Transactions:
- AMMClawback

Modified Transactions:
- AMMCreate
- AMMDeposit
2025-06-18 23:59:44 +09:00
Valentin Balaschenko
acc95ecc56 docs: Add protobuf dependencies to linux setup instructions (#5156) 2025-06-18 23:48:28 +09:00
yinyiqian1
f7592641d1 fix: reject invalid markers in account_objects RPC calls (#5046) 2025-06-18 23:48:09 +09:00
Bob Conan
1338b67964 Update RELEASENOTES.md (#5154)
fix the typo "concensus" -> "consensus"
2025-06-18 23:41:27 +09:00
Gregory Tsipenyuk
9ee638fe7f Introduce MPT support (XLS-33d): (#5143)
Amendment:
- MPTokensV1

New Transactions:
- MPTokenIssuanceCreate
- MPTokenIssuanceDestroy
- MPTokenIssuanceSet
- MPTokenAuthorize

Modified Transactions:
- Payment
- Clawback

New Objects:
- MPTokenIssuance
- MPToken

API updates:
- ledger_entry
- account_objects
- ledger_data

Other:
- Add += and -= operators to ValueProxy

Read full spec: https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0033d-multi-purpose-tokens

---------
Co-authored-by: Shawn Xie <shawnxie920@gmail.com>
Co-authored-by: Howard Hinnant <howard.hinnant@gmail.com>
Co-authored-by: Ed Hennis <ed@ripple.com>
Co-authored-by: John Freeman <jfreeman08@gmail.com>
2025-06-18 23:38:51 +09:00
John Freeman
9c1ed41879 Consolidate definitions of fields, objects, transactions, and features (#5122) 2025-06-18 16:26:50 +09:00
John Freeman
ab1c217e8d Reformat code with clang-format-18 2025-06-18 14:13:10 +09:00
John Freeman
e140a0fd0b Update pre-commit hook 2025-06-18 13:30:15 +09:00
John Freeman
7f3281ff54 Update clang-format settings 2025-06-18 13:30:01 +09:00
John Freeman
17d0e23720 Update clang-format workflow 2025-06-18 13:29:29 +09:00
Chenna Keshava B S
5675408c51 Expand Error Message for rpcInternal (#4959)
Validator operators have been confused by the rpcInternal error, which can occur if the server is not running in another process.
2025-06-18 13:27:24 +09:00
Elliot Lee
48bb555f92 docs: clean up API-CHANGELOG.md (#5064)
Move the newest information to the top, i.e., use reverse chronological order within each of the two sections ("API Versions" and "XRP Ledger server versions")
2025-06-18 13:27:14 +09:00
Denis Angell
2227a382d6 feat(SQLite): allow configurable database pragma values (#5135)
Make page_size and journal_size_limit configurable values in rippled.cfg
2025-06-18 13:27:04 +09:00
Vlad
088c1deaf5 refactor: re-order PRAGMA statements (#5140)
The page_size will soon be made configurable with #5135, making this
re-ordering necessary.

When opening SQLite connection, there are specific pragmas set with
commonPragmas.

In particular, PRAGMA journal_mode creates journal file and locks the
page_size; as of this commit, this sets the page size to the default
value of 4096. Coincidentally, the hardcoded page_size was also 4096, so
no issue was noticed.
2025-06-18 13:26:55 +09:00
Chenna Keshava B S
632f94a8e7 fix(book_changes): add "validated" field and reduce RPC latency (#5096)
Update book_changes RPC to reduce latency, add "validated" field, and accept shortcut strings (current, closed, validated) for ledger_index.

`"validated": true` indicates that the transaction has been included in a validated ledger so the result of the transaction is immutable.

Fix #5033

Fix #5034

Fix #5035

Fix #5036

---------

Co-authored-by: Bronek Kozicki <brok@incorrekt.com>
2025-06-18 13:26:45 +09:00
luozexuan
6bf4adf42f chore: fix typos in comments (#5094)
Signed-off-by: luozexuan <fetchcode@139.com>
2025-06-18 13:26:37 +09:00
Ed Hennis
db9af3a8c9 test: Retry RPC commands to try to fix MacOS CI jobs (#5120)
* Retry some failed RPC connections / commands in unit tests
* Remove orphaned `getAccounts` function

Co-authored-by: John Freeman <jfreeman08@gmail.com>
2025-06-18 13:26:21 +09:00
John Freeman
ef7e743a0e docs: Update options documentation (#5083)
Co-authored-by: Elliot Lee <github.public@intelliot.com>
2025-06-18 13:25:11 +09:00
John Freeman
c97f32cbcc refactor: Remove dead headers (#5081) 2025-06-18 13:24:50 +09:00
John Freeman
187634272d refactor: Remove reporting mode (#5092) 2025-06-18 13:24:40 +09:00
Scott Schurr
be49b22c2f Address rare corruption of NFTokenPage linked list (#4945)
* Add fixNFTokenPageLinks amendment:

It was discovered that under rare circumstances the links between
NFTokenPages could be removed.  If this happens, then the
account_objects and account_nfts RPC commands under-report the
NFTokens owned by an account.

The fixNFTokenPageLinks amendment does the following to address
the problem:

- It fixes the underlying problem so no further broken links
  should be created.
- It adds Invariants so, if such damage were introduced in the
  future, an invariant would stop it.
- It adds a new FixLedgerState transaction that repairs
  directories that were damaged in this fashion.
- It adds unit tests for all of it.
2025-06-18 12:32:59 +09:00
Bronek Kozicki
fd1908f5b6 Factor out Transactor::trapTransaction (#5087) 2025-06-18 12:22:04 +09:00
John Freeman
d27bc94249 Remove shards (#5066) 2025-06-18 12:17:28 +09:00
Bronek Kozicki
16b4550d93 Update gcovr EXCLUDE (#5084) 2025-06-17 23:58:07 +09:00
Bronek Kozicki
b51411f728 Fix crash inside OverlayImpl loops over ids_ (#5071) 2025-06-17 23:57:58 +09:00
Ed Hennis
6a17c6be3f docs: Document the process for merging pull requests (#5010) 2025-06-17 23:57:41 +09:00
Scott Schurr
881c5c8b96 Remove unused constants from resource/Fees.h (#4856) 2025-06-17 23:57:02 +09:00
Mayukha Vadari
eaf63accbe fix: change error for invalid feature param in feature RPC (#5063)
* Returns an "Invalid parameters" error if the `feature` parameter is provided and is not a string.
2025-06-17 23:56:54 +09:00
Ed Hennis
a26bcf1328 Ensure levelization sorting is ASCII-order across platforms (#5072) 2025-06-17 23:56:45 +09:00
Ed Hennis
b5e309347a fix: Fix NuDB build error via Conan patch (#5061)
* Includes updated instructions in BUILD.md.
2025-06-17 23:56:34 +09:00
yinyiqian1
f04b4e066f Disallow filtering account_objects by unsupported types (#5056)
* `account_objects` returns an invalid field error if `type` is not supported.
  This includes objects an account can't own, or which are unsupported by `account_objects`
* Includes:
  * Amendments
  * Directory Node
  * Fee Settings
  * Ledger Hashes
  * Negative UNL
2025-06-17 23:56:15 +09:00
Scott Schurr
b0c8296dc0 chore: Add comments to SignerEntries.h (#5059) 2025-06-17 23:49:42 +09:00
Scott Schurr
d8d55c2397 chore: Rename two files from Directory* to Dir*: (#5058)
The names of the files should reflect the name of the Dir class.

Co-authored-by: Zack Brunson <Zshooter@gmail.com>
Co-authored-by: Ed Hennis <ed@ripple.com>
2025-06-17 23:46:50 +09:00
Denis Angell
d62a3ec724 Update BUILD.md after PR #5052 (#5067)
* Document the need to specify "xrpld" and "tests" to build and test rippled.
2025-06-17 22:55:08 +09:00
John Freeman
f1687f0e1b Add xrpld build option and Conan package test (#5052)
* Make xrpld target optional

* Add job to test Conan recipe

* [fold] address review comments

* [fold] Enable tests in workflows

* [fold] Rename with_xrpld option

* [fold] Fix grep expression
2025-06-17 22:54:49 +09:00
dashangcun
a5787f78a5 chore: remove repeat words (#5053)
Signed-off-by: dashangcun <jchaodaohang@foxmail.com>
Co-authored-by: dashangcun <jchaodaohang@foxmail.com>
Co-authored-by: Zack Brunson <Zshooter@gmail.com>
2025-06-17 22:42:57 +09:00
yinyiqian1
62c17828d7 fix CTID in tx command returns invalidParams on lowercase hex (#5049)
* fix CTID in tx command returns invalidParams on lowercase hex

* test mixed case and change auto to explicit type

* add header cctype because std::tolower is called

* remove unused local variable

* change test case comment from 'lowercase' to 'mixed case'

---------

Co-authored-by: Zack Brunson <Zshooter@gmail.com>
2025-06-17 22:42:43 +09:00
Ed Hennis
1dee7d6c4d Invariant: prevent a deleted account from leaving (most) artifacts on the ledger. (#4663)
* Add feature / amendment "InvariantsV1_1"

* Adds invariant AccountRootsDeletedClean:

* Checks that a deleted account doesn't leave any directly
  accessible artifacts behind.
* Always tests, but only changes the transaction result if
  featureInvariantsV1_1 is enabled.
* Unit tests.

* Resolves #4638

* [FOLD] Review feedback from @gregtatcam:

* Fix unused variable warning
* Improve Invariant test const correctness

* [FOLD] Review feedback from @mvadari:

* Centralize the account keylet function list, and some optimization

* [FOLD] Some structured binding doesn't work in clang

* [FOLD] Review feedback 2 from @mvadari:

* Clean up and clarify some comments.

* [FOLD] Change InvariantsV1_1 to unsupported

* Will allow multiple PRs to be merged over time using the same amendment.

* fixup! [FOLD] Change InvariantsV1_1 to unsupported

* [FOLD] Update and clarify some comments. No code changes.

* Move CMake directory

* Rearrange sources

* Rewrite includes

* Recompute loops

* Fix merge issue and formatting

---------

Co-authored-by: Pretty Printer <cpp@ripple.com>
2025-06-17 22:42:28 +09:00
yinyiqian1
3e95f07a25 fix "account_nfts" with unassociated marker returning issue (#5045)
* fix "account_nfts" with unassociated marker returning issue

* create unit test for fixing nft page invalid marker not returning error

add more test

change test name

create unit test

* fix "account_nfts" with unassociated marker returning issue

* fix "account_nfts" with unassociated marker returning issue

* fix "account_nfts" with unassociated marker returning issue

* fix "account_nfts" with unassociated marker returning issue

* fix "account_nfts" with unassociated marker returning issue

* fix "account_nfts" with unassociated marker returning issue

* fix "account_nfts" with unassociated marker returning issue

* fix "account_nfts" with unassociated marker returning issue

* [FOLD] accumulated review suggestions

* move BEAST check out of lambda function

---------

Authored-by: Scott Schurr <scott@ripple.com>
2025-06-17 22:38:25 +09:00
Scott Schurr
463dd92c9e fixInnerObjTemplate2 amendment (#5047)
* fixInnerObjTemplate2 amendment:

Apply inner object templates to all remaining (non-AMM)
inner objects.

Adds a unit test for applying the template to sfMajorities.
Other remaining inner objects showed no problems having
templates applied.

* Move CMake directory

* Rearrange sources

* Rewrite includes

* Recompute loops

---------

Co-authored-by: Pretty Printer <cpp@ripple.com>
2025-06-17 22:33:07 +09:00
tequ
95e16b0eed fix for current codebase 2025-06-17 21:45:05 +09:00
Pretty Printer
cb641e4733 Recompute loops 2025-06-17 20:32:54 +09:00
Pretty Printer
3cb60afde6 Rewrite includes 2025-06-17 20:32:41 +09:00
Pretty Printer
a6a71bcc3f Rearrange sources 2025-06-17 10:42:41 +00:00
Pretty Printer
6c1bc9052d Rearrange sources 2025-06-17 19:16:40 +09:00
Pretty Printer
6b5a7ec905 Move CMake directory 2025-06-17 18:22:13 +09:00
John Freeman
7e639a1a9d Add bin/physical.sh (#4997) 2025-06-17 17:44:53 +09:00
John Freeman
cd0141d781 Prepare to rearrange sources: (#4997)
- Remove CMake module "MultiConfig".
- Update clang-format configuration, CodeCov configuration,
  levelization script.
- Replace source lists in CMake with globs.
2025-06-17 17:44:40 +09:00
Bronek Kozicki
34be0ce4fe Change order of checks in amm_info: (#4924)
* Change order of checks in amm_info

* Change amm_info error message in API version 3

* Change amm_info error tests
2025-06-17 13:31:33 +09:00
Scott Schurr
01971ab1b9 Add the fixEnforceNFTokenTrustline amendment: (#4946)
Fix interactions between NFTokenOffers and trust lines.

Since the NFTokenAcceptOffer does not check the trust line that
the issuer receives as a transfer fee in the NFTokenAcceptOffer,
if the issuer deletes the trust line after NFTokenCreateOffer,
the trust line is created for the issuer by the
NFTokenAcceptOffer.  That's fixed.

Resolves #4925.
2025-06-17 13:31:15 +09:00
Chenna Keshava B S
7996d08d0c Replaces the usage of boost::string_view with std::string_view (#4509) 2025-06-17 13:27:08 +09:00
Elliot Lee
11ff672df8 docs: explain how to find a clang-format patch generated by CI (#4521) 2025-06-17 13:20:21 +09:00
tequ
00fc12faa9 XLS-52d: NFTokenMintOffer (#4845) 2025-06-17 13:20:05 +09:00
todaymoon
f97bf81b16 chore: remove repeat words (#5041) 2025-06-17 12:54:28 +09:00
Alex Kremer
29abe2ae46 Expose all amendments known by libxrpl (#5026) 2025-06-17 12:54:18 +09:00
Scott Schurr
bb271020df fixReducedOffersV2: prevent offers from blocking order books: (#5032)
Fixes issue #4937.

The fixReducedOffersV1 amendment fixed certain forms of offer
modification that could lead to blocked order books.  Reduced
offers can block order books if the effective quality of the
reduced offer is worse than the quality of the original offer
(from the perspective of the taker). It turns out that, for
small values, the quality of the reduced offer can be
significantly affected by the rounding mode used during
scaling computations.

Issue #4937 identified an additional code path that modified
offers in a way that could lead to blocked order books.  This
commit changes the rounding in that newly located code path so
the quality of the modified offer is never worse than the
quality of the offer as it was originally placed.

It is possible that additional ways of producing blocking
offers will come to light.  Therefore there may be a future
need for a V3 amendment.
2025-06-17 12:54:03 +09:00
Chenna Keshava B S
a5fb634d53 Additional unit tests for testing deletion of trust lines (#4886) 2025-06-17 12:48:31 +09:00
Olek
8896ea7220 Fix conan typo: (#5044)
Add missed coma in 'exportes_sources'
2025-06-17 12:48:06 +09:00
Bronek Kozicki
837dd8c4b9 Add new command line option to make replaying transactions easier: (#5027)
* Add trap_tx_hash command line option

This new option can be used only if replay is also enabled. It takes a transaction hash from the ledger loaded for replay, and will cause a specific line to be hit in Transactor.cpp, right before the selected transaction is applied.
2025-06-17 12:47:45 +09:00
John Freeman
323fba5c17 Fix compatibility with Conan 2.x: (#5001)
Closes #4926, #4990
2025-06-17 12:42:56 +09:00
J. Scott Branson
723a51921d Update SQLite3 max_page_count to match current defaults (#5114)
When rippled initiates a connection to SQLite3, rippled sends a "PRAGMA"
statement defining the maximum number of pages allowed in the database.
Update the max_page_count so it is consistent with the default for newer
versions of SQLite3. Increasing max_page_count is critical for keeping
full history servers online.

Fix #5102
2025-06-17 12:32:25 +09:00
Valentin Balaschenko
8b83693235 Track latencies of certain code blocks, and log if they take too long 2025-06-17 12:32:25 +09:00
John Freeman
beaf794938 Use error codes throughout fast Base58 implementation 2025-06-17 12:32:25 +09:00
Mayukha Vadari
21a383eeaf Improve error handling in some RPC commands 2025-06-17 12:32:24 +09:00
Alex Kremer
06394e9d17 Add xrpl.libpp as an exported lib in conan (#5022) 2025-06-17 12:32:24 +09:00
Gregory Tsipenyuk
ea2e503ef8 Fix Oracle's token pair deterministic order: (#5021)
Price Oracle data-series logic uses `unordered_map` to update the Oracle object.
This results in different servers disagreeing on the order of that hash table.
Consequently, the generated ledgers will have different hashes.
The fix uses `map` instead to guarantee the order of the token pairs
in the data-series.
2025-06-17 12:32:23 +09:00
Gregory Tsipenyuk
447e6c6c1e Fix last Liquidity Provider withdrawal:
Due to the rounding, LPTokenBalance of the last
Liquidity Provider (LP), might not match this LP's
trustline balance. This fix sets LPTokenBalance on
last LP withdrawal to this LP's LPToken trustline
balance.
2025-06-17 12:32:23 +09:00
Gregory Tsipenyuk
e5e4925a39 Fix offer crossing via single path AMM with transfer fee:
Single path AMM offer has to factor in the transfer in rate
when calculating the upper bound quality and the quality function
because single path AMM's offer quality is not constant.
This fix factors in the transfer fee in
BookStep::adjustQualityWithFees().
2025-06-17 12:32:22 +09:00
Gregory Tsipenyuk
3ff7f34d7c Fix adjustAmountsByLPTokens():
The fix is to return the actual adjusted lp tokens and amounts
by the function.
2025-06-17 12:32:22 +09:00
Gregory Tsipenyuk
e1f2e62c08 Add the fixAMMOfferRounding amendment: (#4983)
* Fix AMM offer rounding and low quality LOB offer blocking AMM:

A single-path AMM offer with account offer on DEX, is always generated
starting with the takerPays first, which is rounded up, and then
the takerGets, which is rounded down. This rounding ensures that the pool's
product invariant is maintained. However, when one of the offer's side
is XRP, this rounding can result in the AMM offer having a lower
quality, potentially causing offer generation to fail if the quality
is lower than the account's offer quality.

To address this issue, the proposed fix adjusts the offer generation process
to start with the XRP side first and always rounds it down. This results
in a smaller offer size, improving the offer's quality. Regardless if the offer
has XRP or not, the rounding is done so that the offer size is minimized.
This change still ensures the product invariant, as the other generated
side is the exact result of the swap-in or swap-out equations.

If a liquidity can be provided by both AMM and LOB offer on offer crossing
then AMM offer is generated so that it matches LOB offer quality. If LOB
offer quality is less than limit quality then generated AMM offer quality
is also less than limit quality and the offer doesn't cross. To address
this issue, if LOB quality is better than limit quality then use LOB
quality to generate AMM offer. Otherwise, don't use the quality to generate
AMM offer. In this case, limitOut() function in StrandFlow limits
the out amount to match strand's quality to limit quality and consume
maximum AMM liquidity.
2025-06-17 12:32:21 +09:00
Gregory Tsipenyuk
10dcdd87d4 Price Oracle: validate input parameters and extend test coverage: (#5013)
* Price Oracle: validate input parameters and extend test coverage:

Validate trim, time_threshold, document_id are valid
Int, UInt, or string convertible to UInt. Validate base_asset
and quote_asset are valid currency. Update error codes.
Extend Oracle and GetAggregatePrice unit-tests.
Denote unreachable coverage code.

* Set one-line LCOV_EXCL_LINE

* Move ledger_entry tests to LedgerRPC_test.cpp

* Add constants for "None"

* Fix LedgerRPC test

---------

Co-authored-by: Scott Determan <scott.determan@yahoo.com>
2025-06-17 12:32:21 +09:00
Michael Legleux
6419eaae42 Add external directory to Conan recipe's exports (#5006) 2025-06-17 12:32:20 +09:00
John Freeman
1f28001aae Add missing includes (#5011) 2025-06-17 12:32:20 +09:00
seelabs
9d0b94029a Remove flow assert: (#5009)
Rounding in the payment engine is causing an assert to sometimes fire
with "dust" amounts. This is causing issues when running debug builds of
rippled. This issue will be addressed, but the assert is no longer
serving its purpose.
2025-06-17 12:32:20 +09:00
seelabs
c3d51f85af fix amendment: AMM swap should honor invariants: (#5002)
The AMM has an invariant for swaps where:
new_balance_1*new_balance_2 >= old_balance_1*old_balance_2

Due to rounding, this invariant could sometimes be violated (although by
very small amounts).

This patch introduces an amendment `fixAMMRounding` that changes the
rounding to always favor the AMM. Doing this should maintain the
invariant.

Co-authored-by: Bronek Kozicki
Co-authored-by: thejohnfreeman
2025-06-17 12:32:19 +09:00
seelabs
f15412acb5 Add global access to the current ledger rules:
It can be difficult to make transaction breaking changes to low level
code because the low level code does not have access to a ledger and the
current activated amendments in that ledger (the "rules"). This patch
adds global access to the current ledger rules as a `std::optional`. If
the optional is not seated, then there is no active transaction.
2025-06-17 12:32:19 +09:00
Snoppy
eea44ad6cb chore: fix typos (#4958) 2025-06-17 12:32:18 +09:00
Ed Hennis
2380633d9a test: Add RPC error checking support to unit tests (#4987) 2025-06-17 12:32:18 +09:00
John Freeman
4400a6eef6 Ignore more commits 2025-06-17 12:32:17 +09:00
John Freeman
17c9e967fd Address compiler warnings 2025-06-17 12:32:17 +09:00
John Freeman
3b96cac31c Add markers around source lists 2025-06-17 12:32:16 +09:00
John Freeman
fda0b67d9d Fix source lists 2025-06-17 12:32:16 +09:00
Pretty Printer
58a24ac1a2 Rewrite includes
$ find src/ripple/ src/test/ -type f -exec sed -i 's:include\s*["<]ripple/\(.*\)\.h\(pp\)\?[">]:include <ripple/\1.h>:' {} +
2025-06-17 12:32:16 +09:00
Pretty Printer
0213db8a08 Format formerly .hpp files 2025-06-17 12:32:15 +09:00
Pretty Printer
fcd0e23326 Rename .hpp to .h 2025-06-17 12:32:15 +09:00
John Freeman
2827748bcf Simplify protobuf generation 2025-06-17 12:32:14 +09:00
Pretty Printer
4319b1a097 Consolidate external libraries 2025-06-17 12:32:14 +09:00
John Freeman
6af0cb9bb4 Remove unused files 2025-06-17 12:32:13 +09:00
Ed Hennis
2abb48a618 fix: Remove redundant STAmount conversion in test (#4996) 2025-06-17 12:32:13 +09:00
Scott Determan
8eead5c99c fix: resolve database deadlock: (#4989)
The `rotateWithLock` function holds a lock while it calls a callback
function that's passed in by the caller. This is a problematic design
that needs to be used very carefully. In this case, at least one caller
passed in a callback that eventually relocks the mutex on the same
thread, causing UB (a deadlock was observed). The caller was from
SHAMapStoreImpl, and it called `clearCaches`. This `clearCaches` can
potentially call `fetchNodeObject`, which tried to relock the mutex.

This patch resolves the issue by changing the mutex type to a
`recursive_mutex`. Ideally, the code should be rewritten so it doesn't
hold the mutex during the callback and the mutex should be changed back
to a regular mutex.

Co-authored-by: Ed Hennis <ed@ripple.com>
2025-06-17 12:32:12 +09:00
Michael Legleux
3055029ded fix Conan component reference typo 2025-06-17 12:32:12 +09:00
Bronek Kozicki
ec23db00e7 Remove unused lambdas from MultiApiJson_test 2025-06-17 12:32:12 +09:00
Chenna Keshava B S
39b84e073b test: verify the rounding behavior of equal-asset AMM deposits (#4982)
* Specifically, test using tfLPToken flag
2025-06-17 12:32:11 +09:00
John Freeman
a9afc6c690 test: Add tests to raise coverage of AMM (#4971)
---------

Co-authored-by: Howard Hinnant <howard.hinnant@gmail.com>
Co-authored-by: Mark Travis <mtravis@ripple.com>
Co-authored-by: Bronek Kozicki <brok@incorrekt.com>
Co-authored-by: Mayukha Vadari <mvadari@gmail.com>
Co-authored-by: Chenna Keshava <ckeshavabs@gmail.com>
2025-06-17 12:32:11 +09:00
John Freeman
f9d544caef test: Add tests to raise coverage of AMM (#4971)
---------

Co-authored-by: Howard Hinnant <howard.hinnant@gmail.com>
Co-authored-by: Mark Travis <mtravis@ripple.com>
Co-authored-by: Bronek Kozicki <brok@incorrekt.com>
Co-authored-by: Mayukha Vadari <mvadari@gmail.com>
Co-authored-by: Chenna Keshava <ckeshavabs@gmail.com>
2025-06-17 12:32:10 +09:00
Bronek Kozicki
6cf6b42c57 test: Unit test for AMM offer overflow (#4986) 2025-06-17 12:32:10 +09:00
Mayukha Vadari
534e9989a8 fix amendment to add PreviousTxnID/PreviousTxnLgrSequence (#4751)
This amendment, `fixPreviousTxnID`, adds `PreviousTxnID` and
`PreviousTxnLgrSequence` as fields to all ledger objects that did
not already have them included (`DirectoryNode`, `Amendments`,
`FeeSettings`, `NegativeUNL`, and `AMM`). This makes it much easier
to go through the history of these ledger objects.
2025-06-17 12:32:09 +09:00
Ed Hennis
7fc312b271 chore: Default validator-keys-tool to master branch: (#4943)
* master is the default branch for that project. There's no point in
  using develop.
2025-06-17 12:32:09 +09:00
Scott Determan
8cfea5a9d1 fixXChainRewardRounding: round reward shares down: (#4933)
When calculating reward shares, the amount should always be rounded
down. If the `fixUniversalNumber` amendment is not active, this works
correctly. If it is not active, then the amount is incorrectly rounded
up. This patch introduces an amendment so it will be rounded down.
2025-06-17 12:32:08 +09:00
Mark Travis
c1cb2765ee Don't reach consensus as quickly if no other proposals seen: (#4763)
This fixes a case where a peer can desync under a certain timing
circumstance--if it reaches a certain point in consensus before it receives
proposals. 

This was noticed under high transaction volumes. Namely, when we arrive at the
point of deciding whether consensus is reached after minimum establish phase
duration but before having received any proposals. This could be caused by
finishing the previous round slightly faster and/or having some delay in
receiving proposals. Existing behavior arrives at consensus immediately after
the minimum establish duration with no proposals. This causes us to desync
because we then close a non-validated ledger. The change in this PR causes us to
wait for a configured threshold before making the decision to arrive at
consensus with no proposals. This allows validators to catch up and for brief
delays in receiving proposals to be absorbed. There should be no drawback since,
with no proposals coming in, we needn't be in a huge rush to jump ahead.
2025-06-17 12:32:08 +09:00
Bronek Kozicki
fc305f974b Write improved forAllApiVersions used in NetworkOPs (#4833) 2025-06-17 12:32:08 +09:00
Bronek Kozicki
04f36c8d63 Enforce no duplicate slots from incoming connections: (#4944)
We do not currently enforce that incoming peer connection does not have
remote_endpoint which is already used (either by incoming or outgoing
connection), hence already stored in slots_. If we happen to receive a
connection from such a duplicate remote_endpoint, it will eventually result in a
crash (when disconnecting) or weird behavior (when updating slot state), as a
result of an apparently matching remote_endpoint in slots_ being used by a
different connection.
2025-06-17 12:32:07 +09:00
Mayukha Vadari
70a3be5ebe fixEmptyDID: fix amendment to handle empty DID edge case: (#4950)
This amendment fixes an edge case where an empty DID object can be
created. It adds an additional check to ensure that DIDs are
non-empty when created, and returns a `tecEMPTY_DID` error if the DID
would be empty.
2025-06-17 12:32:07 +09:00
Ed Hennis
842f8b0ede test: Env unit test RPC errors return a unique result: (#4877)
* telENV_RPC_FAILED is a new code, reserved exclusively
  for unit tests when RPC fails. This will
  make those types of errors distinct and easier to test
  for when expected and/or diagnose when not.
* Output RPC command result when result is not expected.
2025-06-17 12:32:06 +09:00
Bronek Kozicki
87368f7f0e Upgrade to xxhash 0.8.2 as a Conan requirement, enable SIMD hashing (#4893)
We are currently using old version 0.6.2 of `xxhash`, as a verbatim copy and paste of its header file `xxhash.h`. Switch to the more recent version 0.8.2. Since this version is in Conan Center (and properly protects its ABI by keeping the state object incomplete), add it as a Conan requirement. Switch to the SIMD instructions (in the new `XXH3` family) supported by the new version.
2025-06-17 12:32:06 +09:00
Michael Legleux
69e3cdce53 Install more public headers (#4940)
Fixes some mistakes in #4885
2025-06-17 12:32:05 +09:00
Scott Determan
37cc0709c7 fix: order book update variable swap: (#4890)
This is likely the result of a typo when the code was simplified.
2025-06-17 12:32:05 +09:00
John Freeman
7e64d49bd0 Embed patched recipe for RocksDB 6.29.5 (#4947) 2025-06-17 12:32:04 +09:00
Gregory Tsipenyuk
bb463bc62f build: add STCurrency.h to xrpl_core to fix clio build (#4939) 2025-06-17 12:32:04 +09:00
Mayukha Vadari
a0accf3d6a feat: add user version of feature RPC (#4781)
* uses same formatting as admin RPC
* hides potentially sensitive data
2025-06-17 12:32:04 +09:00
Scott Determan
9a1888cc2d Fast base58 codec: (#4327)
This algorithm is about an order of magnitude faster than the existing
algorithm (about 10x faster for encoding and about 15x faster for
decoding - including the double hash for the checksum). The algorithms
use gcc's int128 (fast MS version will have to wait, in the meantime MS
falls back to the slow code).
2025-06-17 12:32:03 +09:00
Chenna Keshava B S
a342b510e7 Remove default ctors from SecretKey and PublicKey: (#4607)
* It is now an invariant that all constructed Public Keys are valid,
  non-empty and contain 33 bytes of data.
* Additionally, the memory footprint of the PublicKey class is reduced.
  The size_ data member is declared as static.
* Distinguish and identify the PublisherList retrieved from the local
  config file, versus the ones obtained from other validators.
* Fixes #2942
2025-06-17 12:32:03 +09:00
Gregory Tsipenyuk
b588f1a06e fix compile error on gcc 13: (#4932)
The compilation fails due to an issue in the initializer list
of an optional argument, which holds a vector of pairs.
The code compiles correctly on earlier gcc versions, but fails on gcc 13.
2025-06-17 12:32:02 +09:00
Gregory Tsipenyuk
833a75f57a Price Oracle (XLS-47d): (#4789) (#4789)
Implement native support for Price Oracles.

 A Price Oracle is used to bring real-world data, such as market prices,
 onto the blockchain, enabling dApps to access and utilize information
 that resides outside the blockchain.

 Add Price Oracle functionality:
 - OracleSet: create or update the Oracle object
 - OracleDelete: delete the Oracle object

 To support this functionality add:
 - New RPC method, `get_aggregate_price`, to calculate aggregate price for a token pair of the specified oracles
 - `ltOracle` object

 The `ltOracle` object maintains:
 - Oracle Owner's account
 - Oracle's metadata
 - Up to ten token pairs with the scaled price
 - The last update time the token pairs were updated

 Add Oracle unit-tests
2025-06-17 12:32:02 +09:00
Mayukha Vadari
20812b4a2c feat(rpc): add server_definitions method (#4703)
Add a new RPC / WS call for `server_definitions`, which returns an
SDK-compatible `definitions.json` (binary enum definitions) generated by
the server. This enables clients/libraries to dynamically work with new
fields and features, such as ones that may become available on side
chains. Clients query `server_definitions` on a node from the network
they want to work with, and immediately know how to speak that node's
binary "language", even if new features are added to it in the future
(as long as there are no new serialized types that the software doesn't
know how to serialize/deserialize).

Example:

```js
> {"command": "server_definitions"}
< {
    "result": {
        "FIELDS": [
            [
                "Generic",
                {
                    "isSerialized": false,
                    "isSigningField": false,
                    "isVLEncoded": false,
                    "nth": 0,
                    "type": "Unknown"
                }
            ],
            [
                "Invalid",
                {
                    "isSerialized": false,
                    "isSigningField": false,
                    "isVLEncoded": false,
                    "nth": -1,
                    "type": "Unknown"
                }
            ],
            [
                "ObjectEndMarker",
                {
                    "isSerialized": false,
                    "isSigningField": true,
                    "isVLEncoded": false,
                    "nth": 1,
                    "type": "STObject"
                }
            ],
        ...
```

Close #3657

---------

Co-authored-by: Richard Holland <richard.holland@starstone.co.nz>
2025-06-17 12:32:01 +09:00
Gregory Tsipenyuk
5109b1a117 fix: improper handling of large synthetic AMM offers:
A large synthetic offer was not handled correctly in the payment engine.
This patch fixes that issue and introduces a new invariant check while
processing synthetic offers.
2025-06-17 12:18:08 +09:00
Ed Hennis
08abc9490d test: guarantee proper lifetime for temporary Rules object: (#4917)
* Commit 01c37fe introduced a change to the STTx unit test where a local
  "defaultRules" object was created with a temporary inline "presets"
  value provided to the ctor. Rules::Impl stores a const ref to the
  presets provided to the ctor.  This particular call provided an inline
  temp variable, which goes out of scope as soon as the object is
  created. On Windows, attempting to use the presets (e.g. via the
  enabled() function) causes an access violation, which crashes the test
  run.
* An audit of the code indicates that all other instances of Rules use
  the Application's config.features list, which will have a sufficient
  lifetime.
2025-06-17 12:17:12 +09:00
Gregory Tsipenyuk
71ffc69819 fixInnerObjTemplate: set inner object template (#4906)
Add `STObject` constructor to explicitly set the inner object template.
This allows certain AMM transactions to apply in the same ledger:

There is no issue if the trading fee is greater than or equal to 0.01%.
If the trading fee is less than 0.01%, then:
- After AMM create, AMM transactions must wait for one ledger to close
  (3-5 seconds).
- After one ledger is validated, all AMM transactions succeed, as
  appropriate, except for AMMVote.
- The first AMMVote which votes for a 0 trading fee in a ledger will
  succeed. Subsequent AMMVote transactions which vote for a 0 trading
  fee will wait for the next ledger (3-5 seconds). This behavior repeats
  for each ledger.

This has no effect on the ultimate correctness of AMM. This amendment
will allow the transactions described above to succeed as expected, even
if the trading fee is 0 and the transactions are applied within one
ledger (block).
2025-06-17 12:17:12 +09:00
Chenna Keshava B S
c29a632d0c feat: allow port_grpc to be specified in [server] stanza (#4728)
Prior to this commit, `port_grpc` could not be added to the [server]
stanza. Instead of validating gRPC IP/Port/Protocol information in
ServerHandler, validate grpc port info in GRPCServer constructor. This
should not break backwards compatibility.

gRPC-related config info must be in a section (stanza) called
[port_gprc].

* Close #4015 - That was an alternate solution. It was decided that with
  relaxed validation, it is not necessary to rename port_grpc.
* Fix #4557
2025-06-17 12:17:11 +09:00
Michael Legleux
a8fe0f62e2 build: add headers needed in Conan package for libxrpl (#4885)
These headers are required in the xrpl Conan package in order for
xbridge witness server (xbwd) to build. This change to libxrpl may help
any dependents of libxrpl. This addition does not change any C++ code.
2025-06-17 12:17:11 +09:00
Shawn Xie
59070b4f3e fixNFTokenReserve: ensure NFT tx fails when reserve is not met (#4767)
Without this amendment, an NFTokenAcceptOffer transaction can succeed
even when the NFToken recipient does not have sufficient reserves for
the new NFTokenPage. This allowed accounts to accept NFT sell offers
without having a sufficient reserve. (However, there was no issue in
brokered mode or when a buy offer is involved.)

Instead, the transaction should fail with `tecINSUFFICIENT_RESERVE` as
appropriate. The `fixNFTokenReserve` amendment adds checks in the
NFTokenAcceptOffer transactor to check if the OwnerCount changed. If it
did, then it checks the new reserve requirement.

Fix #4679
2025-06-17 12:17:10 +09:00
tequ
880d8a7be8 bad merge: RPCCall_test, Transaction_test 2025-06-17 12:17:10 +09:00
Ed Hennis
b8854c7437 Fix cahce bug introduced in 2.0.1
Partially chery-picked from f419c18056
2025-06-17 12:17:09 +09:00
John Freeman
5ab9e2fed5 fix(libxrpl): change library names in Conan recipe (#4831)
Use consistent platform-agnostic library names on all platforms.

Fix an issue that prevents dependents like validator-keys-tool from
linking to libxrpl on Windows.

It is bad practice to change the binary base name depending on the
platform. CMake already manipulates the base name into a final name that
fits the conventions of the platform. Linkers accept base names on the
command line and then look for conventional names on disk.
2025-06-17 12:17:09 +09:00
Bronek Kozicki
eb7e17e4f8 test: add unit test for redundant payment (#4860)
If the payee and payer are the same account, then the transaction fails
in preflight with temREDUNDANT.
2025-06-17 12:17:09 +09:00
Bronek Kozicki
e9287a3d3d test: improve code coverage reporting (#4849)
* Speed up the generation of coverage reports by using multiple cores.

* Add codecov step to coverage workflow.
2025-06-17 12:17:05 +09:00
Chenna Keshava B S
2572b3204c docs: update help message about unit test-suite pattern matching (#4846)
Update the "rippled --help" message for the "-u" parameter. This
documents the unit test name pattern matching rule implemented by #4634.

Fix #4800
2025-06-17 12:16:14 +09:00
Elliot Lee
b3de0b6329 docs: add Performance type to PR template (#4875) 2025-06-17 12:16:14 +09:00
Bronek Kozicki
fe5bf9c12d test: add DeliverMax to more JSONRPC tests (#4826)
Minor change in unit tests to improve testing scope.
2025-06-17 12:16:13 +09:00
John Freeman
bb2712dd20 fix: change default send_queue_limit to 500 (#4867)
Clients subscribed to `transactions` over WebSocket are being
disconnected because the traffic exceeds the default `send_queue_limit`
of 100.

This commit changes the default configuration, not the default in code.

Fix #4866
2025-06-17 12:16:13 +09:00
Ed Hennis
0a97b9f471 Improve lifetime management of ledger objects (SLEs) to prevent runaway memory usage: (#4822)
* Add logging for Application.cpp sweep()
* Improve lifetime management of ledger objects (`SLE`s)
* Only store SLE digest in CachedView; get SLEs from CachedSLEs
* Also force release of last ledger used for path finding if there are
  no path finding requests to process
* Count more ST objects (derive from `CountedObject`)
* Track CachedView stats in CountedObjects
* Rename the CachedView counters
* Fix the scope of the digest lookup lock

Before this patch, if you asked "is it caching?" It was always caching.
2025-06-17 12:16:13 +09:00
Ed Hennis
469d4e81e4 WebSocket should only call async_close once (#4848)
Prevent WebSocket connections from trying to close twice.

The issue only occurs in debug builds (assertions are disabled in
release builds, including published packages), and when the WebSocket
connections are unprivileged. The assert (and WRN log) occurs when a
client drives up the resource balance enough to be forcibly disconnected
while there are still messages pending to be sent.

Thanks to @lathanbritz for discovering this issue in #4822.
2025-06-17 12:16:12 +09:00
Hussein Badakhchani
4aa8259353 fix typo: 'of' instead of 'on' (#4821)
Co-authored-by: Hussein Badakhchani <hoos@alsoug.com>
2025-06-17 12:16:12 +09:00
Bronek Kozicki
614382cb7e Workarounds for gcc-13 compatibility (#4817)
Workaround for compilation errors with gcc-13 and other compilers
relying on `libstdc++` version 13. This is temporary until actual fix is
available for us to use: https://github.com/boostorg/beast/pull/2682

Some boost.beast files (which we do use) rely on an old gcc-12 behaviour
where `#include <cstdint>` was not needed even though types from this
header were used. This was broken by a change in libstdc++ version 13:
https://gcc.gnu.org/gcc-13/porting_to.html#header-dep-changes

The necessary fix was implemented in boost.beast, however it is not yet
available. Until it is available, we can use this workaround to enable
compilation of `rippled` with gcc-13, clang-16, etc.
2025-06-17 12:16:11 +09:00
Bronek Kozicki
2c6dff314b APIv2: show DeliverMax in submit, submit_multisigned (#4827)
Show `DeliverMax` instead of `Amount` in output from `submit`,
`submit_multisigned`, `sign`, and `sign_for`.

Fix #4829
2025-06-17 12:16:11 +09:00
Bronek Kozicki
b83e66882c APIv2: consistently return ledger_index as integer (#4820)
For api_version 2, always return ledger_index as integer in JSON output.

api_version 1 retains prior behavior.
2025-06-17 12:16:10 +09:00
Bronek Kozicki
c569651f83 Fix 2.0 regression in tx method with binary output (#4812)
* Fix binary output from tx method

* Formatting fix

* Minor test improvement

* Minor test improvements
2025-06-17 12:16:10 +09:00
Bronek Kozicki
999fc61230 Promote API version 2 to supported (#4803)
* Promote API version 2 to supported

* Switch command line to API version 1

* Fix LedgerRequestRPC test

* Remove obsolete tx_account method

This method is not implemented, the only parts which are removed are related to command-line parsing

* Fix RPCCall test

* Reduce diff size, small test improvements

* Minor fixes

* Support for the mold linker

* [fold] handle case where both mold and gold are installed

* [fold] Use first non-default linker

* Fix TransactionEntry_test

* Fix AccountTx_test

---------

Co-authored-by: seelabs <scott.determan@yahoo.com>
2025-06-17 12:16:10 +09:00
Scott Determan
9899eda7c2 Support for the mold linker (#4807) 2025-06-17 12:16:09 +09:00
Bronek Kozicki
41daa9f64c Unify JSON serialization format of transactions (#4775)
* Remove include <ranges>

* Formatting fix

* Output for subscriptions

* Output from sign, submit etc.

* Output from ledger

* Output from account_tx

* Output from transaction_entry

* Output from tx

* Store close_time_iso in API v2 output

* Add small APIv2 unit test for subscribe

* Add unit test for transaction_entry

* Add unit test for tx

* Remove inLedger from API version 2

* Set ledger_hash and ledger_index

* Move isValidated from RPCHelpers to LedgerMaster

* Store closeTime in LedgerFill

* Time formatting fix

* additional tests for Subscribe unit tests

* Improved comments

* Rename mInLedger to mLedgerIndex

* Minor fixes

* Set ledger_hash on closed ledger, even if not validated

* Update API-CHANGELOG.md

* Add ledger_hash, ledger_index to transaction_entry

* Fix validated and close_time_iso in account_tx

* Fix typos

* Improve getJson for Transaction and STTx

* Minor improvements

* Replace class enum JsonOptions with struct

We may consider turning this into a general-purpose template and using it elsewhere

* simplify the extraction of transactionID from Transaction object

* Remove obsolete comments

* Unconditionally set validated in account_tx output

* Minor improvements

* Minor fixes

---------

Co-authored-by: Chenna Keshava <ckeshavabs@gmail.com>
2025-06-17 12:16:09 +09:00
Scott Determan
d75a6edc58 fix: check for valid public key in attestations (#4798) 2025-06-17 12:16:08 +09:00
pwang200
cc60747344 Fix unit test api_version to enable api_version 2 (#4785)
The command line API still uses `apiMaximumSupportedVersion`.
The unit test RPCs use `apiMinimumSupportedVersion` if unspecified.

Context:
- #4568
- #4552
2025-06-17 12:16:08 +09:00
Gregory Tsipenyuk
65c7f6f7d0 fixFillOrKill: fix offer crossing with tfFillOrKill (#4694)
Introduce the `fixFillOrKill` amendment.

Fix an edge case occurring when an offer with `tfFillOrKill` set (but
without `tfSell` set) fails to cross an offer with a better rate. If
`tfFillOrKill` is set, then the owner must receive the full TakerPays.
Without this amendment, an offer fails if the entire `TakerGets` is not
spent. With this amendment, when `tfSell` is not set, the entire
`TakerGets` does not have to be spent.

For details about OfferCreate, see: https://xrpl.org/offercreate.html

Fix #4684

---------

Co-authored-by: Scott Schurr <scott@ripple.com>
2025-06-17 12:16:07 +09:00
Bronek Kozicki
c3a36ad748 fix: remove include <ranges> (#4788)
Remove dependency on `<ranges>` header, since it is not implemented by
all compilers which we want to support.

This code change only affects unit tests.

Resolve https://github.com/XRPLF/rippled/issues/4787
2025-06-17 12:16:07 +09:00
Bronek Kozicki
0a3ce6cf36 APIv2: remove tx_history and ledger_header (#4759)
Remove `tx_history` and `ledger_header` methods from API version 2.

Update `RPC::Handler` to allow for methods (or method implementations)
to be API version specific. This partially resolves #4727. We can now
store multiple handlers with the same name, as long as they belong to
different (non-overlapping) API versions. This necessarily impacts the
handler lookup algorithm and its complexity; however, there is no
performance loss on x86_64 architecture, and only minimal performance
loss on arm64 (around 10ns). This design change gives us extra
flexibility evolving the API in the future, including other parts of

In API version 2, `tx_history` and `ledger_header` are no longer
recognised; if they are called, `rippled` will return error
`unknownCmd`

Resolve #3638

Resolve #3539
2025-06-17 12:16:06 +09:00
Mark Travis
bedafe5cff docs: clarify definition of network health (#4729)
Update the documentation to describe network health with more nuance as
well as context about related factors.
2025-06-17 12:16:06 +09:00
tequ
d7b7bf7a10 fix temCode: bad merge 2025-06-17 12:16:06 +09:00
Bronek Kozicki
446a1fdaac APIv2(DeliverMax): add alias for Amount in Payment transactions (#4733)
Using the "Amount" field in Payment transactions can cause incorrect
interpretation. There continue to be problems from the use of this
field. "Amount" is rarely the correct field to use; instead,
"delivered_amount" (or "DeliveredAmount") should be used.

Rename the "Amount" field to "DeliverMax", a less misleading name. With
api_version: 2, remove the "Amount" field from Payment transactions.

- Input: "DeliverMax" in `tx_json` is an alias for "Amount"
  - sign
  - submit (in sign-and-submit mode)
  - submit_multisigned
  - sign_for
- Output: Add "DeliverMax" where transactions are provided by the API
  - ledger
  - tx
  - tx_history
  - account_tx
  - transaction_entry
  - subscribe (transactions stream)
- Output: Remove "Amount" from API version 2

Fix #3484

Fix #3902
2025-06-17 12:16:05 +09:00
Mayukha Vadari
18ccbf4a53 DID: Decentralized identifiers (DIDs) (XLS-40): (#4636)
Implement native support for W3C DIDs.

Add a new ledger object: `DID`.

Add two new transactions:
1. `DIDSet`: create or update the `DID` object.
2. `DIDDelete`: delete the `DID` object.

This meets the requirements specified in the DID v1.0 specification
currently recommended by the W3C Credentials Community Group.

The DID format for the XRP Ledger conforms to W3C DID standards.
The objects can be created and owned by any XRPL account holder.
The transactions can be integrated by any service, wallet, or application.
2025-06-17 12:16:05 +09:00
Scott Schurr
9f2fd23575 refactor(peerfinder): use LogicError in PeerFinder::Logic (#4562)
It might be possible for the server code to indirect through certain
`end()` iterators. While a debug build would catch this problem with
`assert()`s, a release build would crash. If there are problems in this
area in the future, it is best to get a definitive indication of the
nature of the error regardless of whether it's a debug or release build.
To accomplish this, these `assert`s are converted into `LogicError`s
that will produce a reasonable error message when they fire.
2025-06-17 12:16:04 +09:00
Ed Hennis
20a422076d fix(PathRequest): remove incorrect assert (#4743)
The assert is saying that the only reason `pathFinder` would be null is
if the request was aborted (connection dropped, etc.). That's what
`continueCallback()` checks. But that is very clearly not true if you
look at `getPathFinder`, which calls `findPaths`, which can return false
for many reasons.

Fix #4744
2025-06-17 12:16:04 +09:00
Ed Hennis
7fded60cc9 docs(API-CHANGELOG): add XRPFees change (#4741)
* Add a new API Changelog section for release 1.10.
* Mark `jss::fee_ref` as deprecated.
* Fix a copy-paste error in one of the unit tests.
2025-06-17 12:16:03 +09:00
Florent
136508e56c docs(rippled-example.cfg): add P2P link compression (#4753)
P2P link compression is a feature added in 1.6.0 by #3287.

https://xrpl.org/enable-link-compression.html

If the default changes in the future - for example, as currently
proposed by #4387 - the comment will be updated at that time.

Fix #4656
2025-06-17 12:16:03 +09:00
Denis Angell
ef1c26f9f5 fixDisallowIncomingV1: allow issuers to authorize trust lines (#4721)
Context: The `DisallowIncoming` amendment provides an option to block
incoming trust lines from reaching your account. The
asfDisallowIncomingTrustline AccountSet Flag, when enabled, prevents any
incoming trust line from being created. However, it was too restrictive:
it would block an issuer from authorizing a trust line, even if the
trust line already exists. Consider:

1. Issuer sets asfRequireAuth on their account.
2. User sets asfDisallowIncomingTrustline on their account.
3. User submits tx to SetTrust to Issuer.

At this point, without `fixDisallowIncomingV1` active, the issuer would
not be able to authorize the trust line.

The `fixDisallowIncomingV1` amendment, once activated, allows an issuer
to authorize a trust line even after the user sets the
asfDisallowIncomingTrustline flag, as long as the trust line already
exists.
2025-06-17 12:16:03 +09:00
Scott Determan
a8e8d50cb8 refactor: reduce boilerplate in applySteps: (#4710)
When a new transactor is added, there are several places in applySteps
that need to be modified. This patch refactors the code so only one
function needs to be modified.
2025-06-17 12:16:02 +09:00
Rome Reginelli
73933a366b refactor: reunify transaction common fields: (#4715)
Make transactions and pseudo-transactions share the same commonFields
again. This regularizes the code in a nice way.

While this technically allows pseudo-transactions to have a
TicketSequence field, pseudo-transactions are only ever constructed by
code paths that don't add such a field, so this is not a transaction
processing change. It may be possible to add a separate check to ensure
TicketSequence (and other fields that don't make sense on
pseudo-transactions) are never added to pseudo-transactions, but that
should not be necessary. (TicketSequence is not the only common field
that can not and does not appear in pseudo-transactions.) Note:
TicketSequence is already documented as a common field.

Related: #4637

Fix #4714
2025-06-17 12:16:02 +09:00
Chenna Keshava B S
92f0efb064 docs(BUILD.md): require GCC 11 or higher (#4700)
Update minimum compiler requirement for building the codebase. The
feature "using enum" is required. This feature was introduced in C++20.

Updating the C++ compiler to version 11 or later fixes this error:

```
Building CXX object CMakeFiles/xrpl_core.dir/src/ripple/protocol/impl/STAmount.cpp.o
/build/ripple/binary/src/ripple/protocol/impl/STAmount.cpp: In lambda function:
/build/ripple/binary/src/ripple/protocol/impl/STAmount.cpp:1577:15: error: expected nested-name-specifier before 'enum'
 1577 |         using enum Number::rounding_mode;
      |               ^~~~
```

Fix #4693
2025-06-17 12:16:01 +09:00
Scott Determan
11849215b4 fix(XLS-38): disallow the same bridge on one chain: (#4720)
Modify the `XChainBridge` amendment.

Before this patch, two door accounts on the same chain could could own
the same bridge spec (of course, one would have to be the issuer and one
would have to be the locker). While this is silly, it does not violate
any bridge invariants. However, on further review, if we allow this then
the `claim` transactions would need to change. Since it's hard to see a
use case for two doors to own the same bridge, this patch disallows
it. (The transaction will return tecDUPLICATE).
2025-06-17 12:16:01 +09:00
Scott Schurr
e9f83a7808 fix: stabilize voting threshold for amendment majority mechanism (#4410)
Amendment "flapping" (an amendment repeatedly gaining and losing
majority) usually occurs when an amendment is on the verge of gaining
majority, and a validator not in favor of the amendment goes offline or
loses sync. This fix makes two changes:

1. The number of validators in the UNL determines the threshold required
   for an amendment to gain majority.
2. The AmendmentTable keeps a record of the most recent Amendment vote
   received from each trusted validator (and, with `trustChanged`, stays
   up-to-date when the set of trusted validators changes). If no
   validation arrives from a given validator, then the AmendmentTable
   assumes that the previously-received vote has not changed.

In other words, when missing an `STValidation` from a remote validator,
each server now uses the last vote seen. There is a 24 hour timeout for
recorded validator votes.

These changes do not require an amendment because they do not impact
transaction processing, but only the threshold at which each individual
validator decides to propose an EnableAmendment pseudo-transaction.

Fix #4350
2025-06-17 12:16:00 +09:00
Ed Hennis
8b0cb51d24 fix(build): uint is not defined on Windows platform (#4731)
Fix the Windows build by using `unsigned int` (instead of `uint`).

The error, introduced by #4618, looks something like:
  rpc\impl\RPCHelpers.h(299,5): error C2061: syntax error: identifier
  'uint' (compiling source file app\ledger\Ledger.cpp)
2025-06-17 12:16:00 +09:00
Nik Bougalis
9838bdf214 Eliminate the built-in SNTP support (fixes #4207): (#4628) 2025-06-17 12:15:59 +09:00
John Freeman
6cf6416f15 fix: accept all valid currency codes in API (#4566)
A few methods, including `book_offers`, take currency codes as
parameters. The XRPL doesn't care if the letters in those codes are
lowercase or uppercase, as long as they come from an alphabet defined
internally. rippled doesn't care either, when they are submitted in a
hex representation. When they are submitted in an ASCII string
representation, rippled, but not XRPL, is more restrictive, preventing
clients from interacting with some currencies already in the XRPL.

This change gets rippled out of the way and lets clients submit currency
codes in ASCII using the full alphabet.

Fixes #4112
2025-06-17 12:15:59 +09:00
Bronek Kozicki
5e1dd22bf3 chore: add .build to .gitignore (#4722)
Currently, the `BUILD.md` instructions suggest using `.build` as the
build directory, so this change helps to reduce confusion.

An alternative would be to instruct developers to add `/.build/` to
`.git/info/exclude` or to user-level `.gitignore` (although the latter
is very intrusive). However, it is being added here because it is a good
practice to have a sensible default that's consistent with the build
instructions.
2025-06-17 12:15:59 +09:00
ForwardSlashBack
dc08a666f9 Fix typo in BUILD.md (#4718)
Co-authored-by: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com>
2025-06-17 12:15:58 +09:00
Peter Chen
07dda63bd5 APIv2(gateway_balances, channel_authorize): update errors (#4618)
gateway_balances
* When `account` does not exist in the ledger, return `actNotFound`
  * (Previously, a normal response was returned)
  * Fix #4290
* When required field(s) are missing, return `invalidParams`
  * (Previously, `invalidHotWallet` was incorrectly returned)
  * Fix #4548

channel_authorize
* When the specified `key_type` is invalid, return `badKeyType`
  * (Previously, `invalidParams` was returned)
  * Fix #4289

Since these are breaking changes, they apply only to API version 2.

Supersedes #4577
2025-06-17 12:15:58 +09:00
John Freeman
53cdb040cf build: use Boost 1.82 and link Boost.Json (#4632)
Add Boost::json to the list of linked Boost libraries.

This seems to be required for macOS.
2025-06-17 12:15:57 +09:00
Chenna Keshava B S
01890e863a docs(overlay): add URL of blog post and clarify wording (#4635) 2025-06-17 12:15:57 +09:00
Elliot Lee
6057c65027 docs(RELEASENOTES): update 1.12.0 notes to match dev blog (#4691)
* Reorganize some changelog entries
* Add note about portable binaries
* Dev blog: https://xrpl.org/blog
2025-06-17 12:15:56 +09:00
John Freeman
0815ec39f8 Update secp256k1 to 0.3.2 (#4653)
Copy the new code to `src/secp256k1` without changes:
`src/secp256k1` is identical to bitcoin-core/secp256k1@acf5c55 (v0.3.2).

We could consider changing to a Git submodule, though that would require
changes to the build instructions because we are not using submodules
anywhere else.
2025-06-17 12:15:56 +09:00
Chenna Keshava B S
c60eb416d2 docs: fix comment for LedgerHistory::fixIndex return value (#4574)
`LedgerHistory::fixIndex` returns `false` if a repair was performed.

Fix #4572
2025-06-17 12:15:55 +09:00
Ed Hennis
3ea653cccb fix: remove unused variable causing clang 14 build errors (#4672)
Removed the unused variable `none` from `Writer.cpp` which was causing
build errors on clang version 14.
2025-06-17 12:15:55 +09:00
Elliot Lee
9605fa0e53 docs(BUILD): make it easier to find environment.md (#4507)
Make the instructions a bit easier to follow. Users on different
platforms can look for their platform name to find relevant information.
2025-06-17 12:15:55 +09:00
Michael Legleux
5741a0d5cb Revert CMake changes (#4707)
This was likely put back when #4292 was rebased.
2025-06-17 12:15:54 +09:00
Scott Determan
11b1602814 Change XChainBridge amendment to Supported::yes (#4709) 2025-06-17 12:15:54 +09:00
Scott Determan
8667480406 Fix Windows build by removing two unused declarations (#4708)
Remove the `verify` and `message` function declarations. The explicit
instantiation requests could not be completed because there were no
implementations for those two member functions. It is helpful that the
Microsoft (MSVC) compiler on Windows appears to be strict when it comes
to template instantiation.

This resolves the warning:

  XChainAttestations.h(450): warning C4661: 'bool
  ripple::XChainAttestationsBase<ripple::XChainClaimAttestation>::verify(void)
  const': no suitable definition provided for explicit template
  instantiation request
2025-06-17 12:15:53 +09:00
Ed Hennis
cff548bcc8 Match unit tests on start of test name (#4634)
* For example, without this change, to run the TxQ tests, must specify
  `--unittest=TxQ1,TxQ2` on the command line. With this change, can use
  `--unittest=TxQ`, and both will be run.
* An exact match will prevent any further partial matching.
* This could have some side effects for different tests with a common
  name beginning. For example, NFToken, NFTokenBurn, NFTokenDir. This
  might be useful. If not, the shorter-named test(s) can be renamed. For
  example, NFToken to NFTokens.
* Split the NFToken, NFTokenBurn, and Offer test classes. Potentially speeds
  up parallel tests by a factor of 5.
2025-06-17 12:15:53 +09:00
Howard Hinnant
acf7486c8d Revert ThreadName due to problems on Windows (#4702)
* Revert "Remove CurrentThreadName.h from RippledCore.cmake (#4697)"

This reverts commit 3b5fcd587313f5ebc762bc21c6a4ec3e6c275e83.

* Revert "Introduce replacement for getting and setting thread name: (#4312)"

This reverts commit 36cb5f90e233f975eb3f80d819b2fbadab0a9387.
2025-06-17 12:15:52 +09:00
Scott Determan
6de5de02cb XChainBridge: Introduce sidechain support (XLS-38): (#4292)
A bridge connects two blockchains: a locking chain and an issuing
chain (also called a mainchain and a sidechain). Both are independent
ledgers, with their own validators and potentially their own custom
transactions. Importantly, there is a way to move assets from the
locking chain to the issuing chain and a way to return those assets from
the issuing chain back to the locking chain: the bridge. This key
operation is called a cross-chain transfer. A cross-chain transfer is
not a single transaction. It happens on two chains, requires multiple
transactions, and involves an additional server type called a "witness".

A bridge does not exchange assets between two ledgers. Instead, it locks
assets on one ledger (the "locking chain") and represents those assets
with wrapped assets on another chain (the "issuing chain"). A good model
to keep in mind is a box with an infinite supply of wrapped assets.
Putting an asset from the locking chain into the box will release a
wrapped asset onto the issuing chain. Putting a wrapped asset from the
issuing chain back into the box will release one of the existing locking
chain assets back onto the locking chain. There is no other way to get
assets into or out of the box. Note that there is no way for the box to
"run out of" wrapped assets - it has an infinite supply.

Co-authored-by: Gregory Popovitch <greg7mdp@gmail.com>
2025-06-17 12:15:52 +09:00
Peter Chen
2c5ecfa75d APIv2(account_tx, noripple_check): return error on invalid input (#4620)
For the `account_tx` and `noripple_check` methods, perform input
validation for optional parameters such as "binary", "forward",
"strict", "transactions". Previously, when these parameters had invalid
values (e.g. not a bool), no error would be returned. Now, it returns an
`invalidParams` error.

* This updates the behavior to match Clio
  (https://github.com/XRPLF/clio).
* Since this is potentially a breaking change, it only applies to
  requests specifying api_version: 2.
* Fix #4543.
2025-06-17 12:15:52 +09:00
Howard Hinnant
bbc943ca10 Remove CurrentThreadName.h from RippledCore.cmake (#4697)
(File was already removed from the source)
2025-06-17 12:15:51 +09:00
Mayukha Vadari
5d3b8976f7 refactor: simplify TxFormats common fields logic (#4637)
Minor refactor to `TxFormats.cpp`:
- Rename `commonFields` to `pseudoCommonFields` (since it is the common fields
  that all pseudo-transactions need)
- Add a new static variable, `commonFields`, which represents all the common
  fields that non-pseudo transactions need (essentially everything that
  `pseudoCommonFields` contains, plus `sfTicketSequence`)

This makes it harder to accidentally leave out `sfTicketSequence` in a new
transaction.
2025-06-17 12:15:51 +09:00
Peter Chen
cabb9cfd50 APIv2(ledger_entry): return invalidParams for bad parameters (#4630)
- Verify "check", used to retrieve a Check object, is a string.
- Verify "nft_page", used to retrieve an NFT Page, is a string.
- Verify "index", used to retrieve any type of ledger object by its
  unique ID, is a string.
- Verify "directory", used to retrieve a DirectoryNode, is a string or
  an object.

This change only impacts api_version 2 since it is a breaking change.

https://xrpl.org/ledger_entry.html

Fix #4550
2025-06-17 12:15:50 +09:00
Mark Pevec
27c1ab5fba docs(rippled-example.cfg): clarify ssl_cert vs ssl_chain (#4667)
Clarify usage of ssl_cert vs ssl_chain
2025-06-17 12:15:50 +09:00
Howard Hinnant
0f4bc92f77 Introduce replacement for getting and setting thread name: (#4312)
* In namespace ripple, introduces get_name function that takes a
  std:🧵:native_handle_type and returns a std::string.
* In namespace ripple, introduces get_name function that takes a
  std::thread or std::jthread and returns a std::string.
* In namespace ripple::this_thread, introduces get_name function
  that takes no parameters and returns the name of the current
  thread as a std::string.
* In namespace ripple::this_thread, introduces set_name function
  that takes a std::string_view and sets the name of the current
  thread.
* Intended to replace the beast utilities setCurrentThreadName
  and getCurrentThreadName.
2025-06-17 12:15:49 +09:00
tequ
5f02b98066 fix bad merge (Remarks) 2025-06-16 00:19:12 +09:00
John Freeman
52d3babf1b Update dependencies (#4595)
Use the most recent versions in ConanCenter.

* Due to a bug in Clang 16, you may get a compile error:
  "call to 'async_teardown' is ambiguous"
  * A compiler flag workaround is documented in `BUILD.md`.
* At this time, building this with gcc 13 may require editing some files
  in `.conan/data`
  * A patch to support gcc13 may be added in a later PR.

---------

Co-authored-by: Scott Schurr <scott@ripple.com>
2025-06-15 23:18:30 +09:00
Gregory Tsipenyuk
9a82bf9ec2 amm_info: fetch by amm account id; add AMM object entry (#4682)
- Update amm_info to fetch AMM by amm account id.
  - This is an additional way to retrieve an AMM object.
  - Alternatively, AMM can still be fetched by the asset pair as well.
- Add owner directory entry for AMM object.

Context:

- Add back the AMM object directory entry, which was deleted by #4626.
  - This fixes `account_objects` for `amm` type.
2025-06-15 23:14:45 +09:00
Rome Reginelli
f94e1c1be2 AMMBid: use tecINTERNAL for 'impossible' errors (#4674)
Modify two error cases in AMMBid transactor to return `tecINTERNAL` to
more clearly indicate that these errors should not be possible unless
operating in unforeseen circumstances. It likely indicates a bug.

The log level has been updated to `fatal()` since it indicates a
(potentially network-wide) unexpected condition when either of these
errors occurs.

Details:

The two specific transaction error cases changed are:

- `tecAMM_BALANCE` - In this case, this error (total LP Tokens
  outstanding is lower than the amount to be burned for the bid) is a
  subset of the case where the user doesn't have enough LP Tokens to pay
  for the bid. When this case is reached, the bidder's LP Tokens balance
  has already been checked first. The user's LP Tokens should always be
  a subset of total LP Tokens issued, so this should be impossible.
- `tecINSUFFICIENT_PAYMENT` - In this case, the amount to be refunded as
  a result of the bid is greater than the price paid for the auction
  slot. This should never occur unless something is wrong with the math
  for calculating the refund amount.

Both error cases in question are "defense in depth" measures meant to
protect against making things worse if the code has already reached a
state that is supposed to be impossible, likely due to a bug elsewhere.

Such "shouldn't ever occur" checks should use an error code that
categorically indicates a larger problem. This is similar to how
`tecINVARIANT_FAILED` is a warning sign that something went wrong and
likely could've been worse, but since there isn't an Invariant Check
applying here, `tecINTERNAL` is the appropriate error code.

This is "debatably" a transaction processing change since it could
hypothetically change how transactions are processed if there's a bug we
don't know about.
2025-06-15 23:14:44 +09:00
Ikko Eltociear Ashimine
9e1831cacf refactor: fix typo in FeeUnits.h (#4644)
covert -> convert
2025-06-15 23:14:44 +09:00
Arihant Kothari
3eb8a64e64 test: add forAllApiVersions helper function (#4611)
Introduce a new variadic template helper function, `forAllApiVersions`,
that accepts callables to execute a set of functions over a range of
versions - from RPC::apiMinimumSupportedVersion to RPC::apiBetaVersion.
This avoids the duplication of code.

Context: #4552
2025-06-15 23:14:43 +09:00
Mayukha Vadari
61fd0d0164 add view updates for account SLEs (#4629)
Signed-off-by: Manoj Doshi <mdoshi@ripple.com>
2025-06-15 23:14:43 +09:00
John Freeman
314cf50863 Fix the package recipe for consumers of libxrpl (#4631)
- "Rename" the type `LedgerInfo` to `LedgerHeader` (but leave an alias
  for `LedgerInfo` to not yet disturb existing uses). Put it in its own
  public header, named after itself, so that it is more easily found.
- Move the type `Fees` and NFT serialization functions into public
  (installed) headers.
- Compile the XRPL and gRPC protocol buffers directly into `libxrpl` and
  install their headers. Fix the Conan recipe to correctly export these
  types.

Addresses change (2) in
https://github.com/XRPLF/XRPL-Standards/discussions/121.

For context: This work supports Clio's dependence on libxrpl. Clio is
just an example consumer. These changes should benefit all current and
future consumers.

---------

Co-authored-by: cyan317 <120398799+cindyyan317@users.noreply.github.com>
Signed-off-by: Manoj Doshi <mdoshi@ripple.com>
2025-06-15 23:14:43 +09:00
John Freeman
00a6922045 Fix package definition for Conan (#4485)
Fix the libxrpl library target for consumers using Conan.

* Fix installation issues and update includes.
* Update requirements in the Conan package info.
  * libxrpl requires openssl::crypto.

(Conan is a software package manager for C++.)
2025-06-15 23:14:42 +09:00
Alphonse Noni Mousse
cd9facd7fa refactor: improve checking of path lengths (#4519)
Improve the checking of the path lengths during Payments. Previously,
the code that did the check of the payment path lengths was sometimes
executed, but without any effect. This changes it to only check when it
matters, and to not make unnecessary copies of the path vectors.

Signed-off-by: Manoj Doshi <mdoshi@ripple.com>
2025-06-15 23:09:45 +09:00
Alphonse N. Mousse
39b2e3334a refactor: use C++20 function std::popcount (#4389)
- Replace custom popcnt16 implementation with std::popcount from C++20
- Maintain compatibility with older compilers and MacOS by providing a
  conditional compilation fallback to __builtin_popcount and a lookup
  table method
- Move and inline related functions within SHAMapInnerNode for
  performance and readability

Signed-off-by: Manoj Doshi <mdoshi@ripple.com>
2025-06-15 23:09:44 +09:00
Gregory Tsipenyuk
f19e254366 fix(AMM): prevent orphaned objects, inconsistent ledger state: (#4626)
When an AMM account is deleted, the owner directory entries must be
deleted in order to ensure consistent ledger state.

* When deleting AMM account:
  * Clean up AMM owner dir, linking AMM account and AMM object
  * Delete trust lines to AMM
* Disallow `CheckCreate` to AMM accounts
  * AMM cannot cash a check
* Constrain entries in AuthAccounts array to be accounts
  * AuthAccounts is an array of objects for the AMMBid transaction
* SetTrust (TrustSet): Allow on AMM only for LP tokens
  * If the destination is an AMM account and the trust line doesn't
    exist, then:
    * If the asset is not the AMM LP token, then fail the tx with
      `tecNO_PERMISSION`
    * If the AMM is in empty state, then fail the tx with `tecAMM_EMPTY`
      * This disallows trustlines to AMM in empty state
* Add AMMID to AMM root account
  * Remove lsfAMM flag and use sfAMMID instead
* Remove owner dir entry for ltAMM
* Add `AMMDelete` transaction type to handle amortized deletion
  * Limit number of trust lines to delete on final withdraw + AMMDelete
  * Put AMM in empty state when LPTokens is 0 upon final withdraw
  * Add `tfTwoAssetIfEmpty` deposit option in AMM empty state
  * Fail all AMM transactions in AMM empty state except special deposit
  * Add `tecINCOMPLETE` to indicate that not all AMM trust lines are
    deleted (i.e. partial deletion)
    * This is handled in Transactor similar to deleted offers
  * Fail AMMDelete with `tecINTERNAL` if AMM root account is nullptr
  * Don't validate for invalid asset pair in AMMDelete
* AMMWithdraw deletes AMM trust lines and AMM account/object only if the
  number of trust lines is less than max
  * Current `maxDeletableAMMTrustLines` = 512
  * Check no directory left after AMM trust lines are deleted
  * Enable partial trustline deletion in AMMWithdraw
* Add `tecAMM_NOT_EMPTY` to fail any transaction that expects an AMM in
  empty state
* Clawback considerations
  * Disallow clawback out of AMM account
  * Disallow AMM create if issuer can claw back

This patch applies to the AMM implementation in #4294.

Acknowledgements:
Richard Holland and Nik Bougalis for responsibly disclosing this issue.

Bug Bounties and Responsible Disclosures:
We welcome reviews of the project code and urge researchers to
responsibly disclose any issues they may find.

To report a bug, please send a detailed report to:

    bugs@xrpl.org

Signed-off-by: Manoj Doshi <mdoshi@ripple.com>
2025-06-15 23:09:42 +09:00
RichardAH
5e083121da feat: support Concise Transaction Identifier (CTID) (XLS-37) (#4418)
* add CTIM to tx rpc

---------

Co-authored-by: Rome Reginelli <mduo13@gmail.com>
Co-authored-by: Elliot Lee <github.public@intelliot.com>
Co-authored-by: Denis Angell <dangell@transia.co>
2025-06-15 23:09:04 +09:00
Shawn Xie
683e9ccc1a Rename allowClawback flag to allowTrustLineClawback (#4617)
Reason for this change is here XRPLF/XRPL-Standards#119

We would want to be explicit that this flag is exclusively for trustline. For new token types(eg. CFT), they will not utilize this flag for clawback, instead, they will turn clawback on/off on the token-level, which is more versatile.
2025-06-15 23:09:03 +09:00
Gregory Tsipenyuk
8dbc6db079 Introduce AMM support (XLS-30d): (#4294)
Add AMM functionality:
- InstanceCreate
- Deposit
- Withdraw
- Governance
- Auctioning
- payment engine integration

To support this functionality, add:
- New RPC method, `amm_info`, to fetch pool and LPT balances
- AMM Root Account
- trust line for each IOU AMM token
- trust line to track Liquidity Provider Tokens (LPT)
- `ltAMM` object

The `ltAMM` object tracks:
- fee votes
- auction slot bids
- AMM tokens pair
- total outstanding tokens balance
- `AMMID` to AMM `RootAccountID` mapping

Add new classes to facilitate AMM integration into the payment engine.
`BookStep` uses these classes to infer if AMM liquidity can be consumed.

The AMM formula implementation uses the new Number class added in #4192.
IOUAmount and STAmount use Number arithmetic.

Add AMM unit tests for all features.

AMM requires the following amendments:
- featureAMM
- fixUniversalNumber
- featureFlowCross

Notes:
- Current trading fee threshold is 1%
- AMM currency is generated by: 0x03 + 152 bits of sha256{cur1, cur2}
- Current max AMM Offers is 30

---------

Co-authored-by: Howard Hinnant <howard.hinnant@gmail.com>
2025-06-15 23:09:01 +09:00
Elliot Lee
b7a29cad94 docs(CONTRIBUTING): push beta releases to release (#4589)
Sections that were rewrapped were wrapped to 72 characters, the same as
the recommendation for commit messages.
2025-06-15 23:07:39 +09:00
Arihant Kothari
7054bf64e9 APIv2(ledger_entry): return "invalidParams" when fields missing (#4552)
Improve error handling for ledger_entry by returning an "invalidParams"
error when one or more request fields are specified incorrectly, or one
or more required fields are missing.

For example, if none of of the following fields is provided, then the
API should return an invalidParams error:
* index, account_root, directory, offer, ripple_state, check, escrow,
  payment_channel, deposit_preauth, ticket

Prior to this commit, the API returned an "unknownOption" error instead.
Since the error was actually due to invalid parameters, rather than
unknown options, this error was misleading.

Since this is an API breaking change, the "invalidParams" error is only
returned for requests using api_version: 2 and above. To maintain
backward compatibility, the "unknownOption" error is still returned for
api_version: 1.

Related: #4573

Fix #4303
2025-06-15 23:07:39 +09:00
Chenna Keshava B S
3ddf1c99d5 refactor: change the return type of mulDiv to std::optional (#4243)
- Previously, mulDiv had `std::pair<bool, uint64_t>` as the output type.
  - This is an error-prone interface as it is easy to ignore when
    overflow occurs.
- Using a return type of `std::optional` should decrease the likelihood
  of ignoring overflow.
  - It also allows for the use of optional::value_or() as a way to
    explicitly recover from overflow.
- Include limits.h header file preprocessing directive in order to
  satisfy gcc's numeric_limits incomplete_type requirement.

Fix #3495

---------

Co-authored-by: John Freeman <jfreeman08@gmail.com>
2025-06-15 23:07:38 +09:00
Shawn Xie
6d5e7e519b fix: add allowClawback flag for account_info (#4590)
* Update the `account_info` API so that the `allowClawback` flag is
  included in the response.
  * The proposed `Clawback` amendement added an `allowClawback` flag in
    the `AccountRoot` object.
  * In the API response, under `account_flags`, there is now an
    `allowClawback` field with a boolean (`true` or `false`) value.
  * For reference, the XLS-39 Clawback implementation can be found in
    #4553

Fix #4588
2025-06-15 23:07:38 +09:00
Peter Chen
224ae4e70f APIv2(account_info): handle invalid "signer_lists" value (#4585)
When requesting `account_info` with an invalid `signer_lists` value, the
API should return an "invalidParams" error.

`signer_lists` should have a value of type boolean. If it is not a
boolean, then it is invalid input. The response now indicates that.

* This is an API breaking change, so the change is only reflected for
  requests containing `"api_version": 2`
* Fix #4539
2025-06-15 23:07:37 +09:00
Chenna Keshava B S
8531ba5838 fix: Update Handler::Condition enum values #3417 (#4239)
- Use powers of two to clearly indicate the bitmask
- Replace bitmask with explicit if-conditions to better indicate predicates

Change enum values to be powers of two (fix #3417) #4239

Implement the simplified condition evaluation
removes the complex bitwise and(&) operator
Implement the second proposed solution in Nik Bougalis's comment - Software does not distinguish between different Conditions (Version: 1.5) #3417 (comment)
I have tested this code change by performing RPC calls with the commands server_info, server_state, peers and validation_info. These commands worked as expected.
2025-06-15 23:07:37 +09:00
Peter Chen
73550a4bfc APIv2: add error messages for account_tx (#4571)
Certain inputs for the AccountTx method should return an error. In other
words, an invalid request from a user or client now results in an error
message.

Since this can change the response from the API, it is an API breaking
change. This commit maintains backward compatibility by keeping the
existing behavior for existing requests. When clients specify
"api_version": 2, they will be able to get the updated error messages.

Update unit tests to check the error based on the API version.

* Fix #4288
* Fix #4545
2025-06-15 23:07:36 +09:00
Ed Hennis
e353c9d6eb Fix build references to deleted ServerHandlerImp: (#4592)
* Commits 0b812cd (#4427) and 11e914f (#4516) conflict. The first added
  references to `ServerHandlerImp` in files outside of that class's
  organizational unit (which is technically incorrect). The second
  removed `ServerHandlerImp`, but was not up to date with develop. This
  results in the build failing.
* Fixes the build by changing references to `ServerHandlerImp` to
  the more correct `ServerHandler`.
2025-06-15 23:07:36 +09:00
Scott Schurr
b733d274a0 refactor: rename ServerHandlerImp to ServerHandler (#4516)
Rename `ServerHandlerImp` to `ServerHandler`. There was no other
ServerHandler definition despite the existence of a header suggesting
that there was.

This resolves a piece of historical confusion in the code, which was
identified during a code review.

The changes in the diff may look more extensive than they actually are.
The contents of `impl/ServerHandlerImp.h` were merged into
`ServerHandler.h`, making the latter file appear to have undergone
significant modifications. However, this is a non-breaking refactor that
only restructures code.
2025-06-15 23:07:36 +09:00
Chenna Keshava B S
346544e371 fix: remove deprecated fields in ledger method (#4244)
Remove deprecated fields from the ledger command:
* accepted
* hash (use ledger_hash instead)
* seqNum (use ledger_index instead)
* totalCoins (use total_coins instead)

Update SHAMapStore unit tests to use `jss:ledger_hash` instead of the
deprecated `hash` field.

Fix #3214
2025-06-15 23:07:35 +09:00
Denis Angell
5d2d1d4497 refactor: replace hand-rolled lexicalCast (#4473)
Replace hand-rolled code with std::from_chars for better
maintainability.

The C++ std::from_chars function is intended to be as fast as possible,
so it is unlikely to be slower than the code it replaces. This change is
a net gain because it reduces the amount of hand-rolled code.
2025-06-15 23:07:35 +09:00
Shawn Xie
0f0ffda053 XLS-39 Clawback: (#4553)
Introduces:
* AccountRoot flag: lsfAllowClawback
* New Clawback transaction
* More info on clawback spec: https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-39d-clawback
2025-06-15 23:07:32 +09:00
Howard Hinnant
37f7734b25 refactor: remove TypedField's move constructor (#4567)
Apply a minor cleanup in `TypedField`:
* Remove a non-working and unused move constructor.
* Constrain the remaining constructor to not be overly generic enough as
  to be used as a copy or move constructor.
2025-06-15 23:06:45 +09:00
drlongle
f8dc0cab65 Add RPC/WS ports to server_info (#4427)
Enhance the /crawl endpoint by publishing WebSocket/RPC ports in the
server_info response. The function processing requests to the /crawl
endpoint actually calls server_info internally, so this change enables a
server to advertise its WebSocket/RPC port(s) to peers via the /crawl
endpoint. `grpc` and `peer` ports are included as well.

The new `ports` array contains objects, each containing a `port` for the
listening port (number string), and an array `protocol` listing the
supported protocol(s).

This allows crawlers to build a richer topology without needing to
port-scan nodes. For non-admin users (including peers), the info about
*admin* ports is excluded.

Also increase test coverage for RPC ServerInfo.

Fix #2837.
2025-06-15 23:06:45 +09:00
Scott Schurr
3c4731a676 fixReducedOffersV1: prevent offers from blocking order books: (#4512)
Curtail the occurrence of order books that are blocked by reduced offers
with the implementation of the fixReducedOffersV1 amendment.

This commit identifies three ways in which offers can be reduced:

1. A new offer can be partially crossed by existing offers, so the new
   offer is reduced when placed in the ledger.

2. An in-ledger offer can be partially crossed by a new offer in a
   transaction. So the in-ledger offer is reduced by the new offer.

3. An in-ledger offer may be under-funded. In this case the in-ledger
   offer is scaled down to match the available funds.

Reduced offers can block order books if the effective quality of the
reduced offer is worse than the quality of the original offer (from the
perspective of the taker). It turns out that, for small values, the
quality of the reduced offer can be significantly affected by the
rounding mode used during scaling computations.

This commit adjusts some rounding modes so that the quality of a reduced
offer is always at least as good (from the taker's perspective) as the
original offer.

The amendment is titled fixReducedOffersV1 because additional ways of
producing reduced offers may come to light. Therefore, there may be a
future need for a V2 amendment.
2025-06-15 23:06:42 +09:00
Ed Hennis
995e70c2b0 Enable the Beta RPC API (v2) for all unit tests: (#4573)
* Enable api_version 2, which is currently in beta. It is expected to be
  marked stable by the next stable release.
* This does not change any defaults.
* The only existing tests changed were one that set the same flag, which
  was now redundant, and a couple that tested versioning explicitly.
2025-06-15 23:05:35 +09:00
264 changed files with 6008 additions and 39207 deletions

View File

@@ -1,40 +0,0 @@
codecov:
require_ci_to_pass: true
# This integration branch uploads the normal suite and JSHookz E2E coverage.
notify:
after_n_builds: 2
comment:
behavior: default
layout: reach,diff,flags,tree,reach
show_carryforward_flags: false
coverage:
range: "60..80"
precision: 1
round: nearest
status:
project:
default:
target: 60%
threshold: 2%
patch:
default:
target: auto
threshold: 2%
changes: false
github_checks:
annotations: true
parsers:
cobertura:
partials_as_hits: true
handle_missing_conditions : true
slack_app: false
ignore:
- "src/test/"
- "include/xrpl/beast/test/"
- "include/xrpl/beast/unit_test/"

View File

@@ -1,25 +1,8 @@
# This feature requires Git >= 2.24
# To use it by default in git blame:
# git config blame.ignoreRevsFile .git-blame-ignore-revs
# Format first-party source according to .clang-format
50760c693510894ca368e90369b0cc2dabfd07f3
# Reintroduce Clang-Format & Levelization
da1d20d6d5d862716125d60899b80fab5302954a
# Consolidate external libraries
da1d20d6d5d862716125d60899b80fab5302954a
# Rename .hpp to .h
0345a2645d0f5ad900f4fbbcaff96040d3a887fc
# Format formerly .hpp files
5a227dc719016e10045e17c9396ad401118044f1
# Rewrite includes
e61880699997398f5a746e6c4034edc7632661f5
# Move CMake directory (#4997)
e47b1c1b3b97c3f6d11858ee02f463596e29e7f0
# Rearrange sources (#4997)
bfafa2bb39e562901736d656806bd700c3699a2f
# Rewrite includes (#4997)
e61880699997398f5a746e6c4034edc7632661f5
# Recompute loops (#4997)
d25b5dcd568bb96c18e347d55fac10fe901a1bfb
# Reformat code with clang-format-18
02749feea88ce61c1f7eeb2d61a57d8ecf07ab11
e2384885f5f630c8f0ffe4bf21a169b433a16858
241b9ddde9e11beb7480600fd5ed90e1ef109b21
760f16f56835663d9286bd29294d074de26a7ba6
0eebe6a5f4246fced516d52b83ec4e7f47373edd

6
.gitattributes vendored
View File

@@ -11,9 +11,3 @@ LICENSE binary
*.vcxproj text eol=crlf
*.props text eol=crlf
*.filters text eol=crlf
# JSHookz projections checked for freshness by the integration workflow.
external/quickjs-provider/jshookz_provider.manifest.cmake linguist-generated=true
external/quickjs-provider/jshookz_provider.manifest.json linguist-generated=true
external/quickjs-provider/jshookz_provider.native-abi.json linguist-generated=true
src/test/app/JSHooks_test_hooks.h linguist-generated=true

View File

@@ -1,12 +0,0 @@
#!/bin/bash
# Pre-commit hook that runs the suspicious patterns check on staged files
# Get the repository's root directory
repo_root=$(git rev-parse --show-toplevel)
# Run the suspicious patterns script in pre-commit mode
"$repo_root/suspicious_patterns.sh" --pre-commit
# Exit with the same code as the script
exit $?

View File

@@ -1,4 +0,0 @@
#!/bin/bash
echo "Configuring git to use .githooks directory..."
git config core.hooksPath .githooks

View File

@@ -2,14 +2,6 @@ name: build
description: 'Builds the project with ccache integration'
inputs:
cmake-target:
description: 'CMake target to build'
required: false
default: all
cmake-args:
description: 'Additional CMake arguments'
required: false
default: null
generator:
description: 'CMake generator to use'
required: true
@@ -28,10 +20,6 @@ inputs:
description: 'C++ compiler to use'
required: false
default: ''
gcov:
description: 'Gcov to use'
required: false
default: ''
compiler-id:
description: 'Unique identifier: compiler-version-stdlib[-gccversion] (e.g. clang-14-libstdcxx-gcc11, gcc-13-libstdcxx)'
required: false
@@ -53,11 +41,10 @@ inputs:
required: false
default: 'dev'
stdlib:
description: 'C++ standard library to use (default = compiler default, e.g. GCC always uses libstdc++)'
description: 'C++ standard library to use'
required: true
type: choice
options:
- default
- libstdcxx
- libcxx
clang_gcc_toolchain:
@@ -100,6 +87,11 @@ runs:
export CCACHE_CONFIGPATH="$HOME/.config/ccache/ccache.conf"
echo "CCACHE_CONFIGPATH=$CCACHE_CONFIGPATH" >> $GITHUB_ENV
# Keep config separate from cache_dir so configs aren't swapped when CCACHE_DIR changes between steps
mkdir -p ~/.config/ccache
export CCACHE_CONFIGPATH="$HOME/.config/ccache/ccache.conf"
echo "CCACHE_CONFIGPATH=$CCACHE_CONFIGPATH" >> $GITHUB_ENV
# Configure ccache settings AFTER cache restore (prevents stale cached config)
ccache --set-config=max_size=${{ inputs.ccache_max_size }}
ccache --set-config=hash_dir=${{ inputs.ccache_hash_dir }}
@@ -130,10 +122,6 @@ runs:
export CXX="${{ inputs.cxx }}"
fi
if [ -n "${{ inputs.gcov }}" ]; then
ln -sf /usr/bin/${{ inputs.gcov }} /usr/local/bin/gcov
fi
# Create wrapper toolchain that overlays ccache on top of Conan's toolchain
# This enables ccache for the main app build without affecting Conan dependency builds
if [ "${{ inputs.ccache_enabled }}" = "true" ]; then
@@ -197,8 +185,7 @@ runs:
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${TOOLCHAIN_FILE} \
-DCMAKE_BUILD_TYPE=${{ inputs.configuration }} \
-Dtests=TRUE \
-Dxrpld=TRUE \
${{ inputs.cmake-args }}
-Dxrpld=TRUE
- name: Show ccache config before build
if: inputs.ccache_enabled == 'true'
@@ -222,7 +209,7 @@ runs:
VERBOSE_FLAG="-- -v"
fi
cmake --build . --config ${{ inputs.configuration }} --parallel $(nproc) --target ${{ inputs.cmake-target }} ${VERBOSE_FLAG}
cmake --build . --config ${{ inputs.configuration }} --parallel $(nproc) ${VERBOSE_FLAG}
- name: Show ccache statistics
if: inputs.ccache_enabled == 'true'

View File

@@ -145,9 +145,6 @@ runs:
# Export wasmedge if not already exported
conan list wasmedge/0.11.2@xahaud/stable 2>/dev/null | (grep -q "not found" && exit 1 || exit 0) || \
conan export external/wasmedge --version 0.11.2 --user xahaud --channel stable
# Keep the cached recipe in sync with this checkout; package binaries remain cached.
conan export external/wasmtime --version 47.0.3 --user xahaud --channel stable
- name: Install dependencies
shell: bash
env:
@@ -162,6 +159,4 @@ runs:
--output-folder . \
--build missing \
--settings build_type=${{ inputs.configuration }} \
--options '&:xrpld=True' \
--options '&:tests=True' \
..

View File

@@ -33,7 +33,6 @@ jobs:
fetch-depth: 2 # Only get the last 2 commits, to avoid fetching all history
build:
if: github.head_ref != 'jshookz'
runs-on: [self-hosted, xahaud-build]
needs: [checkout]
defaults:

View File

@@ -1,110 +0,0 @@
name: Check Genesis Hooks
on:
push:
pull_request:
jobs:
check-genesis-hooks:
runs-on: ubuntu-24.04
env:
CLANG_VERSION: 18
name: Verify xahau.h is in sync with genesis hooks
steps:
- name: Checkout repository
uses: actions/checkout@v6
# Install binaryen from GitHub Releases (pinned to version 100)
- name: Install binaryen (version 100)
run: |
curl -LO https://github.com/WebAssembly/binaryen/releases/download/version_100/binaryen-version_100-x86_64-linux.tar.gz
tar -xzf binaryen-version_100-x86_64-linux.tar.gz
sudo cp binaryen-version_100/bin/* /usr/local/bin/
wasm-opt --version
- name: Install clang-format
run: |
codename=$( lsb_release --codename --short )
sudo tee /etc/apt/sources.list.d/llvm.list >/dev/null <<EOF
deb http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-${CLANG_VERSION} main
deb-src http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-${CLANG_VERSION} main
EOF
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add
sudo apt-get update
sudo apt-get install clang-format-${CLANG_VERSION}
clang-format --version
# Install wasienv (WebAssembly SDK)
- name: Install wasienv
run: |
# Download install.sh
curl -o /tmp/wasienv-install.sh https://raw.githubusercontent.com/wasienv/wasienv/master/install.sh
# Replace /bin to /local/bin
sed -i 's|/bin|/local/bin|g' /tmp/wasienv-install.sh
# Execute the installed script
bash /tmp/wasienv-install.sh
# Add wasienv to PATH for subsequent steps
- name: Setup wasienv
run: |
echo "$HOME/.wasienv/bin" >> $GITHUB_PATH
wasmcc -v || true
# Build and install hook-cleaner tool
- name: Build and install hook-cleaner
run: |
git clone https://github.com/richardah/hook-cleaner-c.git /tmp/hook-cleaner
cd /tmp/hook-cleaner
make
cp hook-cleaner /usr/local/bin/
chmod +x /usr/local/bin/hook-cleaner
# Build and install guard_checker tool
- name: Build and install guard_checker
run: |
cd include/xrpl/hook
make
cp guard_checker /usr/local/bin/
chmod +x /usr/local/bin/guard_checker
# Verify all required tools are available
- name: Verify required tools
run: |
echo "Checking tool availability..."
command -v wasmcc || (echo "Error: wasmcc not found" && exit 1)
command -v wasm-opt || (echo "Error: wasm-opt not found" && exit 1)
command -v hook-cleaner || (echo "Error: hook-cleaner not found" && exit 1)
command -v guard_checker || (echo "Error: guard_checker not found" && exit 1)
command -v xxd || (echo "Error: xxd not found" && exit 1)
command -v clang-format || (echo "Error: clang-format not found" && exit 1)
echo "All tools verified successfully"
- name: Verify independent Wasmtime host catalogue fixture
run: src/test/app/jshooks/raw-catalogue/generate.py --check
# Execute build script to regenerate xahau.h
- name: Run build_xahau_h.sh
run: |
cd hook/genesis
./build_xahau_h.sh
# Check if xahau.h has changed (fail if out of sync)
- name: Verify xahau.h is in sync
run: |
if ! git diff --exit-code include/xrpl/hook/xahau.h; then
echo ""
echo "❌ ERROR: xahau.h is out of sync with genesis hooks"
echo ""
echo "The generated xahau.h differs from the committed version."
echo "Please run the following command and commit the changes:"
echo ""
echo " cd hook/genesis && ./build_xahau_h.sh"
echo ""
echo "Diff:"
git diff include/xrpl/hook/xahau.h
exit 1
fi
echo "✅ xahau.h is in sync with genesis hooks"

View File

@@ -20,7 +20,7 @@ jobs:
sudo apt-get update
sudo apt-get install clang-format-${CLANG_VERSION}
- name: Format first-party sources
run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} +
run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -not -path "src/magic/magic_enum.h" -exec clang-format-${CLANG_VERSION} -i {} +
- name: Check for differences
id: assert
run: |

View File

@@ -1,236 +0,0 @@
# End-to-end proof for the external jshookz toolchain and real Xahau Env.
name: JSHookz end to end
on:
push:
branches: [jshookz]
# PRs targeting jshookz/dev currently duplicate the branch-push e2e
# (different github.ref, so concurrency does not cancel). Re-enable later.
workflow_dispatch:
permissions:
contents: read
id-token: write
concurrency:
group: jshookz-e2e-${{ github.ref }}
cancel-in-progress: true
env:
JSHOOKZ_REF: xahaud-pinned
HOOKZ_REF: 846f5f0f80861985dceb41ad6f02ff914f8a0c3d
XAHAUD_SCRIPTS_REF: e41a712c68a613d95a8911cbf89711db2d95aa3b
WASI_SDK_VERSION: "32"
WASI_SDK_SHA256: 55fc523ebfbc98f69d1034fcfcb83d1ff5610cd9ab7eceef6cd097a30ba4ef93
BINARYEN_VERSION: "128"
BINARYEN_SHA256: 4ce79586d1c4762502eebe9a1db071fa5e446ef8897f2f766eb1cce5ec6dee9e
WIZER_VERSION: "10.0.0"
WIZER_SHA256: 1e9dfaa2f6c436ca7acfdbb82c166f5b8a0062068f12916a554e82c97ca8d371
WASI_SDK_PATH: ${{ github.workspace }}/.tools/wasi-sdk
HOOKZ_WASI_SDK: ${{ github.workspace }}/.tools/wasi-sdk
BINARYEN_HOME: ${{ github.workspace }}/.tools/binaryen
JSHOOKZ_PROVIDER_BUNDLE: ${{ github.workspace }}/.deps/jshookz/build/xahau-provider
XAHAU_QJS_PROVIDER_WASM: ${{ github.workspace }}/.deps/jshookz/build/xahau-provider/jshookz_provider.wasm
XAHAU_REQUIRE_QJS_PROVIDER_TESTS: "1"
CC: gcc-13
CXX: g++-13
CCACHE_DIR: /github/home/.ccache-cache
CMAKE_BUILD_PARALLEL_LEVEL: "2"
jobs:
env-proof:
runs-on: [self-hosted, generic, 20.04]
timeout-minutes: 120
container:
image: ubuntu:24.04
volumes:
- /home/runner/.conan-cache:/.conan-cache
- /home/runner/.ccache-cache:/github/home/.ccache-cache
defaults:
run:
shell: bash
steps:
- name: Install checkout prerequisite
run: |
apt-get update
apt-get install -y git
- name: Check out Xahau integration
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Check out public jshookz
uses: actions/checkout@v4
with:
repository: sublimator/jshookz
ref: ${{ env.JSHOOKZ_REF }}
path: .deps/jshookz
persist-credentials: false
- name: Check out public hookz
uses: actions/checkout@v4
with:
repository: sublimator/hookz
ref: ${{ env.HOOKZ_REF }}
path: .deps/hookz
persist-credentials: false
- name: Check out public xahaud-scripts
uses: actions/checkout@v4
with:
repository: sublimator/xahaud-scripts
ref: ${{ env.XAHAUD_SCRIPTS_REF }}
path: .deps/xahaud-scripts
persist-credentials: false
- uses: astral-sh/setup-uv@v7
- uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install native and TypeScript tools
run: |
apt-get install -y \
build-essential ccache clang-format-18 cmake curl g++-13 gcc-13 \
libsqlite3-dev ninja-build pkg-config xz-utils
ln -sf /usr/bin/clang-format-18 /usr/local/bin/clang-format
ln -sf /usr/bin/gcov-13 /usr/local/bin/gcov
npm install --global typescript@6.0.3
uv python install 3.13
uv tool install --python 3.13 conan==2.21.0
uv tool install --python 3.13 'gcovr>=7,<9'
- name: Install wasi-sdk and Binaryen
run: |
mkdir -p .tools
curl --fail --location --retry 3 \
--output /tmp/wasi-sdk.tar.gz \
"https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-x86_64-linux.tar.gz"
echo "$WASI_SDK_SHA256 /tmp/wasi-sdk.tar.gz" | sha256sum --check
tar -xzf /tmp/wasi-sdk.tar.gz -C .tools
mv ".tools/wasi-sdk-${WASI_SDK_VERSION}.0-x86_64-linux" "$WASI_SDK_PATH"
curl --fail --location --retry 3 \
--output /tmp/binaryen.tar.gz \
"https://github.com/WebAssembly/binaryen/releases/download/version_${BINARYEN_VERSION}/binaryen-version_${BINARYEN_VERSION}-x86_64-linux.tar.gz"
echo "$BINARYEN_SHA256 /tmp/binaryen.tar.gz" | sha256sum --check
tar -xzf /tmp/binaryen.tar.gz -C .tools
mv ".tools/binaryen-version_${BINARYEN_VERSION}" "$BINARYEN_HOME"
echo "$BINARYEN_HOME/bin" >> "$GITHUB_PATH"
- name: Install Wizer
run: |
curl --fail --location --retry 3 \
--output /tmp/wizer.tar.xz \
"https://github.com/bytecodealliance/wizer/releases/download/v${WIZER_VERSION}/wizer-v${WIZER_VERSION}-x86_64-linux.tar.xz"
echo "$WIZER_SHA256 /tmp/wizer.tar.xz" | sha256sum --check
tar -xJf /tmp/wizer.tar.xz -C .tools
echo "$GITHUB_WORKSPACE/.tools/wizer-v${WIZER_VERSION}-x86_64-linux" >> "$GITHUB_PATH"
- name: Install the Hook toolchain
run: |
if [ -f .deps/jshookz/python/jshookz/pyproject.toml ]; then
jshookz_project=.deps/jshookz/python/jshookz
else
jshookz_project=.deps/jshookz/packages/jshookz
fi
uv sync --project "$jshookz_project" \
--locked --group dev --python 3.13
uv tool install --python 3.13 --force --from .deps/hookz hookz
uv tool install --python 3.13 --force \
--from .deps/xahaud-scripts xahaud-scripts
jshookz_cmd="$jshookz_project/.venv/bin/jshookz"
echo "JSHOOKZ_CMD=$jshookz_cmd" >> "$GITHUB_ENV"
echo "JSHOOKZ_HOOK_COMPILER=$jshookz_cmd compile-hook" >> "$GITHUB_ENV"
"$jshookz_cmd" info
hookz --version
x-run-tests --help >/dev/null
- name: Build and verify the sealed provider
run: |
"$JSHOOKZ_CMD" build provider
test -s "$XAHAU_QJS_PROVIDER_WASM"
cmp external/quickjs-provider/jshookz_provider.manifest.json \
"$JSHOOKZ_PROVIDER_BUNDLE/jshookz_provider.manifest.json"
cmp external/quickjs-provider/jshookz_provider.manifest.cmake \
"$JSHOOKZ_PROVIDER_BUNDLE/jshookz_provider.manifest.cmake"
cmp external/quickjs-provider/jshookz_provider.native-abi.json \
"$JSHOOKZ_PROVIDER_BUNDLE/jshookz_provider.native-abi.json"
cp "$XAHAU_QJS_PROVIDER_WASM" \
external/quickjs-provider/jshookz_provider.wasm
- name: Prove generator-lock mutation reds
run: python3 cmake/test_generate_quickjs_provider_bundle.py
- name: Configure Conan for Xahau
run: |
mkdir -p \
/.conan-cache/conan2 \
/.conan-cache/conan2_download \
/.conan-cache/conan2_sources
mkdir -p "$HOME/.conan2"
printf '%s\n' \
'core.cache:storage_path=/.conan-cache/conan2' \
'core.download:download_cache=/.conan-cache/conan2_download' \
'core.sources:download_cache=/.conan-cache/conan2_sources' \
> "$HOME/.conan2/global.conf"
mkdir -p "$HOME/.conan2/profiles"
cat > "$HOME/.conan2/profiles/default" <<'EOF'
[settings]
arch=x86_64
build_type=Debug
compiler=gcc
compiler.cppstd=20
compiler.libcxx=libstdc++11
compiler.version=13
os=Linux
[buildenv]
CC=/usr/bin/gcc-13
CXX=/usr/bin/g++-13
[conf]
tools.build:compiler_executables={"c": "/usr/bin/gcc-13", "cpp": "/usr/bin/g++-13"}
[options]
&:xrpld=True
&:tests=True
date/*:use_system_tz_db=True
EOF
conan remote add --force xrplf https://conan.ripplex.io
conan profile show
conan export external/snappy --version 1.1.10 \
--user xahaud --channel stable
conan export external/soci --version 4.0.3 \
--user xahaud --channel stable
conan export external/wasmedge --version 0.11.2 \
--user xahaud --channel stable
conan export external/wasmtime --version 47.0.3 \
--user xahaud --channel stable
- name: Build Xahau and run the authoritative Env suite
run: |
x-run-tests \
--compile-hooks src/test/app/JSHooks_test.cpp \
--build-type Coverage \
--build-dir build-jshookz-e2e \
--reconfigure-build \
--ccache \
-j 2 \
-- \
ripple.app.JSHooks,ripple.app.QuickJSHostPolicy,ripple.app.HookGuestMemory,ripple.app.HookAPI,ripple.app.HookWasmtimeHostCatalogue,ripple.app.HookArtifact
- name: Upload JSHookz coverage
uses: codecov/codecov-action@v5
with:
files: build-jshookz-e2e/coverage/coverage.json
fail_ci_if_error: true
disable_search: true
verbose: true
plugins: noop
use_oidc: true
- name: Verify the checked-in fixture header is current
run: git diff --exit-code -- src/test/app/JSHooks_test_hooks.h

View File

@@ -10,7 +10,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Check levelization
run: python Builds/levelization/levelization.py
run: Builds/levelization/levelization.sh
- name: Check for differences
id: assert
run: |
@@ -40,7 +40,7 @@ jobs:
To fix it, you can do one of two things:
1. Download and apply the patch generated as an artifact of this
job to your repo, commit, and push.
2. Run 'python Builds/levelization/levelization.py' in your repo,
2. Run './Builds/levelization/levelization.sh' in your repo,
commit, and push.
See Builds/levelization/README.md for more info.

View File

@@ -18,10 +18,6 @@ jobs:
generator: bash ./hook/generate_sfcodes.sh
- target: hook/tts.h
generator: ./hook/generate_tts.sh
- target: hook/ls_flags.h
generator: ./hook/generate_lsflags.sh
- target: hook/tx_flags.h
generator: ./hook/generate_txflags.sh
runs-on: ubuntu-24.04
env:
CLANG_VERSION: 18

View File

@@ -4,8 +4,7 @@ on:
push:
branches: ["dev", "candidate", "release"]
pull_request:
branches: ["**"]
types: [opened, synchronize, reopened, labeled, unlabeled]
branches: ["dev", "candidate", "release"]
schedule:
- cron: '0 0 * * *'
@@ -15,10 +14,6 @@ concurrency:
jobs:
test:
if: >
github.event_name != 'pull_request' ||
contains(fromJson('["dev","candidate","release"]'), github.base_ref) ||
contains(join(github.event.pull_request.labels.*.name, ','), 'ci-full-build')
strategy:
matrix:
generator:

View File

@@ -4,16 +4,9 @@ on:
push:
branches: ["dev", "candidate", "release"]
pull_request:
branches: ["**"]
types: [opened, synchronize, reopened, labeled, unlabeled]
branches: ["dev", "candidate", "release"]
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
inputs:
full_matrix:
description: "Force full matrix (6 configs)"
required: false
default: "false"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -21,10 +14,6 @@ concurrency:
jobs:
matrix-setup:
if: >
github.event_name != 'pull_request' ||
contains(fromJson('["dev","candidate","release"]'), github.base_ref) ||
contains(join(github.event.pull_request.labels.*.name, ','), 'ci-full-build')
runs-on: [self-hosted, generic, 20.04]
container: python:3-slim
outputs:
@@ -57,9 +46,8 @@ jobs:
"cc": "gcc-11",
"cxx": "g++-11",
"compiler_version": 11,
"stdlib": "default",
"configuration": "Debug",
"job_type": "build"
"stdlib": "libstdcxx",
"configuration": "Debug"
},
{
"compiler_id": "gcc-13-libstdcxx",
@@ -67,20 +55,8 @@ jobs:
"cc": "gcc-13",
"cxx": "g++-13",
"compiler_version": 13,
"stdlib": "default",
"configuration": "Debug",
"job_type": "build"
},
{
"compiler_id": "gcc-13-libstdcxx",
"compiler": "gcc",
"cc": "gcc-13",
"cxx": "g++-13",
"gcov": "gcov-13",
"compiler_version": 13,
"stdlib": "default",
"configuration": "Debug",
"job_type": "coverage"
"stdlib": "libstdcxx",
"configuration": "Debug"
},
{
"compiler_id": "clang-14-libstdcxx-gcc11",
@@ -90,8 +66,7 @@ jobs:
"compiler_version": 14,
"stdlib": "libstdcxx",
"clang_gcc_toolchain": 11,
"configuration": "Debug",
"job_type": "build"
"configuration": "Debug"
},
{
"compiler_id": "clang-16-libstdcxx-gcc13",
@@ -101,8 +76,7 @@ jobs:
"compiler_version": 16,
"stdlib": "libstdcxx",
"clang_gcc_toolchain": 13,
"configuration": "Debug",
"job_type": "build"
"configuration": "Debug"
},
{
"compiler_id": "clang-17-libcxx",
@@ -111,8 +85,7 @@ jobs:
"cxx": "clang++-17",
"compiler_version": 17,
"stdlib": "libcxx",
"configuration": "Debug",
"job_type": "build"
"configuration": "Debug"
},
{
# Clang 18 - testing if it's faster than Clang 17 with libc++
@@ -123,16 +96,14 @@ jobs:
"cxx": "clang++-18",
"compiler_version": 18,
"stdlib": "libcxx",
"configuration": "Debug",
"job_type": "build"
"configuration": "Debug"
}
]
# Minimal matrix for PRs and feature branches
minimal_matrix = [
full_matrix[1], # gcc-13 (middle-ground gcc)
full_matrix[2], # gcc-13 coverage
full_matrix[3] # clang-14 (mature, stable clang)
full_matrix[2] # clang-14 (mature, stable clang)
]
# Determine which matrix to use based on the target branch
@@ -140,7 +111,6 @@ jobs:
base_ref = "${{ github.base_ref }}" # For PRs, this is the target branch
event_name = "${{ github.event_name }}"
pr_title = """${{ steps.escape.outputs.title }}"""
pr_labels = """${{ join(github.event.pull_request.labels.*.name, ',') }}"""
pr_head_sha = "${{ github.event.pull_request.head.sha }}"
# Get commit message - for PRs, fetch via API since head_commit.message is empty
@@ -166,24 +136,11 @@ jobs:
print(f"Base ref: {base_ref}")
print(f"PR head SHA: {pr_head_sha}")
print(f"PR title: {pr_title}")
print(f"PR labels: {pr_labels}")
print(f"Commit message: {commit_message}")
# Manual trigger input to force full matrix.
manual_full = "${{ github.event.inputs.full_matrix || 'false' }}" == "true"
# Label/manual overrides, while preserving existing title/commit behavior.
force_full = (
manual_full
or "[ci-nix-full-matrix]" in commit_message
or "[ci-nix-full-matrix]" in pr_title
or ("ci-full-build" in pr_labels and "ci-nix-full-matrix" in pr_labels)
)
force_min = (
"ci-full-build" in pr_labels
)
# Check for override tags in commit message or PR title
force_full = "[ci-nix-full-matrix]" in commit_message or "[ci-nix-full-matrix]" in pr_title
print(f"Force full matrix: {force_full}")
print(f"Force min matrix: {force_min}")
# Check if this is targeting a main branch
# For PRs: check base_ref (target branch)
@@ -191,11 +148,8 @@ jobs:
main_branches = ["refs/heads/dev", "refs/heads/release", "refs/heads/candidate"]
if force_full:
# Override: always use full matrix if forced by manual input or label.
# Override: always use full matrix if tag is present
use_full = True
elif force_min:
# Override: always use minimal matrix if ci-full-build label is present.
use_full = False
elif event_name == "pull_request":
# For PRs, base_ref is just the branch name (e.g., "dev", not "refs/heads/dev")
# Check if the PR targets release or candidate (more critical branches)
@@ -207,21 +161,14 @@ jobs:
# Select the appropriate matrix
if use_full:
if force_full:
print(f"Using FULL matrix (7 configs) - forced by [ci-nix-full-matrix] tag")
print(f"Using FULL matrix (6 configs) - forced by [ci-nix-full-matrix] tag")
else:
print(f"Using FULL matrix (7 configs) - targeting main branch")
print(f"Using FULL matrix (6 configs) - targeting main branch")
matrix = full_matrix
else:
print(f"Using MINIMAL matrix (3 configs) - feature branch/PR")
print(f"Using MINIMAL matrix (2 configs) - feature branch/PR")
matrix = minimal_matrix
# Add runs_on based on job_type
for entry in matrix:
if entry.get("job_type") == "coverage":
entry["runs_on"] = '["self-hosted", "generic", 24.04]'
else:
entry["runs_on"] = '["self-hosted", "generic", 20.04]'
# Output the matrix as JSON
output = json.dumps({"include": matrix})
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
@@ -229,10 +176,7 @@ jobs:
build:
needs: matrix-setup
runs-on: ${{ fromJSON(matrix.runs_on) }}
permissions:
id-token: write
contents: read
runs-on: [self-hosted, generic, 20.04]
container:
image: ubuntu:24.04
volumes:
@@ -261,7 +205,7 @@ jobs:
apt-get install -y software-properties-common
add-apt-repository ppa:ubuntu-toolchain-r/test -y
apt-get update
apt-get install -y git python3 python-is-python3 pipx
apt-get install -y python3 python-is-python3 pipx
pipx ensurepath
apt-get install -y cmake ninja-build ${{ matrix.cc }} ${{ matrix.cxx }} ccache
apt-get install -y perl # for openssl build
@@ -332,12 +276,6 @@ jobs:
pipx install "conan>=2.0,<3"
echo "$HOME/.local/bin" >> $GITHUB_PATH
# Install gcovr for coverage jobs
if [ "${{ matrix.job_type }}" = "coverage" ]; then
pipx install "gcovr>=7,<9"
apt-get install -y curl lcov
fi
- name: Check environment
run: |
echo "PATH:"
@@ -347,13 +285,6 @@ jobs:
which ${{ matrix.cc }} && ${{ matrix.cc }} --version || echo "${{ matrix.cc }} not found"
which ${{ matrix.cxx }} && ${{ matrix.cxx }} --version || echo "${{ matrix.cxx }} not found"
which ccache && ccache --version || echo "ccache not found"
# Check gcovr for coverage jobs
if [ "${{ matrix.job_type }}" = "coverage" ]; then
which gcov && gcov --version || echo "gcov not found"
which gcovr && gcovr --version || echo "gcovr not found"
fi
echo "---- Full Environment ----"
env
@@ -381,7 +312,6 @@ jobs:
gha_cache_enabled: 'false' # Disable caching for self hosted runner
- name: Build
if: matrix.job_type == 'build'
uses: ./.github/actions/xahau-ga-build
with:
generator: Ninja
@@ -396,27 +326,7 @@ jobs:
clang_gcc_toolchain: ${{ matrix.clang_gcc_toolchain || '' }}
ccache_max_size: '100G'
- name: Build (Coverage)
if: matrix.job_type == 'coverage'
uses: ./.github/actions/xahau-ga-build
with:
generator: Ninja
configuration: ${{ matrix.configuration }}
build_dir: ${{ env.build_dir }}
cc: ${{ matrix.cc }}
cxx: ${{ matrix.cxx }}
gcov: ${{ matrix.gcov }}
compiler-id: ${{ matrix.compiler_id }}
cache_version: ${{ env.CACHE_VERSION }}
main_branch: ${{ env.MAIN_BRANCH_NAME }}
stdlib: ${{ matrix.stdlib }}
# Coverage builds are slower due to instrumentation; use fewer parallel jobs to avoid flakiness
cmake-args: '-Dcoverage=ON -Dcoverage_format=xml -Dcoverage_test_parallelism=$(($(nproc)/2)) -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_CXX_FLAGS="-O0" -DCMAKE_C_FLAGS="-O0"'
cmake-target: 'coverage'
ccache_max_size: '100G'
- name: Set artifact name
if: matrix.job_type == 'build'
id: set-artifact-name
run: |
ARTIFACT_NAME="build-output-nix-${{ github.run_id }}-${{ matrix.compiler }}-${{ matrix.configuration }}"
@@ -429,7 +339,6 @@ jobs:
ls -la ${{ env.build_dir }} || echo "Build directory not found or empty"
- name: Run tests
if: matrix.job_type == 'build'
run: |
# Ensure the binary exists before trying to run
if [ -f "${{ env.build_dir }}/rippled" ]; then
@@ -438,42 +347,3 @@ jobs:
echo "Error: rippled executable not found in ${{ env.build_dir }}"
exit 1
fi
# Coverage-specific steps
- name: Move coverage report
if: matrix.job_type == 'coverage'
shell: bash
run: |
mv "${{ env.build_dir }}/coverage.xml" ./
- name: Archive coverage report
if: matrix.job_type == 'coverage'
uses: actions/upload-artifact@v4
with:
name: coverage.xml
path: coverage.xml
retention-days: 30
- name: Upload coverage report
if: matrix.job_type == 'coverage'
uses: codecov/codecov-action@v5
with:
files: coverage.xml
fail_ci_if_error: true
disable_search: true
verbose: true
plugins: noop
use_oidc: true
- name: Export server definitions
if: matrix.job_type == 'build' && matrix.compiler_id == 'gcc-13-libstdcxx'
run: |
${{ env.build_dir }}/rippled --definitions | python3 -m json.tool > server_definitions.json
- name: Upload server definitions
if: matrix.job_type == 'build' && matrix.compiler_id == 'gcc-13-libstdcxx'
uses: actions/upload-artifact@v7
with:
name: server-definitions
path: server_definitions.json
archive: false

4
.gitignore vendored
View File

@@ -53,9 +53,6 @@ Builds/levelization/results/paths.txt
Builds/levelization/results/includes/
Builds/levelization/results/includedby/
# Python
__pycache__
# Ignore tmp directory.
tmp
@@ -79,7 +76,6 @@ docs/html_doc
# Xcode
.DS_Store
*/build/*
!/docs/build/
*.pbxuser
!default.pbxuser
*.mode1v3

2
.mise.toml Normal file
View File

@@ -0,0 +1,2 @@
[tools]
clang-format = "18"

View File

@@ -10,7 +10,7 @@
## Branches
For a stable release, choose the `master` branch or one of the [tagged
releases](https://github.com/Xahau/xahaud/releases).
releases](https://github.com/ripple/rippled/releases).
```
git checkout master
@@ -35,11 +35,17 @@ See [System Requirements](https://xrpl.org/system-requirements.html).
Building rippled generally requires git, Python, Conan, CMake, and a C++ compiler. Some guidance on setting up such a [C++ development environment can be found here](./docs/build/environment.md).
- [Python 3.7](https://www.python.org/downloads/) (configure also uses it to project the QuickJS provider)
- [Python 3.7](https://www.python.org/downloads/)
- [Conan 2.x](https://conan.io/downloads)
- [CMake 3.16](https://cmake.org/download/)
`xahaud` is written in the C++20 dialect and includes the `<concepts>` header.
[^1]: It is possible to build with Conan 2.x,
but the instructions are significantly different,
which is why we are not recommending it yet.
Notably, the `conan profile update` command is removed in 2.x.
Profiles must be edited by hand.
`rippled` is written in the C++20 dialect and includes the `<concepts>` header.
The [minimum compiler versions][2] required are:
| Compiler | Version |
@@ -58,19 +64,17 @@ Here are [sample instructions for setting up a C++ development environment on Li
### Mac
Many xahaud engineers use macOS for development.
Many rippled engineers use macOS for development.
Here are [sample instructions for setting up a C++ development environment on macOS](./docs/build/environment.md#macos).
### Windows
We don't recommend Windows for `xahaud` production at this time. As of
November 2025, Ubuntu has the highest level of quality assurance, testing,
and support.
Windows is not recommended for production use at this time.
Windows developers should use Visual Studio 2019. `xahaud` isn't
compatible with [Boost](https://www.boost.org/) 1.78 or 1.79, and Conan
can't build earlier Boost versions.
- Additionally, 32-bit Windows development is not supported.
[Boost]: https://www.boost.org/
## Steps
@@ -140,8 +144,8 @@ conan profile show default
An easy way to do that is to run the shortcut "x64 Native Tools Command
Prompt" for the version of Visual Studio that you have installed.
Windows developers must also build `xahaud` and its dependencies for the x64
architecture.
Windows developers must also build `rippled` and its dependencies for the x64
architecture:
```
# In ~/.conan2/profiles/default, ensure:
@@ -149,7 +153,10 @@ Prompt" for the version of Visual Studio that you have installed.
arch=x86_64
```
### Multiple compilers
3. (Optional) If you have multiple compilers installed on your platform,
make sure that Conan and CMake select the one you want to use.
This setting will set the correct variables (`CMAKE_<LANG>_COMPILER`)
in the generated CMake toolchain file.
```
# In ~/.conan2/profiles/default, add under [conf] section:
@@ -166,17 +173,9 @@ Prompt" for the version of Visual Studio that you have installed.
CXX=<path>
```
It should choose the compiler for dependencies as well,
but not all of them have a Conan recipe that respects this setting (yet).
For the rest, you can set these environment variables.
Replace `<path>` with paths to the desired compilers:
- `conan profile update env.CC=<path> default`
- `conan profile update env.CXX=<path> default`
Export our [Conan recipe for Snappy](./external/snappy).
It does not explicitly link the C++ standard library,
which allows you to statically link it with GCC, if you want.
4. Export our [Conan recipe for Snappy](./external/snappy).
It doesn't explicitly link the C++ standard library,
which allows you to statically link it with GCC, if you want.
```
conan export external/snappy --version 1.1.10 --user xahaud --channel stable
@@ -185,16 +184,6 @@ which allows you to statically link it with GCC, if you want.
Export our [Conan recipe for RocksDB](./external/rocksdb).
It does not override paths to dependencies when building with Visual Studio.
```
# Conan 1.x
conan export external/rocksdb rocksdb/6.29.5@
# Conan 2.x
conan export --version 6.29.5 external/rocksdb
```
Export our [Conan recipe for SOCI](./external/soci).
It patches their CMake to correctly import its dependencies.
```
conan export external/soci --version 4.0.3 --user xahaud --channel stable
```
@@ -205,17 +194,6 @@ It patches their CMake to correctly import its dependencies.
conan export external/wasmedge --version 0.11.2 --user xahaud --channel stable
```
Export our [Conan recipe for NuDB](./external/nudb).
It fixes some source files to add missing `#include`s.
```
# Conan 1.x
conan export external/nudb nudb/2.0.8@
# Conan 2.x
conan export --version 2.0.8 external/nudb
```
### Build and Test
1. Create a build directory and move into it.
@@ -289,14 +267,13 @@ It fixes some source files to add missing `#include`s.
cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -Dxrpld=ON -Dtests=ON ..
```
**Note:** You can pass build options for `xahaud` in this step.
**Note:** You can pass build options for `rippled` in this step.
4. Build `xahaud`.
5. Build `rippled`.
For a single-configuration generator, it will build whatever configuration
you passed for `CMAKE_BUILD_TYPE`. For a multi-configuration generator,
you must pass the option `--config` to select the build configuration.
The output file is currently named 'rippled'.
Single-config generators:
@@ -311,7 +288,7 @@ It fixes some source files to add missing `#include`s.
cmake --build . --config Debug
```
5. Test xahaud.
6. Test rippled.
Single-config generators:
@@ -326,7 +303,7 @@ It fixes some source files to add missing `#include`s.
./Debug/rippled --unittest
```
The location of `xahaud` in your build directory depends on your CMake
The location of `rippled` in your build directory depends on your CMake
generator. Pass `--help` to see the rest of the command line options.

View File

@@ -50,7 +50,7 @@ that `test` code should *never* be included in `ripple` code.)
## Validation
The [levelization.py](levelization.py) script takes no parameters,
The [levelization.sh](levelization.sh) script takes no parameters,
reads no environment variables, and can be run from any directory,
as long as it is in the expected location in the rippled repo.
It can be run at any time from within a checked out repo, and will
@@ -84,7 +84,7 @@ It generates many files of [results](results):
Github Actions workflow to test that levelization loops haven't
changed. Unfortunately, if changes are detected, it can't tell if
they are improvements or not, so if you have resolved any issues or
done anything else to improve levelization, run `levelization.py`,
done anything else to improve levelization, run `levelization.sh`,
and commit the updated results.
The `loops.txt` and `ordering.txt` files relate the modules
@@ -108,7 +108,7 @@ The committed files hide the detailed values intentionally, to
prevent false alarms and merging issues, and because it's easy to
get those details locally.
1. Run `levelization.py`
1. Run `levelization.sh`
2. Grep the modules in `paths.txt`.
* For example, if a cycle is found `A ~= B`, simply `grep -w
A Builds/levelization/results/paths.txt | grep -w B`

View File

@@ -1,283 +0,0 @@
#!/usr/bin/env python3
"""
Usage: levelization.py
This script takes no parameters, and can be called from any directory in the file system.
"""
import os
import re
import sys
from collections import defaultdict
from pathlib import Path
# Compile regex patterns once at module level
INCLUDE_PATTERN = re.compile(r"^\s*#include.*/.*\.h")
INCLUDE_PATH_PATTERN = re.compile(r'[<"]([^>"]+)[>"]')
def dictionary_sort_key(s):
"""
Create a sort key that mimics 'sort -d' (dictionary order).
Dictionary order only considers blanks and alphanumeric characters.
"""
return "".join(c for c in s if c.isalnum() or c.isspace())
def get_level(file_path):
"""
Extract the level from a file path (second and third directory components).
Equivalent to bash: cut -d/ -f 2,3
Examples:
src/ripple/app/main.cpp -> ripple.app
src/test/app/Import_test.cpp -> test.app
"""
parts = file_path.split("/")
if len(parts) >= 3:
level = f"{parts[1]}/{parts[2]}"
elif len(parts) >= 2:
level = f"{parts[1]}/toplevel"
else:
level = file_path
# If the "level" indicates a file, cut off the filename
if "." in level.split("/")[-1]:
# Use the "toplevel" label as a workaround for `sort`
# inconsistencies between different utility versions
level = level.rsplit("/", 1)[0] + "/toplevel"
return level.replace("/", ".")
def extract_include_level(include_line):
"""
Extract the include path from an #include directive.
Gets the first two directory components from the include path.
Equivalent to bash: cut -d/ -f 1,2
Examples:
#include <ripple/basics/base_uint.h> -> ripple.basics
#include "ripple/app/main/Application.h" -> ripple.app
"""
match = INCLUDE_PATH_PATTERN.search(include_line)
if not match:
return None
include_path = match.group(1)
parts = include_path.split("/")
if len(parts) >= 2:
include_level = f"{parts[0]}/{parts[1]}"
else:
include_level = include_path
# If the "includelevel" indicates a file, cut off the filename
if "." in include_level.split("/")[-1]:
include_level = include_level.rsplit("/", 1)[0] + "/toplevel"
return include_level.replace("/", ".")
def find_repository_directories(start_path, depth_limit=10):
"""
Find the repository root by looking for src or include folders.
Walks up the directory tree from the start path.
"""
current = start_path.resolve()
for _ in range(depth_limit):
src_path = current / "src"
include_path = current / "include"
has_src = src_path.exists()
has_include = include_path.exists()
if has_src or has_include:
dirs = []
if has_src:
dirs.append(src_path)
if has_include:
dirs.append(include_path)
return current, dirs
parent = current.parent
if parent == current:
break
current = parent
raise RuntimeError(
"Could not find repository root. "
"Expected to find a directory containing 'src' and/or 'include' folders."
)
def main():
script_dir = Path(__file__).parent.resolve()
os.chdir(script_dir)
# Clean up and create results directory.
results_dir = script_dir / "results"
if results_dir.exists():
import shutil
shutil.rmtree(results_dir)
results_dir.mkdir()
# Find the repository root.
try:
repo_root, scan_dirs = find_repository_directories(script_dir)
print(f"Found repository root: {repo_root}")
for scan_dir in scan_dirs:
print(f" Scanning: {scan_dir.relative_to(repo_root)}")
except RuntimeError as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
# Find all #include directives.
print("\nScanning for raw includes...")
raw_includes = []
rawincludes_file = results_dir / "rawincludes.txt"
with open(rawincludes_file, "w", buffering=8192) as raw_f:
for dir_path in scan_dirs:
for file_path in dir_path.rglob("*"):
if not file_path.is_file():
continue
try:
rel_path_str = str(file_path.relative_to(repo_root))
with open(
file_path, "r", encoding="utf-8", errors="ignore", buffering=8192
) as f:
for line in f:
if "#include" not in line or "boost" in line:
continue
if INCLUDE_PATTERN.match(line):
line_stripped = line.strip()
entry = f"{rel_path_str}:{line_stripped}\n"
print(entry, end="")
raw_f.write(entry)
raw_includes.append((rel_path_str, line_stripped))
except Exception as e:
print(f"Error reading {file_path}: {e}", file=sys.stderr)
# Build levelization paths and count directly.
print("Build levelization paths")
path_counts = defaultdict(int)
for file_path, include_line in raw_includes:
include_level = extract_include_level(include_line)
if not include_level:
continue
level = get_level(file_path)
if level != include_level:
path_counts[(level, include_level)] += 1
# Sort and deduplicate paths.
print("Sort and deduplicate paths")
sorted_items = sorted(
path_counts.items(),
key=lambda x: (dictionary_sort_key(x[0][0]), dictionary_sort_key(x[0][1])),
)
paths_file = results_dir / "paths.txt"
with open(paths_file, "w") as f:
for (level, include_level), count in sorted_items:
line = f"{count:7} {level} {include_level}\n"
print(line.rstrip())
f.write(line)
# Split into flat-file database.
print("Split into flat-file database")
includes_dir = results_dir / "includes"
includedby_dir = results_dir / "includedby"
includes_dir.mkdir()
includedby_dir.mkdir()
includes_data = defaultdict(list)
includedby_data = defaultdict(list)
for (level, include_level), count in sorted_items:
includes_data[level].append((include_level, count))
includedby_data[include_level].append((level, count))
for level in sorted(includes_data.keys(), key=dictionary_sort_key):
with open(includes_dir / level, "w") as f:
for include_level, count in includes_data[level]:
line = f"{include_level} {count}\n"
print(line.rstrip())
f.write(line)
for include_level in sorted(includedby_data.keys(), key=dictionary_sort_key):
with open(includedby_dir / include_level, "w") as f:
for level, count in includedby_data[include_level]:
line = f"{level} {count}\n"
print(line.rstrip())
f.write(line)
# Search for loops.
print("Search for loops")
loops_file = results_dir / "loops.txt"
ordering_file = results_dir / "ordering.txt"
# Pre-load all include files into memory for fast lookup.
includes_cache = {}
includes_lookup = {}
for include_file in sorted(includes_dir.iterdir(), key=lambda p: p.name):
if not include_file.is_file():
continue
includes_cache[include_file.name] = []
includes_lookup[include_file.name] = {}
with open(include_file, "r") as f:
for line in f:
parts = line.strip().split()
if len(parts) >= 2:
name, count = parts[0], int(parts[1])
includes_cache[include_file.name].append((name, count))
includes_lookup[include_file.name][name] = count
loops_found = set()
with open(loops_file, "w", buffering=8192) as loops_f, open(
ordering_file, "w", buffering=8192
) as ordering_f:
for source in sorted(includes_cache.keys()):
for include, include_freq in includes_cache[source]:
if include not in includes_lookup:
continue
source_freq = includes_lookup[include].get(source)
if source_freq is not None:
loop_key = tuple(sorted([source, include]))
if loop_key in loops_found:
continue
loops_found.add(loop_key)
loops_f.write(f"Loop: {source} {include}\n")
diff = include_freq - source_freq
if diff > 3:
loops_f.write(f" {source} > {include}\n\n")
elif diff < -3:
loops_f.write(f" {include} > {source}\n\n")
elif source_freq == include_freq:
loops_f.write(f" {include} == {source}\n\n")
else:
loops_f.write(f" {include} ~= {source}\n\n")
else:
ordering_f.write(f"{source} > {include}\n")
# Print results.
print("\nOrdering:")
with open(ordering_file, "r") as f:
print(f.read(), end="")
print("\nLoops:")
with open(loops_file, "r") as f:
print(f.read(), end="")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,130 @@
#!/bin/bash
# Usage: levelization.sh
# This script takes no parameters, reads no environment variables,
# and can be run from any directory, as long as it is in the expected
# location in the repo.
pushd $( dirname $0 )
if [ -v PS1 ]
then
# if the shell is interactive, clean up any flotsam before analyzing
git clean -ix
fi
# Ensure all sorting is ASCII-order consistently across platforms.
export LANG=C
rm -rfv results
mkdir results
includes="$( pwd )/results/rawincludes.txt"
pushd ../..
echo Raw includes:
grep -r '^[ ]*#include.*/.*\.h' include src | \
grep -v boost | tee ${includes}
popd
pushd results
oldifs=${IFS}
IFS=:
mkdir includes
mkdir includedby
echo Build levelization paths
exec 3< ${includes} # open rawincludes.txt for input
while read -r -u 3 file include
do
level=$( echo ${file} | cut -d/ -f 2,3 )
# If the "level" indicates a file, cut off the filename
if [[ "${level##*.}" != "${level}" ]]
then
# Use the "toplevel" label as a workaround for `sort`
# inconsistencies between different utility versions
level="$( dirname ${level} )/toplevel"
fi
level=$( echo ${level} | tr '/' '.' )
includelevel=$( echo ${include} | sed 's/.*["<]//; s/[">].*//' | \
cut -d/ -f 1,2 )
if [[ "${includelevel##*.}" != "${includelevel}" ]]
then
# Use the "toplevel" label as a workaround for `sort`
# inconsistencies between different utility versions
includelevel="$( dirname ${includelevel} )/toplevel"
fi
includelevel=$( echo ${includelevel} | tr '/' '.' )
if [[ "$level" != "$includelevel" ]]
then
echo $level $includelevel | tee -a paths.txt
fi
done
echo Sort and dedup paths
sort -ds paths.txt | uniq -c | tee sortedpaths.txt
mv sortedpaths.txt paths.txt
exec 3>&- #close fd 3
IFS=${oldifs}
unset oldifs
echo Split into flat-file database
exec 4<paths.txt # open paths.txt for input
while read -r -u 4 count level include
do
echo ${include} ${count} | tee -a includes/${level}
echo ${level} ${count} | tee -a includedby/${include}
done
exec 4>&- #close fd 4
loops="$( pwd )/loops.txt"
ordering="$( pwd )/ordering.txt"
pushd includes
echo Search for loops
# Redirect stdout to a file
exec 4>&1
exec 1>"${loops}"
for source in *
do
if [[ -f "$source" ]]
then
exec 5<"${source}" # open for input
while read -r -u 5 include includefreq
do
if [[ -f $include ]]
then
if grep -q -w $source $include
then
if grep -q -w "Loop: $include $source" "${loops}"
then
continue
fi
sourcefreq=$( grep -w $source $include | cut -d\ -f2 )
echo "Loop: $source $include"
# If the counts are close, indicate that the two modules are
# on the same level, though they shouldn't be
if [[ $(( $includefreq - $sourcefreq )) -gt 3 ]]
then
echo -e " $source > $include\n"
elif [[ $(( $sourcefreq - $includefreq )) -gt 3 ]]
then
echo -e " $include > $source\n"
elif [[ $sourcefreq -eq $includefreq ]]
then
echo -e " $include == $source\n"
else
echo -e " $include ~= $source\n"
fi
else
echo "$source > $include" >> "${ordering}"
fi
fi
done
exec 5>&- #close fd 5
fi
done
exec 1>&4 #close fd 1
exec 4>&- #close fd 4
cat "${ordering}"
cat "${loops}"
popd
popd
popd

View File

@@ -10,6 +10,9 @@ Loop: test.jtx test.toplevel
Loop: test.jtx test.unit_test
test.unit_test == test.jtx
Loop: xrpl.hook xrpld.app
xrpld.app > xrpl.hook
Loop: xrpl.protocol xrpld.app
xrpld.app > xrpl.protocol

View File

@@ -84,7 +84,6 @@ test.nodestore > xrpl.basics
test.nodestore > xrpld.core
test.nodestore > xrpld.nodestore
test.nodestore > xrpld.unity
test.nodestore > xrpl.protocol
test.overlay > test.jtx
test.overlay > test.toplevel
test.overlay > test.unit_test
@@ -119,7 +118,6 @@ test.rpc > xrpld.core
test.rpc > xrpld.net
test.rpc > xrpld.overlay
test.rpc > xrpld.rpc
test.rpc > xrpld.shamap
test.rpc > xrpl.hook
test.rpc > xrpl.json
test.rpc > xrpl.protocol
@@ -157,7 +155,6 @@ xrpld.app > xrpl.basics
xrpld.app > xrpld.conditions
xrpld.app > xrpld.consensus
xrpld.app > xrpld.perflog
xrpld.app > xrpl.hook
xrpld.app > xrpl.json
xrpld.app > xrpl.resource
xrpld.conditions > xrpl.basics

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.16)
cmake_minimum_required (VERSION 3.16)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -18,52 +18,41 @@ if(POLICY CMP0144)
cmake_policy(SET CMP0144 NEW)
endif()
project(xrpl)
project (xrpl)
set(Boost_NO_BOOST_CMAKE ON)
# make GIT_COMMIT_HASH define available to all sources
find_package(Git)
if(Git_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git
rev-parse HEAD
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE gch)
if(gch)
set(GIT_COMMIT_HASH "${gch}")
message(STATUS gch: ${GIT_COMMIT_HASH})
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
endif()
execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse HEAD
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gch)
if(gch)
set(GIT_COMMIT_HASH "${gch}")
message(STATUS gch: ${GIT_COMMIT_HASH})
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git
rev-parse --abbrev-ref HEAD
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE gb)
if(gb)
set(GIT_BRANCH "${gb}")
message(STATUS gb: ${GIT_BRANCH})
add_definitions(-DGIT_BRANCH="${GIT_BRANCH}")
endif()
endif() # git
execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse --abbrev-ref HEAD
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gb)
if(gb)
set(GIT_BRANCH "${gb}")
message(STATUS gb: ${GIT_BRANCH})
add_definitions(-DGIT_BRANCH="${GIT_BRANCH}")
endif()
endif() #git
# make SOURCE_ROOT_PATH define available for logging
set(SOURCE_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/src/")
add_definitions(-DSOURCE_ROOT_PATH="${SOURCE_ROOT_PATH}")
# BEAST_ENHANCED_LOGGING - adds file:line numbers and formatting to logs
# Automatically enabled for Debug builds via generator expression Can be
# explicitly controlled with -DBEAST_ENHANCED_LOGGING=ON/OFF
option(
BEAST_ENHANCED_LOGGING
"Include file and line numbers in log messages (auto: Debug=ON, Release=OFF)"
OFF)
# Automatically enabled for Debug builds via generator expression
# Can be explicitly controlled with -DBEAST_ENHANCED_LOGGING=ON/OFF
option(BEAST_ENHANCED_LOGGING "Include file and line numbers in log messages (auto: Debug=ON, Release=OFF)" OFF)
message(STATUS "BEAST_ENHANCED_LOGGING option: ${BEAST_ENHANCED_LOGGING}")
if(thread_safety_analysis)
add_compile_options(
-Wthread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
-DRIPPLE_ENABLE_THREAD_SAFETY_ANNOTATIONS)
add_compile_options(-Wthread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -DRIPPLE_ENABLE_THREAD_SAFETY_ANNOTATIONS)
add_compile_options("-stdlib=libc++")
add_link_options("-stdlib=libc++")
endif()
@@ -73,48 +62,40 @@ option(USE_CONAN "Use Conan package manager for dependencies" OFF)
if(CMAKE_TOOLCHAIN_FILE)
# Check if the toolchain file path contains "conan_toolchain"
if(CMAKE_TOOLCHAIN_FILE MATCHES "conan_toolchain")
set(USE_CONAN
ON
CACHE BOOL "Using Conan detected from toolchain file" FORCE)
set(USE_CONAN ON CACHE BOOL "Using Conan detected from toolchain file" FORCE)
message(STATUS "Conan toolchain detected: ${CMAKE_TOOLCHAIN_FILE}")
message(STATUS "Building with Conan dependencies")
endif()
endif()
include(CheckCXXCompilerFlag)
include(FetchContent)
include(ExternalProject)
include(CMakeFuncs) # must come *after* ExternalProject b/c it overrides one
# function in EP
if(target)
message(
FATAL_ERROR
"The target option has been removed - use native cmake options to control build"
)
endif()
include (CheckCXXCompilerFlag)
include (FetchContent)
include (ExternalProject)
include (CMakeFuncs) # must come *after* ExternalProject b/c it overrides one function in EP
if (target)
message (FATAL_ERROR "The target option has been removed - use native cmake options to control build")
endif ()
include(RippledSanity)
include(RippledVersion)
include(RippledSettings)
# this check has to remain in the top-level cmake because of the early return
# statement
if(packages_only)
if(NOT TARGET rpm)
message(
FATAL_ERROR
"packages_only requested, but targets were not created - is docker installed?"
)
# this check has to remain in the top-level cmake
# because of the early return statement
if (packages_only)
if (NOT TARGET rpm)
message (FATAL_ERROR "packages_only requested, but targets were not created - is docker installed?")
endif()
return()
endif()
return ()
endif ()
include(RippledCompiler)
include(RippledInterface)
include(deps/Boost)
find_package(OpenSSL 1.1.1 REQUIRED)
set_target_properties(OpenSSL::SSL PROPERTIES INTERFACE_COMPILE_DEFINITIONS
OPENSSL_NO_SSL2)
set_target_properties(OpenSSL::SSL PROPERTIES
INTERFACE_COMPILE_DEFINITIONS OPENSSL_NO_SSL2
)
set(SECP256K1_INSTALL TRUE)
add_subdirectory(external/secp256k1)
add_library(secp256k1::secp256k1 ALIAS secp256k1)
@@ -122,33 +103,25 @@ add_subdirectory(external/ed25519-donna)
add_subdirectory(external/antithesis-sdk)
find_package(gRPC REQUIRED)
find_package(lz4 REQUIRED)
# Target names with :: are not allowed in a generator expression. We need to
# pull the include directories and imported location properties from separate
# targets.
# Target names with :: are not allowed in a generator expression.
# We need to pull the include directories and imported location properties
# from separate targets.
find_package(LibArchive REQUIRED)
find_package(SOCI REQUIRED)
find_package(SQLite3 REQUIRED)
include(deps/WasmEdge)
option(rocksdb "Enable RocksDB" ON)
if(rocksdb)
find_package(RocksDB REQUIRED)
set_target_properties(
RocksDB::rocksdb PROPERTIES INTERFACE_COMPILE_DEFINITIONS
RIPPLE_ROCKSDB_AVAILABLE=1)
set_target_properties(RocksDB::rocksdb PROPERTIES
INTERFACE_COMPILE_DEFINITIONS RIPPLE_ROCKSDB_AVAILABLE=1
)
target_link_libraries(ripple_libs INTERFACE RocksDB::rocksdb)
endif()
find_package(nudb REQUIRED)
find_package(date REQUIRED)
find_package(xxHash REQUIRED)
find_package(magic_enum REQUIRED)
include(deps/WasmEdge)
if(xrpld)
include(deps/Wasmtime)
include(QuickJSProvider)
endif()
if(TARGET nudb::core)
if(TARGET nudb::core)
set(nudb nudb::core)
elseif(TARGET NuDB::nudb)
set(nudb NuDB::nudb)
@@ -157,16 +130,17 @@ else()
endif()
target_link_libraries(ripple_libs INTERFACE ${nudb})
target_link_libraries(
ripple_libs
INTERFACE ed25519::ed25519
LibArchive::LibArchive
lz4::lz4
OpenSSL::Crypto
OpenSSL::SSL
secp256k1::secp256k1
soci::soci
SQLite::SQLite3)
target_link_libraries(ripple_libs INTERFACE
ed25519::ed25519
lz4::lz4
OpenSSL::Crypto
OpenSSL::SSL
# Ripple::grpc_pbufs
# Ripple::pbufs
secp256k1::secp256k1
soci::soci
SQLite::SQLite3
)
if(coverage)
include(RippledCov)

View File

@@ -57,12 +57,12 @@ Ensure that your code compiles according to the build instructions in the
[`documentation`](https://docs.xahau.network/infrastructure/building-xahau).
If you create new source files, they must go under `src/ripple`.
You will need to add them to one of the
[source lists](./Builds/CMake/RippledCore.cmake) in CMake.
[source lists](./cmake/RippledCore.cmake) in CMake.
Please write tests for your code.
If you create new test source files, they must go under `src/test`.
You will need to add them to one of the
[source lists](./Builds/CMake/RippledCore.cmake) in CMake.
[source lists](./cmake/RippledCore.cmake) in CMake.
If your test can be run offline, in under 60 seconds, then it can be an
automatic test run by `rippled --unittest`.
Otherwise, it must be a manual test.

View File

@@ -12,7 +12,7 @@ The server software that powers Xahau is called `xahaud` and is available in thi
### Build from Source
* [Read the build instructions in our documentation](https://xahau.network/docs/infrastructure/build-xahaud/)
* [Read the build instructions in our documentation](https://xahau.network/infrastructure/building-xahau)
* If you encounter any issues, please [open an issue](https://github.com/xahau/xahaud/issues)
## Highlights of Xahau

View File

@@ -2,7 +2,7 @@
set -o errexit
marker_base=f62f74da10c5936c64bd16cd509a8b68f1464e41
marker_base=34be0ce4fef20c978df2923c29321ad6cc17facc
marker_commit=${1:-${marker_base}}
if [ $(git merge-base ${marker_commit} ${marker_base}) != ${marker_base} ]; then

View File

@@ -1,148 +0,0 @@
#!/usr/bin/env python3
"""Build and import one committed jshookz provider snapshot into Xahau."""
from __future__ import annotations
import argparse
import json
import os
import shlex
import shutil
import subprocess
from pathlib import Path
SNAPSHOT_FILES = (
"jshookz_provider.manifest.cmake",
"jshookz_provider.manifest.json",
"jshookz_provider.native-abi.json",
"jshookz_provider.wasm",
)
API_SNAPSHOT_FILES = {
"python/jshookz/src/jshookz/types/api-artifacts.json": "api-artifacts.json",
"python/jshookz/src/jshookz/types/hooks-api.d.ts": "hooks-api.d.ts",
"python/jshookz/src/jshookz/types/xahau-quickjs-v1.d.ts":
"xahau-quickjs-v1.d.ts",
"python/jshookz/src/jshookz/types/xahau-quickjs-v1.surface.json":
"xahau-quickjs-v1.surface.json",
}
def run(*args: str, cwd: Path, capture: bool = False) -> str:
completed = subprocess.run(
args,
cwd=cwd,
check=True,
text=True,
stdout=subprocess.PIPE if capture else None,
)
return completed.stdout.strip() if capture else ""
def main() -> int:
parser = argparse.ArgumentParser(
description=(
"Build a committed jshookz checkout and copy its sealed "
"provider lock into Xahau. CI tracks jshookz main; the lock "
"is what must match."
)
)
parser.add_argument("jshookz_checkout", type=Path)
parser.add_argument(
"--no-build",
action="store_true",
help="import an already-built build/xahau-provider bundle",
)
args = parser.parse_args()
xahau_root = Path(__file__).resolve().parents[1]
jshookz_root = args.jshookz_checkout.expanduser().resolve()
cli = next(
(
candidate
for candidate in (
jshookz_root / "python/jshookz/.venv/bin/jshookz",
jshookz_root / "packages/jshookz/.venv/bin/jshookz",
)
if candidate.is_file()
),
None,
)
if cli is None:
parser.error(
"missing jshookz CLI under python/jshookz/.venv or "
"packages/jshookz/.venv"
)
bundle = jshookz_root / "build/xahau-provider"
destination = xahau_root / "external/quickjs-provider"
dirty = run(
"git",
"status",
"--porcelain",
"--untracked-files=no",
cwd=jshookz_root,
capture=True,
)
if dirty:
parser.error(
"jshookz checkout has uncommitted tracked changes; commit them "
"before creating a pinned snapshot"
)
commit = run("git", "rev-parse", "HEAD", cwd=jshookz_root, capture=True)
if not args.no_build:
run(str(cli), "build", "provider", cwd=jshookz_root)
missing = [name for name in SNAPSHOT_FILES if not (bundle / name).is_file()]
missing.extend(
source for source in API_SNAPSHOT_FILES if not (jshookz_root / source).is_file()
)
if missing:
parser.error(f"incomplete provider bundle: {', '.join(missing)}")
for name in SNAPSHOT_FILES:
shutil.copy2(bundle / name, destination / name)
for source, name in API_SNAPSHOT_FILES.items():
shutil.copy2(jshookz_root / source, destination / name)
manifest = json.loads((bundle / "jshookz_provider.manifest.json").read_text())
wasi_sdk = os.environ.get("HOOKZ_WASI_SDK")
if not wasi_sdk:
try:
wasi_sdk = str(
Path(
run(
"mise",
"where",
"wasi-sdk",
cwd=jshookz_root,
capture=True,
)
)
/ "wasi-sdk"
)
except (FileNotFoundError, subprocess.CalledProcessError):
wasi_sdk = "/path/to/wasi-sdk"
print(f"jshookz commit: {commit}")
print(f"provider sha256: {manifest['provider']['sha256']}")
print(f"bytecode ABI: {manifest['bytecode_abi_id']}")
print(f"runtime profile: {manifest['runtime_profile_id']}")
print("snapshot imported; regenerate fixtures and run the focused suite with:")
print(
" env "
f"JSHOOKZ_HOOK_COMPILER={shlex.quote(f'{cli} compile-hook')} "
f"HOOKZ_WASI_SDK={shlex.quote(wasi_sdk)} "
f"XAHAU_QJS_PROVIDER_WASM={shlex.quote(str(bundle / 'jshookz_provider.wasm'))} "
"XAHAU_REQUIRE_QJS_PROVIDER_TESTS=1 "
"x-run-tests --compile-hooks src/test/app/JSHooks_test.cpp "
"--build-dir build --ccache -- "
"ripple.app.JSHooks,ripple.app.QuickJSHostPolicy,"
"ripple.app.HookGuestMemory,ripple.app.HookAPI"
)
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -51,9 +51,10 @@ export CMAKE_STATIC_LINKER_FLAGS="-static-libstdc++"
git config --global --add safe.directory /io &&
git checkout src/libxrpl/protocol/BuildInfo.cpp &&
sed -i s/\"0.0.0\"/\"$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)$(if [ -n "$4" ]; then echo "+$4"; fi)\"/g src/libxrpl/protocol/BuildInfo.cpp &&
sed -i s/\"0.0.0\"/\"$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)$(if [ -n "$4" ]; then echo "+$4"; fi)\"/g src/libxrpl/protocol/BuildInfo.cpp &&
conan export external/snappy --version 1.1.10 --user xahaud --channel stable &&
conan export external/soci --version 4.0.3 --user xahaud --channel stable &&
conan export external/wasmedge --version 0.11.2 --user xahaud --channel stable &&
cd release-build &&
# Install dependencies - tool_requires in conanfile.py handles glibc 2.28 compatibility
# for build tools (protoc, grpc plugins, b2) in HBB environment
@@ -71,7 +72,6 @@ cmake .. -G Ninja \
-Dxrpld=TRUE \
-Dtests=TRUE &&
ccache -z &&
ccache -p &&
ninja -j $3 && echo "=== Re-running final link with verbose output ===" && rm -f rippled && ninja -v rippled &&
ccache -s &&
strip -s rippled &&
@@ -95,16 +95,8 @@ if [[ "$4" == "" ]]; then
echo "Non GH, local building, no Action runner magic"
else
# GH Action, runner
if [[ "$(git rev-parse --abbrev-ref HEAD)" == "release" ]]; then
echo "building on the release branch... placing it in builds/candidate"
mkdir /data/builds/candidate
cp /io/release-build/xahaud /data/builds/candidate/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
cp /io/release-build/release.info /data/builds/candidate/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
else
echo "building non-release branch, placing it in builds root"
cp /io/release-build/xahaud /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
cp /io/release-build/release.info /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
fi
cp /io/release-build/xahaud /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
cp /io/release-build/release.info /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
echo "Published build to: http://build.xahau.tech/"
echo $(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
fi

View File

@@ -12,16 +12,17 @@ echo "-- GITHUB_REPOSITORY: $1"
echo "-- GITHUB_SHA: $2"
echo "-- GITHUB_RUN_NUMBER: $4"
umask 0000
umask 0000;
####
cd /io
mkdir -p src/certs
curl --silent -k https://raw.githubusercontent.com/RichardAH/rippled-release-builder/main/ca-bundle/certbundle.h -o src/certs/certbundle.h
if [ "$(grep certbundle.h src/xrpld/net/detail/RegisterSSLCerts.cpp | wc -l)" -eq "0" ]; then
cp src/xrpld/net/detail/RegisterSSLCerts.cpp src/xrpld/net/detail/RegisterSSLCerts.cpp.old
perl -i -pe "s/^{/{
cd /io;
mkdir -p src/certs;
curl --silent -k https://raw.githubusercontent.com/RichardAH/rippled-release-builder/main/ca-bundle/certbundle.h -o src/certs/certbundle.h;
if [ "`grep certbundle.h src/xrpld/net/detail/RegisterSSLCerts.cpp | wc -l`" -eq "0" ]
then
cp src/xrpld/net/detail/RegisterSSLCerts.cpp src/xrpld/net/detail/RegisterSSLCerts.cpp.old
perl -i -pe "s/^{/{
#ifdef EMBEDDED_CA_BUNDLE
BIO *cbio = BIO_new_mem_buf(ca_bundle.data(), ca_bundle.size());
X509_STORE *cts = SSL_CTX_get_cert_store(ctx.native_handle());
@@ -67,14 +68,15 @@ fi
source /opt/rh/gcc-toolset-11/enable
export PATH=/usr/local/bin:$PATH
export CC='/usr/lib64/ccache/gcc' &&
export CXX='/usr/lib64/ccache/g++' &&
echo "-- Build Rippled --" &&
pwd &&
echo "MOVING TO [ build-core.sh ]"
export CXX='/usr/lib64/ccache/g++' &&
echo "-- Build Rippled --" &&
pwd &&
printenv >.env.temp
cat .env.temp | grep '=' | sed s/\\\(^[^=]\\+=\\\)/\\1\\\"/g | sed s/\$/\\\"/g >.env
rm .env.temp
echo "MOVING TO [ build-core.sh ]";
printenv > .env.temp;
cat .env.temp | grep '=' | sed s/\\\(^[^=]\\+=\\\)/\\1\\\"/g|sed s/\$/\\\"/g > .env;
rm .env.temp;
echo "Persisting ENV:"
cat .env

View File

@@ -394,7 +394,7 @@
# true - enables compression
# false - disables compression [default].
#
# The rippled server can save bandwidth by compressing its peer-to-peer communications,
# The xahaud server can save bandwidth by compressing its peer-to-peer communications,
# at a cost of greater CPU usage. If you enable link compression,
# the server automatically compresses communications with peer servers
# that also have link compression enabled.
@@ -477,19 +477,6 @@
#
#
#
# [sntp_servers]
#
# IP address or domain of NTP servers to use for time synchronization.
#
# These NTP servers are suitable for xahaud servers located in the United
# States:
# time.windows.com
# time.apple.com
# time.nist.gov
# pool.ntp.org
#
#
#
# [max_transactions]
#
# Configure the maximum number of transactions to have in the job queue
@@ -954,12 +941,6 @@
#
# path Location to store the database
#
# Required keys for RWDB:
#
# online_delete Required. RWDB stores data in memory and will
# grow unbounded without online_delete. See the
# online_delete section below.
#
# Optional keys
#
# cache_size Size of cache for database records. Default is 16384.
@@ -1450,7 +1431,7 @@
#
# ETL commands for Clio. We recommend setting secure_gateway
# in this section to a comma-separated list of the addresses
# of your Clio servers, in order to bypass rippled's rate limiting.
# of your Clio servers, in order to bypass xahaud's rate limiting.
#
# This port is commented out but can be enabled by removing
# the '#' from each corresponding line including the entry under [server]
@@ -1524,13 +1505,10 @@ secure_gateway = 127.0.0.1
# when the node has approximately two times the "online_delete" value of
# ledgers. No external administrative command is required to initiate
# deletion.
[ledger_history]
256
[node_db]
type=NuDB
path=/opt/xahaud/db/nudb
online_delete=256
online_delete=512
advisory_delete=0
[database_path]
@@ -1542,18 +1520,7 @@ advisory_delete=0
[debug_logfile]
/var/log/xahaud/debug.log
[sntp_servers]
time.windows.com
time.apple.com
time.nist.gov
pool.ntp.org
# Use the following [ips] section for the main network:
[ips]
bacab.alloy.ee 21337
hubs.xahau.as16089.net 21337
# To use the Xahau Test Network
# To use the Xahau test network
# (see https://xahau.network/docs/infrastructure/installing-xahaud),
# use the following [ips] section:
# [ips]
@@ -1579,10 +1546,3 @@ validators-xahau.txt
# set to ssl_verify to 0.
[ssl_verify]
1
# Define which network xahaud is connecting to
# 21337 for the Main Xahau Network
# 21338 for the Test Xahau Network
[network_id]
21337
# 21338

View File

@@ -95,9 +95,6 @@
# - replace both functions setup_target_for_coverage_gcovr_* with a single setup_target_for_coverage_gcovr
# - add support for all gcovr output formats
#
# 2024-04-03, Bronek Kozicki
# - add support for output formats: jacoco, clover, lcov
#
# USAGE:
#
# 1. Copy this file into your cmake modules path.
@@ -259,10 +256,10 @@ endif()
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# FORMAT "cobertura" # Output format, one of:
# # xml cobertura sonarqube jacoco clover
# # json-summary json-details coveralls csv
# # txt html-single html-nested html-details
# # lcov (xml is an alias to cobertura;
# # xml cobertura sonarqube json-summary
# # json-details coveralls csv txt
# # html-single html-nested html-details
# # (xml is an alias to cobertura;
# # if no format is set, defaults to xml)
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
# # to BASE_DIRECTORY, with CMake 3.4+)
@@ -311,8 +308,6 @@ function(setup_target_for_coverage_gcovr)
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.txt)
elseif(Coverage_FORMAT STREQUAL "csv")
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.csv)
elseif(Coverage_FORMAT STREQUAL "lcov")
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.lcov)
else()
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.xml)
endif()
@@ -325,14 +320,6 @@ function(setup_target_for_coverage_gcovr)
set(Coverage_FORMAT cobertura) # overwrite xml
elseif(Coverage_FORMAT STREQUAL "sonarqube")
list(APPEND GCOVR_ADDITIONAL_ARGS --sonarqube "${GCOVR_OUTPUT_FILE}" )
elseif(Coverage_FORMAT STREQUAL "jacoco")
list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco "${GCOVR_OUTPUT_FILE}" )
list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco-pretty )
elseif(Coverage_FORMAT STREQUAL "clover")
list(APPEND GCOVR_ADDITIONAL_ARGS --clover "${GCOVR_OUTPUT_FILE}" )
list(APPEND GCOVR_ADDITIONAL_ARGS --clover-pretty )
elseif(Coverage_FORMAT STREQUAL "lcov")
list(APPEND GCOVR_ADDITIONAL_ARGS --lcov "${GCOVR_OUTPUT_FILE}" )
elseif(Coverage_FORMAT STREQUAL "json-summary")
list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary "${GCOVR_OUTPUT_FILE}" )
list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary-pretty)
@@ -393,7 +380,6 @@ function(setup_target_for_coverage_gcovr)
${GCOVR_PATH}
--gcov-executable ${GCOV_TOOL}
--gcov-ignore-parse-errors=negative_hits.warn_once_per_file
--gcov-ignore-parse-errors=suspicious_hits.warn_once_per_file
-r ${BASEDIR}
${GCOVR_ADDITIONAL_ARGS}
${GCOVR_EXCLUDE_ARGS}

View File

@@ -1,928 +0,0 @@
#!/usr/bin/env python3
"""Project the sealed QuickJS bundle into one C++ translation unit."""
from __future__ import annotations
import argparse
import hashlib
import json
import re
import sys
from pathlib import Path
from typing import Any
CHUNK = 64
CMAKE_SET = re.compile(r'^set\(XAHAU_QUICKJS_([A-Z0-9_]+) "([^"]*)"\)\s*$')
WASM_VALTYPE = {"i32", "i64"}
WASM_BYTE = {"i32": "0x7f", "i64": "0x7e"}
WASM_STACK_BYTES = 131072
WASM_PAGE_BYTES = 65536
PROVIDER_MEMORY_MINIMUM_PAGES = 7
PROVIDER_MEMORY_MAXIMUM_PAGES = 512
PROVIDER_MEMORY_MAX_BYTES = PROVIDER_MEMORY_MAXIMUM_PAGES * WASM_PAGE_BYTES
SEALED_MANIFEST_SHA256 = (
"1673b27d21063957cece9095cceb7e2dbfa53b6f49a5b7f824a486d7d90b2391"
)
SEALED_PROVIDER_SHA256 = (
"f60ab333acb547e50d7d087960839bd11833cb133d496af98e0b72a1bb3b84df"
)
SEALED_PROVIDER_SIZE = 1116638
SEALED_NATIVE_ABI_SHA256 = (
"328ec938dcad875f3bdf25b8d779dd77f3571589818ca9271cb98c64c7018f99"
)
SEALED_BYTECODE_ABI_ID = (
"75ea54f357d397c4b33899e495bb385dad975a43b1c4a7a2cead30474327d33e"
)
SEALED_RUNTIME_PROFILE_ID = (
"29acf12e170436e5ccadfbc118d02a60909f86a88262106652b2f71994b0ea25"
)
SEALED_WASMTIME_VERSION = "47.0.3"
SEALED_HOOK_API_VERSION = 1
SEALED_HOST_ADAPTER_POLICY = "xahau-raw-hook-host-v1"
SEALED_BROAD_DECLARATION_SHA256 = (
"649079b831bc68eff0f440644649a505addafb08a3f5174e4031c8de6aedffa0"
)
SEALED_EXACT_V1_DECLARATION_SHA256 = (
"20881232f0602e35de0fcbb8b5a3c1511606392749a0f79daebb386204f4f4da"
)
SEALED_SURFACE_SHA256 = (
"96a9218bf38abbf1bc9f2839408700d03572e0b065d625263f70477bc32597ac"
)
SEALED_API_ARTIFACT_MANIFEST_SHA256 = (
"95babf622bf5edff76fdcbd9746bad8f1f8b275a3d4bacdc320ff4deae543eba"
)
API_ARTIFACT_SCHEMA = "jshookz.api-artifacts.v1"
SEALED_API_ARTIFACTS = {
"python/jshookz/src/jshookz/types/hooks-api.d.ts": (
"broad_declaration",
"hooks-api.d.ts",
SEALED_BROAD_DECLARATION_SHA256,
),
"python/jshookz/src/jshookz/types/xahau-quickjs-v1.d.ts": (
"exact_v1_declaration",
"xahau-quickjs-v1.d.ts",
SEALED_EXACT_V1_DECLARATION_SHA256,
),
"python/jshookz/src/jshookz/types/xahau-quickjs-v1.surface.json": (
"selected_surface",
"xahau-quickjs-v1.surface.json",
SEALED_SURFACE_SHA256,
),
}
SEALED_LIMITS = {
"host_work_base_per_call": 1,
"host_work_budget": 1000000,
"host_work_meter": "base-plus-addressed-byte-v1",
"host_work_per_addressed_byte": 1,
"quickjs_heap_bytes": 16777216,
"quickjs_stack_bytes": 65536,
"serialized_object_max_bytes": 1048576,
"serialized_object_max_fields": 32768,
"serialized_object_max_scopes": 32769,
"serialized_object_max_depth": 10,
"wasmtime_fuel_per_initialization": 5000000,
"wasmtime_fuel_per_invocation": 50000000,
}
SEALED_HOST_WORK_ADDRESSED_LENGTH_INDICES = {
"accept": [1],
"emit": [1, 3],
"hook_account": [1],
"ledger_last_hash": [1],
"prepare": [1, 3],
"rollback": [1],
"state": [1, 3],
"state_set": [1, 3],
"trace": [1, 3],
}
SEALED_ENGINE_CONFIGURATION = {
"consume_fuel": True,
"cranelift_nan_canonicalization": True,
"wasi": False,
"wasm_memory64": False,
"wasm_multi_memory": False,
"wasm_relaxed_simd": False,
"wasm_tail_call": False,
"wasm_threads": False,
}
IMPORT_KEYS = frozenset({"module", "name", "params", "results"})
FUNCTION_EXPORT_KEYS = frozenset({"kind", "name", "params", "results"})
MEMORY_EXPORT_KEYS = frozenset(
{"kind", "name", "minimum_pages", "maximum_pages", "memory64", "shared"}
)
SURFACE_KEYS = frozenset(
{"declaration", "declaration_sha256", "manifest", "schema", "sha256"}
)
NESTED_SURFACE_KEYS = frozenset({"declaration", "manifest", "schema"})
def _import_row(name: str, params: list[str], results: list[str]) -> dict[str, Any]:
return {"module": "env", "name": name, "params": params, "results": results}
def _function_export(name: str, params: list[str], results: list[str]) -> dict[str, Any]:
return {"kind": "function", "name": name, "params": params, "results": results}
SEALED_IMPORTS = [
_import_row("accept", ["i32", "i32", "i64"], ["i64"]),
_import_row("emit", ["i32", "i32", "i32", "i32"], ["i64"]),
_import_row("etxn_reserve", ["i32"], ["i64"]),
_import_row("hook_account", ["i32", "i32"], ["i64"]),
_import_row("ledger_last_hash", ["i32", "i32"], ["i64"]),
_import_row("ledger_last_time", [], ["i64"]),
_import_row("ledger_seq", [], ["i64"]),
_import_row("otxn_type", [], ["i64"]),
_import_row("prepare", ["i32", "i32", "i32", "i32"], ["i64"]),
_import_row("rollback", ["i32", "i32", "i64"], ["i64"]),
_import_row("state", ["i32", "i32", "i32", "i32"], ["i64"]),
_import_row("state_set", ["i32", "i32", "i32", "i32"], ["i64"]),
_import_row("trace", ["i32", "i32", "i32", "i32", "i32"], ["i64"]),
]
SEALED_EXPORTS = [
_function_export("_initialize", [], []),
_function_export("free", ["i32"], []),
_function_export("malloc", ["i32"], ["i32"]),
{
"kind": "memory",
"maximum_pages": 512,
"memory64": False,
"minimum_pages": 7,
"name": "memory",
"shared": False,
},
_function_export("qjs_cbak", ["i32", "i32", "i32"], ["i32"]),
_function_export("qjs_compile", ["i32", "i32"], ["i32"]),
_function_export("qjs_compile_module", ["i32", "i32"], ["i32"]),
_function_export("qjs_destroy", [], []),
_function_export("qjs_enable_coverage", ["i32"], []),
_function_export("qjs_eval", ["i32", "i32"], ["i32"]),
_function_export("qjs_eval_bytecode", ["i32", "i32"], ["i32"]),
_function_export("qjs_eval_module", ["i32", "i32"], ["i32"]),
_function_export("qjs_get_bytecode_len", [], ["i32"]),
_function_export("qjs_get_bytecode_ptr", [], ["i32"]),
_function_export("qjs_get_result_len", [], ["i32"]),
_function_export("qjs_get_result_ptr", [], ["i32"]),
_function_export("qjs_hook", ["i32", "i32", "i32"], ["i32"]),
_function_export("qjs_init", [], []),
_function_export("qjs_set_max_stack_size", ["i32"], []),
_function_export("qjs_set_memory_limit", ["i32"], []),
_function_export("qjs_set_seed", ["i32"], []),
_function_export("qjs_validate_hook_module", ["i32", "i32"], ["i32"]),
]
class LockError(ValueError):
"""A sealed QuickJS lock identity failed a fail-closed check."""
def quote(value: str) -> str:
if not isinstance(value, str) or any(c in value for c in "\n\r"):
raise LockError(f"invalid QuickJS policy string: {value!r}")
return json.dumps(value)
def parse_cmake(path: Path) -> dict[str, str]:
values: dict[str, str] = {}
for line in path.read_text().splitlines():
match = CMAKE_SET.match(line)
if match:
values[match.group(1)] = match.group(2)
return values
def hex_bytes(value: str) -> str:
if len(value) != 64 or any(c not in "0123456789abcdefABCDEF" for c in value):
raise LockError(f"QuickJS identity must be 32 hexadecimal bytes: {value!r}")
return ", ".join(f"0x{value[i:i + 2]}" for i in range(0, 64, 2))
def require(cmake: dict[str, str], key: str) -> str:
if key not in cmake:
raise LockError(f"QuickJS cmake projection missing {key}")
return cmake[key]
def require_int(cmake: dict[str, str], key: str) -> int:
return int(require(cmake, key))
def require_hex(value: object, label: str) -> str:
text = str(value).lower()
if len(text) != 64 or any(c not in "0123456789abcdef" for c in text):
raise LockError(f"{label} is not a SHA-256 hex digest: {value!r}")
return text
def require_sealed(actual: object, expected: object, label: str) -> None:
if actual != expected:
raise LockError(
f"{label} disagrees with the sealed F0 table: "
f"{actual!r} != {expected!r}"
)
def validate_api_artifacts(bundle: Path) -> dict[str, str]:
manifest_path = bundle / "api-artifacts.json"
manifest = json.loads(manifest_path.read_text())
if not isinstance(manifest, dict) or set(manifest) != {"artifacts", "schema"}:
raise LockError("API artifact manifest has extra or missing keys")
if manifest.get("schema") != API_ARTIFACT_SCHEMA:
raise LockError("API artifact manifest schema disagrees with the sealed F0 table")
artifacts = manifest.get("artifacts")
if not isinstance(artifacts, dict) or set(artifacts) != set(SEALED_API_ARTIFACTS):
raise LockError("API artifact manifest file set disagrees with the sealed F0 table")
identities: dict[str, str] = {}
for source_path, artifact in SEALED_API_ARTIFACTS.items():
identity_name, local_name, sealed_digest = artifact
actual_digest = hashlib.sha256((bundle / local_name).read_bytes()).hexdigest()
declared_digest = require_hex(
artifacts.get(source_path), f"API artifact {source_path} SHA-256"
)
if actual_digest != declared_digest:
raise LockError(
f"API artifact {source_path} disagrees with its manifest digest"
)
require_sealed(actual_digest, sealed_digest, f"API artifact {source_path}")
identities[identity_name] = actual_digest
actual_manifest = hashlib.sha256(manifest_path.read_bytes()).hexdigest()
require_sealed(
actual_manifest,
SEALED_API_ARTIFACT_MANIFEST_SHA256,
"API artifact manifest SHA-256",
)
identities["api_artifact_manifest"] = actual_manifest
return identities
def cpp_bool(value: object) -> str:
if value is True:
return "true"
if value is False:
return "false"
raise LockError(f"expected JSON boolean, got {value!r}")
def join_types(values: object, label: str) -> str:
if not isinstance(values, list) or not all(isinstance(item, str) for item in values):
raise LockError(f"{label} is not a list of wasm value types: {values!r}")
for item in values:
if item not in WASM_VALTYPE:
raise LockError(f"{label} has unsupported wasm value type {item!r}")
return ",".join(values)
def wasm_signature(params: object, results: object, label: str) -> list[str]:
join_types(params, f"{label} params")
join_types(results, f"{label} results")
assert isinstance(params, list) and isinstance(results, list)
return [WASM_BYTE[item] for item in results] + [WASM_BYTE[item] for item in params]
def embed_body(data: bytes | None) -> str:
if data is None:
return (
"std::span<std::uint8_t const>\n"
"embeddedQuickJSProvider()\n"
"{\n"
" return {};\n"
"}\n"
)
lines = []
for offset in range(0, len(data), CHUNK):
chunk = data[offset : offset + CHUNK]
lines.append(' "' + "".join(f"\\x{b:02x}" for b in chunk) + '"')
return (
"namespace {\n"
"\n"
"constexpr char const sealedProvider[] =\n"
+ "\n".join(lines)
+ ";\n"
"\n"
"static_assert(\n"
f" sizeof(sealedProvider) - 1 == {len(data)},\n"
' "embedded provider size disagrees with its manifest");\n'
"\n"
"} // namespace\n"
"\n"
"std::span<std::uint8_t const>\n"
"embeddedQuickJSProvider()\n"
"{\n"
" return {\n"
" reinterpret_cast<std::uint8_t const*>(sealedProvider),\n"
" sizeof(sealedProvider) - 1};\n"
"}\n"
)
def format_export_row(item: dict[str, Any]) -> str:
kind = item["kind"]
name = item["name"]
if kind == "memory":
fields = (
quote(kind),
quote(name),
quote(""),
quote(""),
f"{int(item['minimum_pages'])}U",
f"{int(item['maximum_pages'])}U",
cpp_bool(item["memory64"]),
cpp_bool(item["shared"]),
)
elif kind == "function":
fields = (
quote(kind),
quote(name),
quote(join_types(item["params"], f"export {name} params")),
quote(join_types(item["results"], f"export {name} results")),
"0U",
"0U",
"false",
"false",
)
else:
raise LockError(f"unsupported provider export kind: {kind!r}")
return "{" + ", ".join(fields) + "}"
def require_typed_exports(exports: object, label: str) -> list[dict[str, Any]]:
if not isinstance(exports, list) or not all(isinstance(item, dict) for item in exports):
raise LockError(f"{label} must be a list of typed export rows")
names: list[str] = []
memory_rows: list[dict[str, Any]] = []
for item in exports:
kind = item.get("kind")
name = item.get("name")
if not isinstance(kind, str) or not isinstance(name, str) or not name:
raise LockError(f"{label} row is missing kind/name: {item!r}")
if kind == "function":
if set(item) != FUNCTION_EXPORT_KEYS:
raise LockError(f"{label} function {name} has extra or missing keys")
join_types(item.get("params"), f"{label} {name} params")
join_types(item.get("results"), f"{label} {name} results")
elif kind == "memory":
if set(item) != MEMORY_EXPORT_KEYS:
raise LockError(f"{label} memory row has extra or missing keys")
for key in ("minimum_pages", "maximum_pages"):
if not isinstance(item.get(key), int):
raise LockError(f"{label} memory row missing integer {key}")
if item.get("memory64") is not False or item.get("shared") is not False:
raise LockError(
f"{label} memory row is not memory64=false / shared=false"
)
memory_rows.append(item)
else:
raise LockError(f"{label} has unsupported export kind {kind!r}")
names.append(name)
if len(names) != len(set(names)):
raise LockError(f"{label} contains duplicate export names")
if names != sorted(names):
raise LockError(f"{label} must be normalized by export name")
if len(memory_rows) != 1 or memory_rows[0].get("name") != "memory":
raise LockError(f"{label} must export exactly one memory named memory")
return exports
def require_typed_imports(imports: object, label: str) -> list[dict[str, Any]]:
if not isinstance(imports, list) or not all(isinstance(item, dict) for item in imports):
raise LockError(f"{label} must be a list of typed import rows")
names: list[str] = []
for item in imports:
module = item.get("module")
name = item.get("name")
if not isinstance(module, str) or not isinstance(name, str) or not name:
raise LockError(f"{label} row is missing module/name: {item!r}")
if set(item) != IMPORT_KEYS:
raise LockError(f"{label} {name} has extra or missing keys")
wasm_signature(item.get("params"), item.get("results"), f"{label} {name}")
names.append(name)
if len(names) != len(set(names)):
raise LockError(f"{label} contains duplicate import names")
return imports
def require_build(build: object, label: str) -> dict[str, Any]:
if not isinstance(build, dict):
raise LockError(f"{label} is missing build metadata")
stack = build.get("wasm_stack_bytes")
memory = build.get("wasm_memory_max_bytes")
if stack != WASM_STACK_BYTES:
raise LockError(
f"{label} wasm_stack_bytes is {stack!r}, expected {WASM_STACK_BYTES}"
)
if memory != PROVIDER_MEMORY_MAX_BYTES:
raise LockError(
f"{label} wasm_memory_max_bytes is {memory!r}, "
f"expected {PROVIDER_MEMORY_MAX_BYTES}"
)
return build
def cross_compare_int(cmake: dict[str, str], key: str, actual: object, label: str) -> int:
expected = require_int(cmake, key)
if actual != expected:
raise LockError(
f"{label} disagrees between JSON ({actual!r}) and CMake {key} ({expected!r})"
)
return expected
def cross_compare_str(cmake: dict[str, str], key: str, actual: object, label: str) -> str:
expected = require(cmake, key)
if str(actual) != expected:
raise LockError(
f"{label} disagrees between JSON ({actual!r}) and CMake {key} ({expected!r})"
)
return expected
def validate_lock(
profile: dict[str, Any],
native: dict[str, Any],
cmake: dict[str, str],
wasmtime_version: str,
api_identities: dict[str, str],
) -> tuple[list[dict[str, Any]], list[dict[str, Any]], dict[str, Any], str, str, int]:
schema = require(cmake, "MANIFEST_SCHEMA")
if schema != "xahau.quickjs.runtime-profile-lock.v1" or profile.get("schema") != schema:
raise LockError(f"unsupported QuickJS provider manifest schema: {schema}")
expected_sha = require_hex(require(cmake, "PROVIDER_SHA256"), "CMake provider SHA-256")
json_sha = require_hex(profile.get("provider", {}).get("sha256"), "JSON provider SHA-256")
if json_sha != expected_sha:
raise LockError("provider sha256 disagrees between JSON lock and cmake")
require_sealed(expected_sha, SEALED_PROVIDER_SHA256, "provider SHA-256")
expected_size = require_int(cmake, "PROVIDER_SIZE")
json_size = profile.get("provider", {}).get("size")
if json_size != expected_size:
raise LockError("provider size disagrees between JSON lock and cmake")
require_sealed(expected_size, SEALED_PROVIDER_SIZE, "provider size")
bytecode = require_hex(require(cmake, "BYTECODE_ABI_ID"), "CMake bytecode ABI")
if require_hex(profile.get("bytecode_abi_id"), "JSON bytecode ABI") != bytecode:
raise LockError("bytecode ABI disagrees between JSON lock and cmake")
require_sealed(bytecode, SEALED_BYTECODE_ABI_ID, "bytecode ABI")
runtime_profile = require_hex(
require(cmake, "RUNTIME_PROFILE_ID"), "CMake runtime-profile ID"
)
if require_hex(profile.get("runtime_profile_id"), "JSON runtime-profile ID") != runtime_profile:
raise LockError("runtime-profile ID disagrees between JSON lock and cmake")
require_sealed(
runtime_profile, SEALED_RUNTIME_PROFILE_ID, "runtime-profile ID"
)
pinned_wasmtime = require(cmake, "WASMTIME_VERSION")
engine = profile.get("source", {}).get("engine", {})
engine_version = engine.get("version")
if wasmtime_version != pinned_wasmtime or engine_version != pinned_wasmtime:
raise LockError(
f"QuickJS provider requires Wasmtime {pinned_wasmtime}, "
f"but CMake resolved {wasmtime_version} and JSON has {engine_version!r}"
)
require_sealed(pinned_wasmtime, SEALED_WASMTIME_VERSION, "Wasmtime version")
require_sealed(
engine.get("configuration"),
SEALED_ENGINE_CONFIGURATION,
"Wasmtime engine configuration",
)
limits = profile.get("source", {}).get("limits")
if not isinstance(limits, dict):
raise LockError("JSON runtime-profile source is missing limits")
cross_compare_int(
cmake, "SERIALIZED_OBJECT_MAX_BYTES", limits.get("serialized_object_max_bytes"),
"serialized_object_max_bytes",
)
cross_compare_int(
cmake, "SERIALIZED_OBJECT_MAX_FIELDS", limits.get("serialized_object_max_fields"),
"serialized_object_max_fields",
)
cross_compare_int(
cmake, "SERIALIZED_OBJECT_MAX_SCOPES", limits.get("serialized_object_max_scopes"),
"serialized_object_max_scopes",
)
cross_compare_int(
cmake, "SERIALIZED_OBJECT_MAX_DEPTH", limits.get("serialized_object_max_depth"),
"serialized_object_max_depth",
)
for key, expected in SEALED_LIMITS.items():
require_sealed(limits.get(key), expected, key)
require_sealed(
limits.get("host_work_addressed_length_indices"),
SEALED_HOST_WORK_ADDRESSED_LENGTH_INDICES,
"host_work_addressed_length_indices",
)
cross_compare_int(cmake, "HEAP_BYTES", limits.get("quickjs_heap_bytes"), "quickjs_heap_bytes")
cross_compare_int(cmake, "STACK_BYTES", limits.get("quickjs_stack_bytes"), "quickjs_stack_bytes")
cross_compare_int(
cmake, "INITIALIZATION_FUEL", limits.get("wasmtime_fuel_per_initialization"),
"initialization fuel",
)
cross_compare_int(
cmake, "INVOCATION_FUEL", limits.get("wasmtime_fuel_per_invocation"),
"invocation fuel",
)
cross_compare_int(cmake, "HOST_WORK_BUDGET", limits.get("host_work_budget"), "host_work_budget")
cross_compare_int(
cmake, "HOST_WORK_BASE_PER_CALL", limits.get("host_work_base_per_call"),
"host_work_base_per_call",
)
cross_compare_int(
cmake, "HOST_WORK_PER_ADDRESSED_BYTE", limits.get("host_work_per_addressed_byte"),
"host_work_per_addressed_byte",
)
cross_compare_str(cmake, "HOST_WORK_METER", limits.get("host_work_meter"), "host_work_meter")
host_adapter_policy = cross_compare_str(
cmake, "HOST_ADAPTER_POLICY",
profile.get("source", {}).get("execution", {}).get("host_adapter_policy"),
"host_adapter_policy",
)
require_sealed(
host_adapter_policy, SEALED_HOST_ADAPTER_POLICY, "host_adapter_policy"
)
hook_api_version = cross_compare_int(
cmake, "HOOK_API_VERSION",
profile.get("source", {}).get("artifact", {}).get("hook_api_version"),
"hook_api_version",
)
require_sealed(hook_api_version, SEALED_HOOK_API_VERSION, "hook_api_version")
provider = profile.get("provider")
source_provider = profile.get("source", {}).get("provider")
if not isinstance(provider, dict) or not isinstance(source_provider, dict):
raise LockError("JSON lock is missing provider or source.provider")
require_build(provider.get("build"), "provider.build")
require_build(source_provider.get("build"), "source.provider.build")
require_sealed(
source_provider.get("forbidden_import_modules"),
["wasi_snapshot_preview1"],
"forbidden provider import modules",
)
expected_import_count = require_int(cmake, "PROVIDER_IMPORT_COUNT")
provider_imports = require_typed_imports(provider.get("imports"), "provider.imports")
source_imports = require_typed_imports(
source_provider.get("imports"), "source.provider.imports"
)
native_imports = native.get("selected")
if not isinstance(native_imports, list):
raise LockError("native ABI snapshot is missing selected imports")
if provider_imports != source_imports:
raise LockError("provider import signatures disagree between JSON copies")
if provider_imports != SEALED_IMPORTS:
raise LockError(
"provider import signatures disagree with the sealed F0 table"
)
if (
len(provider_imports) != expected_import_count
or len(native_imports) != expected_import_count
):
raise LockError("QuickJS provider/native ABI import counts differ")
provider_names = [item["name"] for item in provider_imports]
native_names = [item["name"] for item in native_imports]
if len(set(provider_names)) != expected_import_count or set(provider_names) != set(
native_names
):
raise LockError("QuickJS provider/native ABI import sets differ")
native_by_name = {item["name"]: item for item in native_imports}
for item in provider_imports:
native_item = native_by_name[item["name"]]
expected_sig = wasm_signature(
item["params"], item["results"], f"import {item['name']}"
)
if native_item.get("wasm_signature") != expected_sig:
raise LockError(
f"import {item['name']} wasm signature disagrees between JSON and native ABI"
)
expected_export_count = require_int(cmake, "PROVIDER_EXPORT_COUNT")
provider_exports = require_typed_exports(provider.get("exports"), "provider.exports")
allowed_exports = require_typed_exports(
source_provider.get("allowed_exports"), "source.provider.allowed_exports"
)
if len(provider_exports) != expected_export_count:
raise LockError("QuickJS provider export count disagrees with its CMake lock")
if provider_exports != allowed_exports:
raise LockError("provider export signatures disagree between JSON copies")
memory = next(item for item in provider_exports if item["kind"] == "memory")
if (
int(memory["minimum_pages"]) != PROVIDER_MEMORY_MINIMUM_PAGES
or int(memory["maximum_pages"]) != PROVIDER_MEMORY_MAXIMUM_PAGES
or memory["memory64"] is not False
or memory["shared"] is not False
):
raise LockError(
"QuickJS provider memory shape is not min 7 / max 512 / "
"memory64=false / shared=false"
)
if provider_exports != SEALED_EXPORTS:
raise LockError(
"provider export signatures disagree with the sealed F0 table"
)
surface = profile.get("javascript_surface")
nested_surface = profile.get("source", {}).get("javascript_surface")
if not isinstance(surface, dict) or not isinstance(nested_surface, dict):
raise LockError("JSON lock is missing javascript_surface")
if set(surface) != SURFACE_KEYS or set(nested_surface) != NESTED_SURFACE_KEYS:
raise LockError("javascript_surface has extra or missing keys")
declaration_sha = require_hex(
surface.get("declaration_sha256"), "javascript surface declaration SHA-256"
)
surface_sha = require_hex(surface.get("sha256"), "javascript surface SHA-256")
require_sealed(
declaration_sha,
api_identities["exact_v1_declaration"],
"exact-v1 declaration SHA-256",
)
require_sealed(
surface_sha, api_identities["selected_surface"], "selected surface SHA-256"
)
for key in ("declaration", "manifest", "schema"):
if surface.get(key) != nested_surface.get(key):
raise LockError(f"javascript_surface.{key} disagrees between JSON copies")
return (
provider_imports,
provider_exports,
native_imports,
declaration_sha,
surface_sha,
expected_size,
)
def render_source(
*,
provenance: str,
cmake: dict[str, str],
native: dict[str, Any],
provider_imports: list[dict[str, Any]],
provider_exports: list[dict[str, Any]],
native_imports: list[dict[str, Any]],
declaration_sha: str,
surface_sha: str,
broad_declaration_sha: str,
api_artifact_manifest_sha: str,
manifest_sha: str,
expected_sha: str,
expected_size: int,
wasm_bytes: bytes | None,
actual_native: str,
) -> str:
provider_names = [item["name"] for item in provider_imports]
provider_rows = ",\n ".join(
"{"
+ ", ".join(
(
quote(item["module"]),
quote(item["name"]),
quote(join_types(item["params"], f"import {item['name']} params")),
quote(join_types(item["results"], f"import {item['name']} results")),
)
)
+ "}"
for item in provider_imports
)
native_rows = ",\n ".join(
"{"
+ ", ".join(
(
quote(item["name"]),
quote(item["return_type"]),
quote(",".join(item["param_types"])),
quote(item["amendment"] or ""),
)
)
+ "}"
for item in native_imports
)
export_rows = ",\n ".join(format_export_row(item) for item in provider_exports)
source = native["source"]
memory = next(item for item in provider_exports if item["kind"] == "memory")
return f"""// Generated by cmake/GenerateQuickJSProviderBundle.py; do not edit.
// Source: {provenance}
#include <xrpld/app/hook/QuickJSHookRuntime.h>
#include <xrpld/app/hook/detail/QuickJSProviderProfile.h>
#include <array>
#include <cstdint>
#include <span>
#include <string_view>
namespace hook::artifact::generated {{
std::array<std::uint8_t, 32> const providerSHA256 = {{
{hex_bytes(expected_sha)}}};
std::array<std::uint8_t, 32> const bytecodeABI = {{
{hex_bytes(require(cmake, "BYTECODE_ABI_ID"))}}};
std::array<std::uint8_t, 32> const runtimeProfile = {{
{hex_bytes(require(cmake, "RUNTIME_PROFILE_ID"))}}};
std::string_view const providerManifestSHA256 = {quote(manifest_sha)};
std::size_t const providerSize = {expected_size};
std::uint16_t const hookApiVersion = {require(cmake, "HOOK_API_VERSION")};
std::uint64_t const initializationFuel = {require(cmake, "INITIALIZATION_FUEL")}ULL;
std::uint64_t const invocationFuel = {require(cmake, "INVOCATION_FUEL")}ULL;
std::string_view const hostWorkMeter = {quote(require(cmake, "HOST_WORK_METER"))};
std::uint64_t const hostWorkBudget = {require(cmake, "HOST_WORK_BUDGET")}ULL;
std::uint64_t const hostWorkBasePerCall = {require(cmake, "HOST_WORK_BASE_PER_CALL")}ULL;
std::uint64_t const hostWorkPerAddressedByte =
{require(cmake, "HOST_WORK_PER_ADDRESSED_BYTE")}ULL;
std::string_view const hostAdapterPolicy = {quote(require(cmake, "HOST_ADAPTER_POLICY"))};
std::uint32_t const heapBytes = {require(cmake, "HEAP_BYTES")}U;
std::uint32_t const stackBytes = {require(cmake, "STACK_BYTES")}U;
std::uint32_t const wasmStackBytes = {WASM_STACK_BYTES}U;
std::uint32_t const serializedObjectMaxBytes =
{require(cmake, "SERIALIZED_OBJECT_MAX_BYTES")}U;
std::uint32_t const serializedObjectMaxFields =
{require(cmake, "SERIALIZED_OBJECT_MAX_FIELDS")}U;
std::uint32_t const serializedObjectMaxScopes =
{require(cmake, "SERIALIZED_OBJECT_MAX_SCOPES")}U;
std::uint32_t const serializedObjectMaxDepth =
{require(cmake, "SERIALIZED_OBJECT_MAX_DEPTH")}U;
std::uint32_t const providerMemoryMinimumPages = {int(memory["minimum_pages"])}U;
std::uint32_t const providerMemoryMaximumPages = {int(memory["maximum_pages"])}U;
bool const providerMemory64 = false;
bool const providerMemoryShared = false;
std::string_view const javascriptBroadDeclarationSHA256 =
{quote(broad_declaration_sha)};
std::string_view const javascriptExactV1DeclarationSHA256 =
{quote(declaration_sha)};
std::string_view const javascriptSurfaceSHA256 = {quote(surface_sha)};
std::string_view const javascriptAPIArtifactManifestSHA256 =
{quote(api_artifact_manifest_sha)};
namespace {{
std::string_view const providerImportNames[] = {{
{", ".join(quote(name) for name in provider_names)}}};
std::string_view const providerExportNames[] = {{
{", ".join(quote(item["name"]) for item in provider_exports)}}};
ProviderImportSignature const providerImportSignatureData[] = {{
{provider_rows}}};
ProviderExportSignature const providerExportSignatureData[] = {{
{export_rows}}};
NativeImportSignature const nativeImportSignatureData[] = {{
{native_rows}}};
}} // namespace
std::span<std::string_view const> const providerImports{{providerImportNames}};
std::span<std::string_view const> const providerExports{{providerExportNames}};
std::span<ProviderImportSignature const> const providerImportSignatures{{
providerImportSignatureData}};
std::span<ProviderExportSignature const> const providerExportSignatures{{
providerExportSignatureData}};
std::span<NativeImportSignature const> const nativeImportSignatures{{
nativeImportSignatureData}};
std::string_view const nativeABISourceRepository = {quote(source["repository"])};
std::string_view const nativeABISourceCommit = {quote(source["commit"])};
std::string_view const nativeABISourcePath = {quote(source["path"])};
std::string_view const nativeABISHA256 = {quote(actual_native)};
std::size_t const nativeABICatalogueCount = {source["macro_function_count"]};
}} // namespace hook::artifact::generated
namespace hook {{
{embed_body(wasm_bytes)}
}} // namespace hook
"""
def project_bundle(bundle: Path, wasmtime_version: str, output: Path) -> int:
profile_path = bundle / "jshookz_provider.manifest.json"
cmake_path = bundle / "jshookz_provider.manifest.cmake"
native_path = bundle / "jshookz_provider.native-abi.json"
api_manifest_path = bundle / "api-artifacts.json"
api_paths = tuple(
bundle / local_name
for _, local_name, _ in SEALED_API_ARTIFACTS.values()
)
for path in (profile_path, cmake_path, native_path, api_manifest_path, *api_paths):
if not path.is_file():
print(f"missing sealed QuickJS bundle file: {path}", file=sys.stderr)
return 1
cmake = parse_cmake(cmake_path)
actual_manifest = hashlib.sha256(profile_path.read_bytes()).hexdigest()
if actual_manifest != require(cmake, "MANIFEST_SHA256"):
print(
"QuickJS provider JSON manifest does not match its CMake projection",
file=sys.stderr,
)
return 1
actual_native = hashlib.sha256(native_path.read_bytes()).hexdigest()
if actual_native != require(cmake, "NATIVE_ABI_SHA256"):
print(
"QuickJS native ABI snapshot does not match its sealed digest",
file=sys.stderr,
)
return 1
try:
profile = json.loads(profile_path.read_text())
native = json.loads(native_path.read_text())
api_identities = validate_api_artifacts(bundle)
(
provider_imports,
provider_exports,
native_imports,
declaration_sha,
surface_sha,
expected_size,
) = validate_lock(
profile, native, cmake, wasmtime_version, api_identities
)
require_sealed(
actual_manifest, SEALED_MANIFEST_SHA256, "provider manifest SHA-256"
)
require_sealed(
actual_native, SEALED_NATIVE_ABI_SHA256, "native ABI SHA-256"
)
except LockError as error:
print(str(error), file=sys.stderr)
return 1
wasm_name = require(cmake, "PROVIDER_FILE")
wasm_path = bundle / wasm_name
expected_sha = require(cmake, "PROVIDER_SHA256").lower()
fingerprint = hashlib.sha256()
for path in (
profile_path,
cmake_path,
native_path,
api_manifest_path,
*api_paths,
Path(__file__),
):
fingerprint.update(path.read_bytes())
fingerprint.update(wasmtime_version.encode())
wasm_bytes: bytes | None = None
if wasm_path.is_file():
wasm_bytes = wasm_path.read_bytes()
digest = hashlib.sha256(wasm_bytes).hexdigest()
if digest != expected_sha or len(wasm_bytes) != expected_size:
print(
"QuickJS provider WASM does not match its generated manifest",
file=sys.stderr,
)
return 1
fingerprint.update(b"wasm")
fingerprint.update(bytes.fromhex(digest))
provenance = f"{wasm_path} sha256={digest} size={len(wasm_bytes)}"
else:
fingerprint.update(b"absent")
provenance = "no provider binary was present in the bundle directory"
stamp_path = output.with_name(output.name + ".stamp")
stamp = fingerprint.hexdigest()
if output.is_file() and stamp_path.is_file() and stamp_path.read_text() == stamp:
return 0
if wasm_bytes is None:
print(
f"No QuickJS provider WASM at {wasm_path}; nothing is embedded "
"and the daemon will refuse to start",
file=sys.stderr,
)
text = render_source(
provenance=provenance,
cmake=cmake,
native=native,
provider_imports=provider_imports,
provider_exports=provider_exports,
native_imports=native_imports,
declaration_sha=declaration_sha,
surface_sha=surface_sha,
broad_declaration_sha=api_identities["broad_declaration"],
api_artifact_manifest_sha=api_identities["api_artifact_manifest"],
manifest_sha=actual_manifest,
expected_sha=expected_sha,
expected_size=expected_size,
wasm_bytes=wasm_bytes,
actual_native=actual_native,
)
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(text)
stamp_path.write_text(stamp)
return 0
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--bundle-dir", type=Path, required=True)
parser.add_argument("--wasmtime-version", required=True)
parser.add_argument("--output", type=Path, required=True)
args = parser.parse_args()
try:
return project_bundle(args.bundle_dir, args.wasmtime_version, args.output)
except LockError as error:
print(str(error), file=sys.stderr)
return 1
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -1,90 +0,0 @@
set(XAHAU_QUICKJS_PROVIDER_BUNDLE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/external/quickjs-provider"
CACHE PATH
"Directory containing the sealed QuickJS provider WASM and generated manifests")
get_filename_component(XAHAU_QUICKJS_PROVIDER_BUNDLE_DIR
"${XAHAU_QUICKJS_PROVIDER_BUNDLE_DIR}"
ABSOLUTE
BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(XAHAU_QUICKJS_PROVIDER_MANIFEST
"${XAHAU_QUICKJS_PROVIDER_BUNDLE_DIR}/jshookz_provider.manifest.cmake")
set(XAHAU_QUICKJS_PROVIDER_PROFILE_LOCK
"${XAHAU_QUICKJS_PROVIDER_BUNDLE_DIR}/jshookz_provider.manifest.json")
set(XAHAU_QUICKJS_NATIVE_ABI
"${XAHAU_QUICKJS_PROVIDER_BUNDLE_DIR}/jshookz_provider.native-abi.json")
set(XAHAU_QUICKJS_API_ARTIFACT_MANIFEST
"${XAHAU_QUICKJS_PROVIDER_BUNDLE_DIR}/api-artifacts.json")
set(XAHAU_QUICKJS_BROAD_DECLARATION
"${XAHAU_QUICKJS_PROVIDER_BUNDLE_DIR}/hooks-api.d.ts")
set(XAHAU_QUICKJS_EXACT_V1_DECLARATION
"${XAHAU_QUICKJS_PROVIDER_BUNDLE_DIR}/xahau-quickjs-v1.d.ts")
set(XAHAU_QUICKJS_SELECTED_SURFACE
"${XAHAU_QUICKJS_PROVIDER_BUNDLE_DIR}/xahau-quickjs-v1.surface.json")
foreach(_bundle_file
"${XAHAU_QUICKJS_PROVIDER_MANIFEST}"
"${XAHAU_QUICKJS_PROVIDER_PROFILE_LOCK}"
"${XAHAU_QUICKJS_NATIVE_ABI}"
"${XAHAU_QUICKJS_API_ARTIFACT_MANIFEST}"
"${XAHAU_QUICKJS_BROAD_DECLARATION}"
"${XAHAU_QUICKJS_EXACT_V1_DECLARATION}"
"${XAHAU_QUICKJS_SELECTED_SURFACE}")
if(NOT EXISTS "${_bundle_file}")
message(FATAL_ERROR
"Missing sealed QuickJS provider bundle file: ${_bundle_file}")
endif()
endforeach()
if(NOT DEFINED wasmtime_VERSION_STRING OR wasmtime_VERSION_STRING STREQUAL "")
message(FATAL_ERROR
"QuickJS provider requires an exact Wasmtime version, but the resolved "
"package did not publish one")
endif()
find_program(XAHAU_QUICKJS_PYTHON NAMES python3 python)
if(NOT XAHAU_QUICKJS_PYTHON)
message(FATAL_ERROR
"Python is required to project the sealed QuickJS provider bundle")
endif()
set(XAHAU_QUICKJS_GENERATED_INCLUDE_DIR
"${CMAKE_CURRENT_BINARY_DIR}/generated")
set(XAHAU_QUICKJS_PROVIDER_VALUES_SOURCE
"${XAHAU_QUICKJS_GENERATED_INCLUDE_DIR}/xrpld/app/hook/detail/QuickJSProviderValues.cpp")
set(XAHAU_QUICKJS_BUNDLE_SCRIPT
"${CMAKE_CURRENT_LIST_DIR}/GenerateQuickJSProviderBundle.py")
# The gitignored wasm is not a CMake depend (ninja cannot name a missing
# file). Refresh on every rippled build; the script no-ops when inputs
# including wasm existence/digest are unchanged.
add_custom_target(xahau_quickjs_refresh_provider
COMMAND
"${XAHAU_QUICKJS_PYTHON}"
"${XAHAU_QUICKJS_BUNDLE_SCRIPT}"
--bundle-dir "${XAHAU_QUICKJS_PROVIDER_BUNDLE_DIR}"
--wasmtime-version "${wasmtime_VERSION_STRING}"
--output "${XAHAU_QUICKJS_PROVIDER_VALUES_SOURCE}"
BYPRODUCTS "${XAHAU_QUICKJS_PROVIDER_VALUES_SOURCE}"
DEPENDS
"${XAHAU_QUICKJS_PROVIDER_PROFILE_LOCK}"
"${XAHAU_QUICKJS_PROVIDER_MANIFEST}"
"${XAHAU_QUICKJS_NATIVE_ABI}"
"${XAHAU_QUICKJS_API_ARTIFACT_MANIFEST}"
"${XAHAU_QUICKJS_BROAD_DECLARATION}"
"${XAHAU_QUICKJS_EXACT_V1_DECLARATION}"
"${XAHAU_QUICKJS_SELECTED_SURFACE}"
"${XAHAU_QUICKJS_BUNDLE_SCRIPT}"
COMMENT "Projecting sealed QuickJS provider values"
VERBATIM)
message(STATUS
"QuickJS provider values: ${XAHAU_QUICKJS_PROVIDER_VALUES_SOURCE}")
add_custom_target(xahau_quickjs_lock_mutations
COMMAND
"${XAHAU_QUICKJS_PYTHON}"
"${CMAKE_CURRENT_LIST_DIR}/test_generate_quickjs_provider_bundle.py"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Proving sealed QuickJS lock mutation reds"
VERBATIM)

View File

@@ -54,7 +54,6 @@ add_library(xrpl.imports.main INTERFACE)
target_link_libraries(xrpl.imports.main
INTERFACE
LibArchive::LibArchive
magic_enum::magic_enum
OpenSSL::Crypto
Ripple::boost
wasmedge::wasmedge
@@ -69,17 +68,6 @@ target_link_libraries(xrpl.imports.main
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp>
)
# date-tz for enhanced logging (always linked, code is #ifdef guarded)
if(TARGET date::date-tz)
target_link_libraries(xrpl.imports.main INTERFACE date::date-tz)
endif()
# BEAST_ENHANCED_LOGGING: enable for Debug builds OR when explicitly requested
# Uses generator expression so it works with multi-config generators (Xcode, VS, Ninja Multi-Config)
target_compile_definitions(xrpl.imports.main INTERFACE
$<$<OR:$<CONFIG:Debug>,$<BOOL:${BEAST_ENHANCED_LOGGING}>>:BEAST_ENHANCED_LOGGING=1>
)
include(add_module)
include(target_link_modules)
@@ -90,6 +78,12 @@ target_link_libraries(xrpl.libxrpl.beast PUBLIC
xrpl.libpb
)
# Conditionally add enhanced logging source when BEAST_ENHANCED_LOGGING is enabled
if(DEFINED BEAST_ENHANCED_LOGGING AND BEAST_ENHANCED_LOGGING)
target_sources(xrpl.libxrpl.beast PRIVATE
src/libxrpl/beast/utility/src/beast_EnhancedLogging.cpp)
endif()
# Level 02
add_module(xrpl basics)
target_link_libraries(xrpl.libxrpl.basics PUBLIC xrpl.libxrpl.beast)
@@ -174,106 +168,18 @@ if(xrpld)
"${CMAKE_CURRENT_SOURCE_DIR}/src/xrpld/*.cpp"
)
target_sources(rippled PRIVATE ${sources})
add_dependencies(rippled xahau_quickjs_refresh_provider)
target_sources(rippled PRIVATE "${XAHAU_QUICKJS_PROVIDER_VALUES_SOURCE}")
if(tests)
file(GLOB_RECURSE sources CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/src/test/*.cpp"
)
if(HOOKS_TEST_ONLY OR DEFINED ENV{HOOKS_TEST_ONLY})
list(FILTER sources EXCLUDE REGEX "_test\\.cpp$")
message(STATUS "HOOKS_TEST_ONLY: excluded *_test.cpp from src/test/")
endif()
target_sources(rippled PRIVATE ${sources})
# External Env tests live next to the producer. Point at a directory of
# *_test.cpp files (typically jshookz/env-tests). hookz build-test-hooks
# must be on PATH. Coverage is not wired here.
if(NOT HOOKS_TEST_DIR AND DEFINED ENV{HOOKS_TEST_DIR})
set(HOOKS_TEST_DIR $ENV{HOOKS_TEST_DIR})
endif()
if(NOT HOOKS_SOURCE_DIR AND DEFINED ENV{HOOKS_SOURCE_DIR})
set(HOOKS_SOURCE_DIR $ENV{HOOKS_SOURCE_DIR})
endif()
if(HOOKS_TEST_DIR AND EXISTS "${HOOKS_TEST_DIR}")
file(GLOB EXTERNAL_HOOK_TESTS CONFIGURE_DEPENDS
"${HOOKS_TEST_DIR}/*_test.cpp"
)
if(EXTERNAL_HOOK_TESTS)
set(_hooks_extra_args "")
set(_hooks_source_deps "")
if(HOOKS_SOURCE_DIR)
foreach(_dir ${HOOKS_SOURCE_DIR})
list(APPEND _hooks_extra_args "--hooks-c-dir" "${_dir}")
string(REGEX REPLACE "^[^=]+=" "" _hook_dir "${_dir}")
if(EXISTS "${_hook_dir}")
file(GLOB_RECURSE _hook_dir_deps CONFIGURE_DEPENDS
"${_hook_dir}/*.c"
"${_hook_dir}/*.h"
"${_hook_dir}/*.ts"
"${_hook_dir}/*.js"
)
if(HOOKS_TEST_DIR)
list(FILTER _hook_dir_deps EXCLUDE REGEX "^${HOOKS_TEST_DIR}/")
endif()
list(APPEND _hooks_source_deps ${_hook_dir_deps})
endif()
endforeach()
list(REMOVE_DUPLICATES _hooks_source_deps)
endif()
set(_hooks_always_run OFF)
if(HOOKS_FORCE_RECOMPILE OR DEFINED ENV{HOOKS_FORCE_RECOMPILE})
list(APPEND _hooks_extra_args "--force-write" "--no-cache")
set(_hooks_always_run ON)
message(STATUS "Hook force recompile enabled (cache bypassed)")
endif()
foreach(_test_file ${EXTERNAL_HOOK_TESTS})
get_filename_component(_stem ${_test_file} NAME_WE)
set(_hooks_header "${HOOKS_TEST_DIR}/${_stem}_hooks.h")
if(_hooks_always_run)
add_custom_target(compile_hooks_${_stem} ALL
COMMAND hookz build-test-hooks "${_test_file}" ${_hooks_extra_args}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Compiling hooks for ${_stem} (forced)"
VERBATIM
)
list(APPEND EXTERNAL_HOOK_TARGETS compile_hooks_${_stem})
else()
add_custom_command(
OUTPUT "${_hooks_header}"
COMMAND hookz build-test-hooks "${_test_file}" ${_hooks_extra_args}
DEPENDS "${_test_file}" ${_hooks_source_deps}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Compiling hooks for ${_stem}"
VERBATIM
)
list(APPEND EXTERNAL_HOOK_HEADERS "${_hooks_header}")
endif()
endforeach()
if(_hooks_always_run)
foreach(_tgt ${EXTERNAL_HOOK_TARGETS})
add_dependencies(rippled ${_tgt})
endforeach()
else()
add_custom_target(compile_external_hooks DEPENDS ${EXTERNAL_HOOK_HEADERS})
add_dependencies(rippled compile_external_hooks)
endif()
target_sources(rippled PRIVATE ${EXTERNAL_HOOK_TESTS})
set_property(
SOURCE ${EXTERNAL_HOOK_TESTS}
APPEND PROPERTY INCLUDE_DIRECTORIES "${HOOKS_TEST_DIR}"
)
message(STATUS "Including external hook tests from: ${HOOKS_TEST_DIR}")
endif()
endif()
endif()
target_link_libraries(rippled
Ripple::boost
Ripple::opts
Ripple::libs
wasmtime::wasmtime
xrpl.libxrpl
# Workaround for a Conan 1.x bug that prevents static linking of libstdc++
# when a dependency (snappy) modifies system_libs. See the comment in

View File

@@ -1,4 +1,4 @@
find_package(Boost 1.86 REQUIRED
find_package(Boost 1.83 REQUIRED
COMPONENTS
chrono
container
@@ -7,7 +7,6 @@ find_package(Boost 1.86 REQUIRED
date_time
filesystem
json
json
program_options
regex
system
@@ -32,6 +31,7 @@ target_link_libraries(ripple_boost
Boost::date_time
Boost::filesystem
Boost::json
Boost::iostreams
Boost::program_options
Boost::regex
Boost::system

View File

@@ -1 +0,0 @@
find_package(wasmtime REQUIRED)

View File

@@ -8,7 +8,7 @@
# those warnings.
if (RIPPLED_SOURCE)
execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different
${RIPPLED_SOURCE}/Builds/CMake/SociConfig.cmake.patched
${RIPPLED_SOURCE}/cmake/SociConfig.cmake.patched
cmake/SociConfig.cmake )
endif ()

View File

@@ -1,756 +0,0 @@
#!/usr/bin/env python3
"""Fail-closed generator/checker mutation reds for the sealed QuickJS lock."""
from __future__ import annotations
import hashlib
import json
import re
import shutil
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SCRIPT = Path(__file__).with_name("GenerateQuickJSProviderBundle.py")
BUNDLE = ROOT / "external" / "quickjs-provider"
WASM_VERSION = "47.0.3"
CMAKE_SET = re.compile(r'^set\(XAHAU_QUICKJS_([A-Z0-9_]+) "([^"]*)"\)\s*$')
PIN = {
"provider_sha256": "f60ab333acb547e50d7d087960839bd11833cb133d496af98e0b72a1bb3b84df",
"provider_size": "1116638",
"manifest_sha256": "1673b27d21063957cece9095cceb7e2dbfa53b6f49a5b7f824a486d7d90b2391",
"runtime_profile_id": "29acf12e170436e5ccadfbc118d02a60909f86a88262106652b2f71994b0ea25",
"broad_declaration_sha256": "649079b831bc68eff0f440644649a505addafb08a3f5174e4031c8de6aedffa0",
"exact_v1_declaration_sha256": "20881232f0602e35de0fcbb8b5a3c1511606392749a0f79daebb386204f4f4da",
"surface_sha256": "96a9218bf38abbf1bc9f2839408700d03572e0b065d625263f70477bc32597ac",
"api_artifact_manifest_sha256": "95babf622bf5edff76fdcbd9746bad8f1f8b275a3d4bacdc320ff4deae543eba",
"bytecode_abi": "75ea54f357d397c4b33899e495bb385dad975a43b1c4a7a2cead30474327d33e",
"native_abi": "328ec938dcad875f3bdf25b8d779dd77f3571589818ca9271cb98c64c7018f99",
"wasm_stack_bytes": "131072",
}
RECEIPT_B = {
"provider_sha256": "40f9ac0203afa9296196c627bc94e669ad789322ddc1e4ab58ba0cf6d32a5e21",
"provider_size": "1101461",
"runtime_profile_id": "60950ca8b6fe4dd2a35559367051998bc04f75e8aa41934dd4caad0de5a1c3ba",
"declaration_sha256": "56b4b2974b8a63a550721abd60350e392990762e76666f050b1a7c810e584957",
"surface_sha256": "b112346b95da74d04930ba86bd597e56a428e41e11581804ccc49907ae206eb0",
}
TYPED_IMPORT_ROWS = (
'{"env", "accept", "i32,i32,i64", "i64"}',
'{"env", "emit", "i32,i32,i32,i32", "i64"}',
'{"env", "etxn_reserve", "i32", "i64"}',
'{"env", "hook_account", "i32,i32", "i64"}',
'{"env", "ledger_last_hash", "i32,i32", "i64"}',
'{"env", "ledger_last_time", "", "i64"}',
'{"env", "ledger_seq", "", "i64"}',
'{"env", "otxn_type", "", "i64"}',
'{"env", "prepare", "i32,i32,i32,i32", "i64"}',
'{"env", "rollback", "i32,i32,i64", "i64"}',
'{"env", "state", "i32,i32,i32,i32", "i64"}',
'{"env", "state_set", "i32,i32,i32,i32", "i64"}',
'{"env", "trace", "i32,i32,i32,i32,i32", "i64"}',
)
TYPED_EXPORT_ROWS = (
'{"function", "_initialize", "", "", 0U, 0U, false, false}',
'{"function", "free", "i32", "", 0U, 0U, false, false}',
'{"function", "malloc", "i32", "i32", 0U, 0U, false, false}',
'{"memory", "memory", "", "", 7U, 512U, false, false}',
'{"function", "qjs_cbak", "i32,i32,i32", "i32", 0U, 0U, false, false}',
'{"function", "qjs_compile", "i32,i32", "i32", 0U, 0U, false, false}',
'{"function", "qjs_compile_module", "i32,i32", "i32", 0U, 0U, false, false}',
'{"function", "qjs_destroy", "", "", 0U, 0U, false, false}',
'{"function", "qjs_enable_coverage", "i32", "", 0U, 0U, false, false}',
'{"function", "qjs_eval", "i32,i32", "i32", 0U, 0U, false, false}',
'{"function", "qjs_eval_bytecode", "i32,i32", "i32", 0U, 0U, false, false}',
'{"function", "qjs_eval_module", "i32,i32", "i32", 0U, 0U, false, false}',
'{"function", "qjs_get_bytecode_len", "", "i32", 0U, 0U, false, false}',
'{"function", "qjs_get_bytecode_ptr", "", "i32", 0U, 0U, false, false}',
'{"function", "qjs_get_result_len", "", "i32", 0U, 0U, false, false}',
'{"function", "qjs_get_result_ptr", "", "i32", 0U, 0U, false, false}',
'{"function", "qjs_hook", "i32,i32,i32", "i32", 0U, 0U, false, false}',
'{"function", "qjs_init", "", "", 0U, 0U, false, false}',
'{"function", "qjs_set_max_stack_size", "i32", "", 0U, 0U, false, false}',
'{"function", "qjs_set_memory_limit", "i32", "", 0U, 0U, false, false}',
'{"function", "qjs_set_seed", "i32", "", 0U, 0U, false, false}',
'{"function", "qjs_validate_hook_module", "i32,i32", "i32", 0U, 0U, false, false}',
)
def json_path(bundle: Path) -> Path:
return bundle / "jshookz_provider.manifest.json"
def cmake_path(bundle: Path) -> Path:
return bundle / "jshookz_provider.manifest.cmake"
def native_path(bundle: Path) -> Path:
return bundle / "jshookz_provider.native-abi.json"
def wasm_path(bundle: Path) -> Path:
return bundle / "jshookz_provider.wasm"
def api_manifest_path(bundle: Path) -> Path:
return bundle / "api-artifacts.json"
def broad_declaration_path(bundle: Path) -> Path:
return bundle / "hooks-api.d.ts"
def exact_v1_declaration_path(bundle: Path) -> Path:
return bundle / "xahau-quickjs-v1.d.ts"
def surface_path(bundle: Path) -> Path:
return bundle / "xahau-quickjs-v1.surface.json"
def load_json(bundle: Path) -> dict:
return json.loads(json_path(bundle).read_text())
def write_json(bundle: Path, data: dict) -> None:
json_path(bundle).write_text(json.dumps(data, indent=2) + "\n")
def set_cmake(bundle: Path, key: str, value: str) -> None:
path = cmake_path(bundle)
lines = []
replaced = False
for line in path.read_text().splitlines():
match = CMAKE_SET.match(line)
if match and match.group(1) == key:
lines.append(f'set(XAHAU_QUICKJS_{key} "{value}")')
replaced = True
else:
lines.append(line)
if not replaced:
raise AssertionError(f"CMake lock is missing {key}")
path.write_text("\n".join(lines) + "\n")
def rehash_manifest(bundle: Path) -> None:
digest = hashlib.sha256(json_path(bundle).read_bytes()).hexdigest()
set_cmake(bundle, "MANIFEST_SHA256", digest)
def rehash_native(bundle: Path) -> None:
digest = hashlib.sha256(native_path(bundle).read_bytes()).hexdigest()
set_cmake(bundle, "NATIVE_ABI_SHA256", digest)
def load_api_manifest(bundle: Path) -> dict:
return json.loads(api_manifest_path(bundle).read_text())
def write_api_manifest(bundle: Path, data: dict) -> None:
api_manifest_path(bundle).write_text(json.dumps(data, indent=2) + "\n")
def clone_bundle(root: Path) -> Path:
dest = root / "bundle"
shutil.copytree(BUNDLE, dest, ignore=shutil.ignore_patterns("README.md"))
return dest
def generate(
bundle: Path, work: Path, wasmtime_version: str = WASM_VERSION
) -> tuple[int, str, str]:
output = work / "QuickJSProviderValues.cpp"
completed = subprocess.run(
[
sys.executable,
str(SCRIPT),
"--bundle-dir",
str(bundle),
"--wasmtime-version",
wasmtime_version,
"--output",
str(output),
],
check=False,
capture_output=True,
text=True,
)
cpp = output.read_text() if output.is_file() else ""
return completed.returncode, completed.stderr, cpp
def hex_bytes(value: str) -> str:
return ", ".join(f"0x{value[i:i + 2]}" for i in range(0, 64, 2))
def pin_holds(returncode: int, cpp: str) -> bool:
if returncode != 0 or not cpp:
return False
required = [
hex_bytes(PIN["provider_sha256"]),
f"std::size_t const providerSize = {PIN['provider_size']};",
f'"{PIN["manifest_sha256"]}"',
hex_bytes(PIN["runtime_profile_id"]),
f'"{PIN["broad_declaration_sha256"]}"',
f'"{PIN["exact_v1_declaration_sha256"]}"',
f'"{PIN["surface_sha256"]}"',
f'"{PIN["api_artifact_manifest_sha256"]}"',
hex_bytes(PIN["bytecode_abi"]),
f'"{PIN["native_abi"]}"',
f"std::uint32_t const wasmStackBytes = {PIN['wasm_stack_bytes']}U;",
"std::uint32_t const serializedObjectMaxBytes =\n 1048576U;",
"std::uint32_t const serializedObjectMaxFields =\n 32768U;",
"std::uint32_t const serializedObjectMaxScopes =\n 32769U;",
"std::uint32_t const serializedObjectMaxDepth =\n 10U;",
"std::uint32_t const providerMemoryMinimumPages = 7U;",
"std::uint32_t const providerMemoryMaximumPages = 512U;",
"constexpr char const sealedProvider[] =",
f"sizeof(sealedProvider) - 1 == {PIN['provider_size']}",
]
if any(item not in cpp for item in required):
return False
return all(row in cpp for row in (*TYPED_IMPORT_ROWS, *TYPED_EXPORT_ROWS))
class GenerateQuickJSProviderBundleTest(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
missing = [
path.name
for path in (
json_path(BUNDLE),
cmake_path(BUNDLE),
native_path(BUNDLE),
wasm_path(BUNDLE),
api_manifest_path(BUNDLE),
broad_declaration_path(BUNDLE),
exact_v1_declaration_path(BUNDLE),
surface_path(BUNDLE),
SCRIPT,
)
if not path.is_file()
]
if missing:
raise AssertionError(
"sealed QuickJS bundle is incomplete: " + ", ".join(missing)
)
def mutate(
self, mutator, wasmtime_version: str = WASM_VERSION
) -> tuple[int, str, str]:
with tempfile.TemporaryDirectory() as tmp:
work = Path(tmp)
bundle = clone_bundle(work)
mutator(bundle)
return generate(bundle, work / "out", wasmtime_version)
def assert_generator_red(
self, mutator, fragment: str, wasmtime_version: str = WASM_VERSION
) -> None:
returncode, stderr, cpp = self.mutate(mutator, wasmtime_version)
self.assertNotEqual(returncode, 0, stderr)
self.assertIn(fragment, stderr)
self.assertFalse(pin_holds(returncode, cpp), stderr)
def test_unmutated_lock_projects_pin_and_typed_exports(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
work = Path(tmp)
returncode, stderr, cpp = generate(clone_bundle(work), work / "out")
self.assertEqual(returncode, 0, stderr)
self.assertTrue(pin_holds(returncode, cpp), stderr)
self.assertEqual(cpp.count("ProviderExportSignature const"), 2)
def test_provider_bytes_mutation(self) -> None:
def mutate(bundle: Path) -> None:
path = wasm_path(bundle)
data = bytearray(path.read_bytes())
data[-1] ^= 0xFF
path.write_bytes(data)
self.assert_generator_red(mutate, "WASM does not match")
def test_provider_size_mutation(self) -> None:
def mutate(bundle: Path) -> None:
set_cmake(bundle, "PROVIDER_SIZE", "1116637")
self.assert_generator_red(mutate, "provider size disagrees")
def test_coordinated_provider_size_mutation(self) -> None:
def mutate(bundle: Path) -> None:
value = 1116637
data = load_json(bundle)
data["provider"]["size"] = value
write_json(bundle, data)
rehash_manifest(bundle)
set_cmake(bundle, "PROVIDER_SIZE", str(value))
self.assert_generator_red(mutate, "provider size disagrees with the sealed F0")
def test_provider_sha_mutation(self) -> None:
def mutate(bundle: Path) -> None:
set_cmake(
bundle,
"PROVIDER_SHA256",
"00" + PIN["provider_sha256"][2:],
)
self.assert_generator_red(mutate, "provider sha256 disagrees")
def test_coordinated_provider_sha_mutation(self) -> None:
def mutate(bundle: Path) -> None:
value = "00" + PIN["provider_sha256"][2:]
data = load_json(bundle)
data["provider"]["sha256"] = value
write_json(bundle, data)
rehash_manifest(bundle)
set_cmake(bundle, "PROVIDER_SHA256", value)
self.assert_generator_red(mutate, "provider SHA-256 disagrees with the sealed F0")
def test_manifest_sha_mutation(self) -> None:
def mutate(bundle: Path) -> None:
set_cmake(
bundle,
"MANIFEST_SHA256",
"00" + PIN["manifest_sha256"][2:],
)
self.assert_generator_red(mutate, "JSON manifest does not match")
def test_coordinated_manifest_identity_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["diagnostic_note"] = "not F0"
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "provider manifest SHA-256")
def test_runtime_profile_id_mutation(self) -> None:
def mutate(bundle: Path) -> None:
set_cmake(
bundle,
"RUNTIME_PROFILE_ID",
"00" + PIN["runtime_profile_id"][2:],
)
self.assert_generator_red(mutate, "runtime-profile ID disagrees")
def test_coordinated_runtime_profile_id_mutation(self) -> None:
def mutate(bundle: Path) -> None:
value = "00" + PIN["runtime_profile_id"][2:]
data = load_json(bundle)
data["runtime_profile_id"] = value
write_json(bundle, data)
rehash_manifest(bundle)
set_cmake(bundle, "RUNTIME_PROFILE_ID", value)
self.assert_generator_red(mutate, "runtime-profile ID disagrees with the sealed F0")
def _coordinated_api_artifact_mutation(
self, source_path: str, local_path, fragment: str
) -> None:
def mutate(bundle: Path) -> None:
path = local_path(bundle)
path.write_bytes(path.read_bytes() + b"\n")
manifest = load_api_manifest(bundle)
manifest["artifacts"][source_path] = hashlib.sha256(
path.read_bytes()
).hexdigest()
write_api_manifest(bundle, manifest)
self.assert_generator_red(mutate, fragment)
def test_broad_declaration_identity_mutation(self) -> None:
self._coordinated_api_artifact_mutation(
"python/jshookz/src/jshookz/types/hooks-api.d.ts",
broad_declaration_path,
"hooks-api.d.ts disagrees with the sealed F0 table",
)
def test_exact_v1_declaration_identity_mutation(self) -> None:
self._coordinated_api_artifact_mutation(
"python/jshookz/src/jshookz/types/xahau-quickjs-v1.d.ts",
exact_v1_declaration_path,
"xahau-quickjs-v1.d.ts disagrees with the sealed F0 table",
)
def test_selected_surface_identity_mutation(self) -> None:
self._coordinated_api_artifact_mutation(
"python/jshookz/src/jshookz/types/xahau-quickjs-v1.surface.json",
surface_path,
"xahau-quickjs-v1.surface.json disagrees with the sealed F0 table",
)
def test_api_artifact_manifest_identity_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_api_manifest(bundle)
api_manifest_path(bundle).write_text(json.dumps(data, indent=4) + "\n")
self.assert_generator_red(mutate, "API artifact manifest SHA-256")
def test_declaration_sha_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["javascript_surface"]["declaration_sha256"] = (
"00" + PIN["exact_v1_declaration_sha256"][2:]
)
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "declaration SHA-256 disagrees")
def test_surface_sha_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["javascript_surface"]["sha256"] = "00" + PIN["surface_sha256"][2:]
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "surface SHA-256 disagrees")
def test_bytecode_abi_mutation(self) -> None:
def mutate(bundle: Path) -> None:
set_cmake(bundle, "BYTECODE_ABI_ID", "00" + PIN["bytecode_abi"][2:])
self.assert_generator_red(mutate, "bytecode ABI disagrees")
def test_coordinated_bytecode_abi_mutation(self) -> None:
def mutate(bundle: Path) -> None:
value = "00" + PIN["bytecode_abi"][2:]
data = load_json(bundle)
data["bytecode_abi_id"] = value
write_json(bundle, data)
rehash_manifest(bundle)
set_cmake(bundle, "BYTECODE_ABI_ID", value)
self.assert_generator_red(mutate, "bytecode ABI disagrees with the sealed F0")
def test_native_abi_mutation(self) -> None:
def mutate(bundle: Path) -> None:
set_cmake(bundle, "NATIVE_ABI_SHA256", "00" + PIN["native_abi"][2:])
self.assert_generator_red(mutate, "native ABI snapshot does not match")
def test_coordinated_native_abi_identity_mutation(self) -> None:
def mutate(bundle: Path) -> None:
path = native_path(bundle)
path.write_bytes(path.read_bytes() + b"\n")
rehash_native(bundle)
self.assert_generator_red(mutate, "native ABI SHA-256")
def test_import_signature_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["provider"]["imports"][0]["params"].append("i32")
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "import signatures disagree")
def test_export_signature_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
for item in data["provider"]["exports"]:
if item["name"] == "qjs_hook":
item["params"].append("i32")
break
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "export signatures disagree")
def test_coordinated_export_signature_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
for collection in (
data["provider"]["exports"],
data["source"]["provider"]["allowed_exports"],
):
for item in collection:
if item["name"] == "qjs_hook":
item["params"].append("i32")
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "sealed F0 table")
def test_coordinated_wasi_import_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
for collection in (
data["provider"]["imports"],
data["source"]["provider"]["imports"],
):
for item in collection:
if item["name"] == "accept":
item["module"] = "wasi_snapshot_preview1"
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "sealed F0 table")
def test_coordinated_import_signature_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
for collection in (
data["provider"]["imports"],
data["source"]["provider"]["imports"],
):
for item in collection:
if item["name"] == "accept":
item["params"].append("i32")
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "sealed F0 table")
def test_export_extra_key_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
for collection in (
data["provider"]["exports"],
data["source"]["provider"]["allowed_exports"],
):
for item in collection:
if item["name"] == "qjs_init":
item["note"] = "extra"
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "extra or missing keys")
def _memory_shape_mutation(self, key: str, value) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
for collection in (
data["provider"]["exports"],
data["source"]["provider"]["allowed_exports"],
):
for item in collection:
if item["kind"] == "memory":
item[key] = value
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "memory")
def test_memory_minimum_shape_mutation(self) -> None:
self._memory_shape_mutation("minimum_pages", 6)
def test_memory_maximum_shape_mutation(self) -> None:
self._memory_shape_mutation("maximum_pages", 511)
def test_memory64_shape_mutation(self) -> None:
self._memory_shape_mutation("memory64", True)
def test_shared_memory_shape_mutation(self) -> None:
self._memory_shape_mutation("shared", True)
def test_serialized_object_max_bytes_mutation(self) -> None:
def mutate(bundle: Path) -> None:
set_cmake(bundle, "SERIALIZED_OBJECT_MAX_BYTES", "1048577")
self.assert_generator_red(mutate, "serialized_object_max_bytes")
def test_serialized_object_max_fields_mutation(self) -> None:
def mutate(bundle: Path) -> None:
set_cmake(bundle, "SERIALIZED_OBJECT_MAX_FIELDS", "32769")
self.assert_generator_red(mutate, "serialized_object_max_fields")
def test_serialized_object_max_scopes_mutation(self) -> None:
def mutate(bundle: Path) -> None:
set_cmake(bundle, "SERIALIZED_OBJECT_MAX_SCOPES", "32770")
self.assert_generator_red(mutate, "serialized_object_max_scopes")
def test_serialized_object_max_depth_mutation(self) -> None:
def mutate(bundle: Path) -> None:
set_cmake(bundle, "SERIALIZED_OBJECT_MAX_DEPTH", "11")
self.assert_generator_red(mutate, "serialized_object_max_depth")
def _coordinated_limit(self, json_key: str, cmake_key: str, value: int) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["source"]["limits"][json_key] = value
write_json(bundle, data)
rehash_manifest(bundle)
set_cmake(bundle, cmake_key, str(value))
self.assert_generator_red(mutate, "sealed F0 table")
def test_coordinated_serialized_object_max_bytes_mutation(self) -> None:
self._coordinated_limit(
"serialized_object_max_bytes", "SERIALIZED_OBJECT_MAX_BYTES", 1048578
)
def test_coordinated_serialized_object_max_fields_mutation(self) -> None:
self._coordinated_limit(
"serialized_object_max_fields", "SERIALIZED_OBJECT_MAX_FIELDS", 1
)
def test_coordinated_serialized_object_max_scopes_mutation(self) -> None:
self._coordinated_limit(
"serialized_object_max_scopes", "SERIALIZED_OBJECT_MAX_SCOPES", 1
)
def test_coordinated_serialized_object_max_depth_mutation(self) -> None:
self._coordinated_limit(
"serialized_object_max_depth", "SERIALIZED_OBJECT_MAX_DEPTH", 1
)
def test_coordinated_heap_limit_mutation(self) -> None:
self._coordinated_limit("quickjs_heap_bytes", "HEAP_BYTES", 16777215)
def test_coordinated_stack_limit_mutation(self) -> None:
self._coordinated_limit("quickjs_stack_bytes", "STACK_BYTES", 65535)
def test_coordinated_initialization_fuel_mutation(self) -> None:
self._coordinated_limit(
"wasmtime_fuel_per_initialization", "INITIALIZATION_FUEL", 4999999
)
def test_coordinated_invocation_fuel_mutation(self) -> None:
self._coordinated_limit(
"wasmtime_fuel_per_invocation", "INVOCATION_FUEL", 49999999
)
def test_coordinated_host_work_budget_mutation(self) -> None:
self._coordinated_limit("host_work_budget", "HOST_WORK_BUDGET", 999999)
def test_coordinated_host_work_base_mutation(self) -> None:
self._coordinated_limit(
"host_work_base_per_call", "HOST_WORK_BASE_PER_CALL", 2
)
def test_coordinated_host_work_per_byte_mutation(self) -> None:
self._coordinated_limit(
"host_work_per_addressed_byte", "HOST_WORK_PER_ADDRESSED_BYTE", 2
)
def test_coordinated_host_work_meter_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["source"]["limits"]["host_work_meter"] = "other-meter"
write_json(bundle, data)
rehash_manifest(bundle)
set_cmake(bundle, "HOST_WORK_METER", "other-meter")
self.assert_generator_red(mutate, "host_work_meter")
def test_host_work_address_mapping_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["source"]["limits"]["host_work_addressed_length_indices"][
"accept"
] = [0]
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "host_work_addressed_length_indices")
def test_coordinated_host_adapter_policy_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["source"]["execution"]["host_adapter_policy"] = "other-policy"
write_json(bundle, data)
rehash_manifest(bundle)
set_cmake(bundle, "HOST_ADAPTER_POLICY", "other-policy")
self.assert_generator_red(mutate, "host_adapter_policy")
def test_coordinated_hook_api_version_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["source"]["artifact"]["hook_api_version"] = 2
write_json(bundle, data)
rehash_manifest(bundle)
set_cmake(bundle, "HOOK_API_VERSION", "2")
self.assert_generator_red(mutate, "hook_api_version")
def test_wasmtime_engine_configuration_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["source"]["engine"]["configuration"]["wasi"] = True
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "Wasmtime engine configuration")
def test_coordinated_wasmtime_version_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["source"]["engine"]["version"] = "48.0.0"
write_json(bundle, data)
rehash_manifest(bundle)
set_cmake(bundle, "WASMTIME_VERSION", "48.0.0")
self.assert_generator_red(
mutate, "Wasmtime version disagrees with the sealed F0", "48.0.0"
)
def test_provider_memory_max_bytes_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["provider"]["build"]["wasm_memory_max_bytes"] = 33554431
data["source"]["provider"]["build"][
"wasm_memory_max_bytes"
] = 33554431
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "wasm_memory_max_bytes")
def test_wasm_stack_bytes_mutation(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["provider"]["build"]["wasm_stack_bytes"] = 65536
data["source"]["provider"]["build"]["wasm_stack_bytes"] = 65536
write_json(bundle, data)
rehash_manifest(bundle)
self.assert_generator_red(mutate, "wasm_stack_bytes")
def test_stale_receipt_b_lock_control(self) -> None:
def mutate(bundle: Path) -> None:
data = load_json(bundle)
data["provider"]["sha256"] = RECEIPT_B["provider_sha256"]
data["provider"]["size"] = int(RECEIPT_B["provider_size"])
data["runtime_profile_id"] = RECEIPT_B["runtime_profile_id"]
data["javascript_surface"]["declaration_sha256"] = RECEIPT_B[
"declaration_sha256"
]
data["javascript_surface"]["sha256"] = RECEIPT_B["surface_sha256"]
for collection in (
data["provider"]["exports"],
data["source"]["provider"]["allowed_exports"],
):
for item in collection:
if item["kind"] == "memory":
item["minimum_pages"] = 6
write_json(bundle, data)
rehash_manifest(bundle)
set_cmake(bundle, "PROVIDER_SHA256", RECEIPT_B["provider_sha256"])
set_cmake(bundle, "PROVIDER_SIZE", RECEIPT_B["provider_size"])
set_cmake(
bundle, "RUNTIME_PROFILE_ID", RECEIPT_B["runtime_profile_id"]
)
self.assert_generator_red(
mutate, "provider SHA-256 disagrees with the sealed F0"
)
if __name__ == "__main__":
unittest.main()

View File

@@ -2,162 +2,157 @@ from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
import re
class Xrpl(ConanFile):
name = "xrpl"
name = 'xrpl'
license = "ISC"
author = "John Freeman <jfreeman@ripple.com>"
url = "https://github.com/xrplf/rippled"
description = "The XRP Ledger"
settings = "os", "compiler", "build_type", "arch"
license = 'ISC'
author = 'John Freeman <jfreeman@ripple.com>'
url = 'https://github.com/xrplf/rippled'
description = 'The XRP Ledger'
settings = 'os', 'compiler', 'build_type', 'arch'
options = {
"assertions": [True, False],
"coverage": [True, False],
"fPIC": [True, False],
"jemalloc": [True, False],
"rocksdb": [True, False],
"shared": [True, False],
"static": [True, False],
"tests": [True, False],
"unity": [True, False],
"xrpld": [True, False],
"with_wasmedge": [True, False],
"tool_requires_b2": [True, False],
'assertions': [True, False],
'coverage': [True, False],
'fPIC': [True, False],
'jemalloc': [True, False],
'rocksdb': [True, False],
'shared': [True, False],
'static': [True, False],
'tests': [True, False],
'unity': [True, False],
'xrpld': [True, False],
'with_wasmedge': [True, False],
'tool_requires_b2': [True, False],
}
requires = [
"date/3.0.3",
"grpc/1.50.1",
"libarchive/3.7.6",
"magic_enum/0.9.5",
"nudb/2.0.8",
"openssl/3.6.0",
"soci/4.0.3@xahaud/stable",
"xxhash/0.8.2",
"zlib/1.3.1",
'date/3.0.3',
'grpc/1.50.1',
'libarchive/3.7.6',
'nudb/2.0.8',
'openssl/3.6.0',
'soci/4.0.3@xahaud/stable',
'xxhash/0.8.2',
'zlib/1.3.1',
]
tool_requires = [
"protobuf/3.21.12",
'protobuf/3.21.12',
]
default_options = {
"assertions": False,
"coverage": False,
"fPIC": True,
"jemalloc": False,
"rocksdb": True,
"shared": False,
"static": True,
"tests": False,
"unity": False,
"xrpld": False,
"with_wasmedge": True,
"tool_requires_b2": False,
"date/*:header_only": False,
"grpc/*:shared": False,
"grpc/*:secure": True,
"libarchive/*:shared": False,
"libarchive/*:with_acl": False,
"libarchive/*:with_bzip2": False,
"libarchive/*:with_cng": False,
"libarchive/*:with_expat": False,
"libarchive/*:with_iconv": False,
"libarchive/*:with_libxml2": False,
"libarchive/*:with_lz4": True,
"libarchive/*:with_lzma": False,
"libarchive/*:with_lzo": False,
"libarchive/*:with_nettle": False,
"libarchive/*:with_openssl": False,
"libarchive/*:with_pcreposix": False,
"libarchive/*:with_xattr": False,
"libarchive/*:with_zlib": False,
"lz4/*:shared": False,
"openssl/*:shared": False,
"protobuf/*:shared": False,
"protobuf/*:with_zlib": True,
"rocksdb/*:enable_sse": False,
"rocksdb/*:lite": False,
"rocksdb/*:shared": False,
"rocksdb/*:use_rtti": True,
"rocksdb/*:with_jemalloc": False,
"rocksdb/*:with_lz4": True,
"rocksdb/*:with_snappy": True,
"snappy/*:shared": False,
"soci/*:shared": False,
"soci/*:with_sqlite3": True,
"soci/*:with_boost": True,
"wasmtime/*:shared": False,
"xxhash/*:shared": False,
'assertions': False,
'coverage': False,
'fPIC': True,
'jemalloc': False,
'rocksdb': True,
'shared': False,
'static': True,
'tests': False,
'unity': False,
'with_wasmedge': True,
'tool_requires_b2': False,
'xrpld': False,
'date/*:header_only': False,
'grpc/*:shared': False,
'grpc/*:secure': True,
'libarchive/*:shared': False,
'libarchive/*:with_acl': False,
'libarchive/*:with_bzip2': False,
'libarchive/*:with_cng': False,
'libarchive/*:with_expat': False,
'libarchive/*:with_iconv': False,
'libarchive/*:with_libxml2': False,
'libarchive/*:with_lz4': True,
'libarchive/*:with_lzma': False,
'libarchive/*:with_lzo': False,
'libarchive/*:with_nettle': False,
'libarchive/*:with_openssl': False,
'libarchive/*:with_pcreposix': False,
'libarchive/*:with_xattr': False,
'libarchive/*:with_zlib': False,
'lz4/*:shared': False,
'openssl/*:shared': False,
'protobuf/*:shared': False,
'protobuf/*:with_zlib': True,
'rocksdb/*:enable_sse': False,
'rocksdb/*:lite': False,
'rocksdb/*:shared': False,
'rocksdb/*:use_rtti': True,
'rocksdb/*:with_jemalloc': False,
'rocksdb/*:with_lz4': True,
'rocksdb/*:with_snappy': True,
'snappy/*:shared': False,
'soci/*:shared': False,
'soci/*:with_sqlite3': True,
'soci/*:with_boost': True,
'xxhash/*:shared': False,
}
def set_version(self):
path = f"{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp"
regex = r"versionString\s?=\s?\"(.*)\""
with open(path, "r") as file:
path = f'{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp'
regex = r'versionString\s?=\s?\"(.*)\"'
with open(path, 'r') as file:
matches = (re.search(regex, line) for line in file)
match = next(m for m in matches if m)
self.version = match.group(1)
def build_requirements(self):
# These provide build tools (protoc, grpc plugins) that run during build
self.tool_requires("grpc/1.50.1")
self.tool_requires('grpc/1.50.1')
# Explicitly require b2 (e.g. for building from source for glibc compatibility)
if self.options.tool_requires_b2:
self.tool_requires("b2/5.3.2")
self.tool_requires('b2/5.3.2')
def configure(self):
if self.settings.compiler == "apple-clang":
self.options["boost/*"].visibility = "global"
if self.settings.compiler == 'apple-clang':
self.options['boost/*'].visibility = 'global'
def requirements(self):
# Force sqlite3 version to avoid conflicts with soci
self.requires("sqlite3/3.47.0", override=True)
# Force our custom snappy build for all dependencies
self.requires("snappy/1.1.10@xahaud/stable", override=True)
# Force boost version for all dependencies to avoid conflicts
self.requires("boost/1.86.0", override=True)
self.requires("lz4/1.10.0", force=True)
self.requires('boost/1.86.0', override=True)
self.requires('lz4/1.10.0', force=True)
self.requires('protobuf/3.21.9', force=True)
# Force sqlite3 version to avoid conflicts with soci
self.requires('sqlite3/3.47.0', override=True)
# Force our custom snappy build for all dependencies
self.requires('snappy/1.1.10@xahaud/stable', override=True)
if self.options.with_wasmedge:
self.requires("wasmedge/0.11.2@xahaud/stable")
if self.options.xrpld:
self.requires("wasmtime/47.0.3@xahaud/stable")
self.requires('wasmedge/0.11.2@xahaud/stable')
if self.options.jemalloc:
self.requires("jemalloc/5.3.0")
self.requires('jemalloc/5.3.0')
if self.options.rocksdb:
self.requires("rocksdb/6.29.5")
self.requires('rocksdb/6.29.5')
exports_sources = (
"CMakeLists.txt",
"bin/getRippledInfo",
"cfg/*",
"cmake/*",
"external/*",
"include/*",
"src/*",
'CMakeLists.txt',
'bin/getRippledInfo',
'cfg/*',
'cmake/*',
'external/*',
'include/*',
'src/*',
)
def layout(self):
cmake_layout(self)
# Fix this setting to follow the default introduced in Conan 1.48
# to align with our build instructions.
self.folders.generators = "build/generators"
generators = "CMakeDeps"
self.folders.generators = 'build/generators'
generators = 'CMakeDeps'
def generate(self):
tc = CMakeToolchain(self)
tc.variables["tests"] = self.options.tests
tc.variables["assert"] = self.options.assertions
tc.variables["coverage"] = self.options.coverage
tc.variables["jemalloc"] = self.options.jemalloc
tc.variables["rocksdb"] = self.options.rocksdb
tc.variables["BUILD_SHARED_LIBS"] = self.options.shared
tc.variables["static"] = self.options.static
tc.variables["unity"] = self.options.unity
tc.variables["xrpld"] = self.options.xrpld
tc.variables['tests'] = self.options.tests
tc.variables['assert'] = self.options.assertions
tc.variables['coverage'] = self.options.coverage
tc.variables['jemalloc'] = self.options.jemalloc
tc.variables['rocksdb'] = self.options.rocksdb
tc.variables['BUILD_SHARED_LIBS'] = self.options.shared
tc.variables['static'] = self.options.static
tc.variables['unity'] = self.options.unity
tc.variables['xrpld'] = self.options.xrpld
tc.generate()
def build(self):
@@ -172,29 +167,29 @@ class Xrpl(ConanFile):
cmake.install()
def package_info(self):
libxrpl = self.cpp_info.components["libxrpl"]
libxrpl = self.cpp_info.components['libxrpl']
libxrpl.libs = [
"xrpl",
"xrpl.libpb",
"ed25519",
"secp256k1",
'xrpl',
'xrpl.libpb',
'ed25519',
'secp256k1',
]
# TODO: Fix the protobufs to include each other relative to
# `include/`, not `include/ripple/proto/`.
libxrpl.includedirs = ["include", "include/ripple/proto"]
libxrpl.includedirs = ['include', 'include/ripple/proto']
libxrpl.requires = [
"boost::boost",
"date::date",
"grpc::grpc++",
"libarchive::libarchive",
"lz4::lz4",
"nudb::nudb",
"openssl::crypto",
"protobuf::libprotobuf",
"soci::soci",
"sqlite3::sqlite",
"xxhash::xxhash",
"zlib::zlib",
'boost::boost',
'date::date',
'grpc::grpc++',
'libarchive::libarchive',
'lz4::lz4',
'nudb::nudb',
'openssl::crypto',
'protobuf::libprotobuf',
'soci::soci',
'sqlite3::sqlite',
'xxhash::xxhash',
'zlib::zlib',
]
if self.options.rocksdb:
libxrpl.requires.append("rocksdb::librocksdb")
libxrpl.requires.append('rocksdb::librocksdb')

View File

@@ -11,11 +11,11 @@ platforms: Linux, macOS, or Windows.
Package ecosystems vary across Linux distributions,
so there is no one set of instructions that will work for every Linux user.
These instructions are written for Ubuntu 22.04.
They are largely copied from the [script][1] used to configure a Docker
They are largely copied from the [script][1] used to configure our Docker
container for continuous integration.
That script handles many more responsibilities.
These instructions are just the bare minimum to build one configuration of
xahaud.
rippled.
You can check that codebase for other Linux distributions and versions.
If you cannot find yours there,
then we hope that these instructions can at least guide you in the right

177
docs/build/install.md vendored
View File

@@ -1,30 +1,159 @@
Comprehensive instructions for installing and running xahaud are available on the [https://Xahau.Network](https://xahau.network/docs/infrastructure/installing-xahaud) documentation website.
This document contains instructions for installing rippled.
The APT package manager is common on Debian-based Linux distributions like
Ubuntu,
while the YUM package manager is common on Red Hat-based Linux distributions
like CentOS.
Installing from source is an option for all platforms,
and the only supported option for installing custom builds.
## Create the Runtime Environment
xahaud can be [built from source](../../BUILD.md) or installed using the binary files available from [https://build.xahau.tech](https://build.xahau.tech/). After obtaining a working xahaud binary, users will need to provide a suitable runtime environment. The following setup can be used for Linux or Docker environments.
1. Create or download two configuration files: the main xahaud.cfg configuration file and a second validators-xahau.txt file defining which validators or UNL list publishers are trusted. The default location for these files in this xahaud repository is `cfg/`.
2. Provide a directory structure that is congruent with the contents of xahaud.cfg. This will include a location for logfiles, such as `/var/log/xahaud/`, as well as database files, `/opt/xahaud/db/`. Configuration files are, by default, sourced from `/etc/xahaud/`. It is possible to provide a symbolic link, if users wish to store configuration files elsewhere.
3. If desired, created a xahaud user and group, and change ownership of the binary and directories. Servers used for validating nodes should use the most restrictive permissions possible for `xahaud.cfg`, as the validation token is stored therein.
4. If desired, create a systemd service file: `/etc/systemd/system/xahaud.service`, enabling xahaud to run as a daemon. Alternately, run: `/path/to/binary/xahaud --conf=/path/to/xahaud.cfg`.
## From source
From a source build, you can install rippled and libxrpl using CMake's
`--install` mode:
## Example systemd Service File
```
[Unit]
Description=Xahaud Daemon
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/path/to/xahaud --silent --conf /path/to/xahaud.cfg
Restart=on-failure
User=xahaud
Group=xahaud
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
cmake --install . --prefix /opt/local
```
After the systemd service file is installed, it must be loaded with: `systemctl daemon-reload`. xahaud can then be enabled: `systemctl enable --now xahaud`.
The default [prefix][1] is typically `/usr/local` on Linux and macOS and
`C:/Program Files/rippled` on Windows.
[1]: https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html
## With the APT package manager
1. Update repositories:
sudo apt update -y
2. Install utilities:
sudo apt install -y apt-transport-https ca-certificates wget gnupg
3. Add Ripple's package-signing GPG key to your list of trusted keys:
sudo mkdir /usr/local/share/keyrings/
wget -q -O - "https://repos.ripple.com/repos/api/gpg/key/public" | gpg --dearmor > ripple-key.gpg
sudo mv ripple-key.gpg /usr/local/share/keyrings
4. Check the fingerprint of the newly-added key:
gpg /usr/local/share/keyrings/ripple-key.gpg
The output should include an entry for Ripple such as the following:
gpg: WARNING: no command supplied. Trying to guess what you mean ...
pub rsa3072 2019-02-14 [SC] [expires: 2026-02-17]
C0010EC205B35A3310DC90DE395F97FFCCAFD9A2
uid TechOps Team at Ripple <techops+rippled@ripple.com>
sub rsa3072 2019-02-14 [E] [expires: 2026-02-17]
In particular, make sure that the fingerprint matches. (In the above example, the fingerprint is on the third line, starting with `C001`.)
4. Add the appropriate Ripple repository for your operating system version:
echo "deb [signed-by=/usr/local/share/keyrings/ripple-key.gpg] https://repos.ripple.com/repos/rippled-deb focal stable" | \
sudo tee -a /etc/apt/sources.list.d/ripple.list
The above example is appropriate for **Ubuntu 20.04 Focal Fossa**. For other operating systems, replace the word `focal` with one of the following:
- `jammy` for **Ubuntu 22.04 Jammy Jellyfish**
- `bionic` for **Ubuntu 18.04 Bionic Beaver**
- `bullseye` for **Debian 11 Bullseye**
- `buster` for **Debian 10 Buster**
If you want access to development or pre-release versions of `rippled`, use one of the following instead of `stable`:
- `unstable` - Pre-release builds ([`release` branch](https://github.com/ripple/rippled/tree/release))
- `nightly` - Experimental/development builds ([`develop` branch](https://github.com/ripple/rippled/tree/develop))
**Warning:** Unstable and nightly builds may be broken at any time. Do not use these builds for production servers.
5. Fetch the Ripple repository.
sudo apt -y update
6. Install the `rippled` software package:
sudo apt -y install rippled
7. Check the status of the `rippled` service:
systemctl status rippled.service
The `rippled` service should start automatically. If not, you can start it manually:
sudo systemctl start rippled.service
8. Optional: allow `rippled` to bind to privileged ports.
This allows you to serve incoming API requests on port 80 or 443. (If you want to do so, you must also update the config file's port settings.)
sudo setcap 'cap_net_bind_service=+ep' /opt/ripple/bin/rippled
## With the YUM package manager
1. Install the Ripple RPM repository:
Choose the appropriate RPM repository for the stability of releases you want:
- `stable` for the latest production release (`master` branch)
- `unstable` for pre-release builds (`release` branch)
- `nightly` for experimental/development builds (`develop` branch)
*Stable*
cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo
[ripple-stable]
name=XRP Ledger Packages
enabled=1
gpgcheck=0
repo_gpgcheck=1
baseurl=https://repos.ripple.com/repos/rippled-rpm/stable/
gpgkey=https://repos.ripple.com/repos/rippled-rpm/stable/repodata/repomd.xml.key
REPOFILE
*Unstable*
cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo
[ripple-unstable]
name=XRP Ledger Packages
enabled=1
gpgcheck=0
repo_gpgcheck=1
baseurl=https://repos.ripple.com/repos/rippled-rpm/unstable/
gpgkey=https://repos.ripple.com/repos/rippled-rpm/unstable/repodata/repomd.xml.key
REPOFILE
*Nightly*
cat << REPOFILE | sudo tee /etc/yum.repos.d/ripple.repo
[ripple-nightly]
name=XRP Ledger Packages
enabled=1
gpgcheck=0
repo_gpgcheck=1
baseurl=https://repos.ripple.com/repos/rippled-rpm/nightly/
gpgkey=https://repos.ripple.com/repos/rippled-rpm/nightly/repodata/repomd.xml.key
REPOFILE
2. Fetch the latest repo updates:
sudo yum -y update
3. Install the new `rippled` package:
sudo yum install -y rippled
4. Configure the `rippled` service to start on boot:
sudo systemctl enable rippled.service
5. Start the `rippled` service:
sudo systemctl start rippled.service

View File

@@ -1,48 +0,0 @@
# QuickJS provider manifest
These files are generated or sealed together by a jshookz source checkout:
```sh
# Current layout (cpp/provider, python/jshookz). Older checkouts used
# packages/jshookz; bin/update-jshookz-snapshot accepts either CLI path.
uv sync --project python/jshookz --locked --group dev
python/jshookz/.venv/bin/jshookz build provider
```
Update this Xahau branch from a clean, committed jshookz checkout with one
command:
```sh
bin/update-jshookz-snapshot /path/to/jshookz
```
That builds and imports the sealed lock files plus the broad/exact-v1
declarations, selected-surface manifest, and API-artifact manifest. CI checks out jshookz
`main` and fails if `build provider` does not reproduce that lock. The
importer then prints a self-contained `x-run-tests` command that
regenerates the embedded Hook fixtures and verifies the cut.
`jshookz_provider.manifest.json` is the verified runtime-profile lock.
`jshookz_provider.manifest.cmake` is its minimal CMake projection. Xahau checks
the JSON hash before generating the C++ profile constants, and the runtime
checks any supplied provider WASM against the projected size and SHA-256.
`api-artifacts.json` closes the three tracked API artifacts; Xahau verifies its
own digest and every named artifact before projecting their identities. These
files add no parallel CMake lock-value fields.
The provider binary is not vendored in this integration slice. Tests inject
the exact built artifact. Configure needs python3 to project these lock files.
A daemon whose embed is empty will not start.
For a local producer-to-consumer build, point Xahau straight at the emitted
bundle instead of copying it:
```sh
cmake -S . -B build \
-DXAHAU_QUICKJS_PROVIDER_BUNDLE_DIR=/path/to/jshookz/build/xahau-provider
```
A build-time generator writes `QuickJSProviderValues.cpp` from those
locks and, if present, the gitignored wasm. Configure only checks that
the three lock files exist. Changing the bundle rebuilds that one
translation unit; hash, Wasmtime, and optional-wasm checks run then.

View File

@@ -1,8 +0,0 @@
{
"artifacts": {
"python/jshookz/src/jshookz/types/hooks-api.d.ts": "649079b831bc68eff0f440644649a505addafb08a3f5174e4031c8de6aedffa0",
"python/jshookz/src/jshookz/types/xahau-quickjs-v1.d.ts": "20881232f0602e35de0fcbb8b5a3c1511606392749a0f79daebb386204f4f4da",
"python/jshookz/src/jshookz/types/xahau-quickjs-v1.surface.json": "96a9218bf38abbf1bc9f2839408700d03572e0b065d625263f70477bc32597ac"
},
"schema": "jshookz.api-artifacts.v1"
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +0,0 @@
# Generated by jshookz build provider; do not edit.
set(XAHAU_QUICKJS_MANIFEST_SCHEMA "xahau.quickjs.runtime-profile-lock.v1")
set(XAHAU_QUICKJS_MANIFEST_SHA256 "1673b27d21063957cece9095cceb7e2dbfa53b6f49a5b7f824a486d7d90b2391")
set(XAHAU_QUICKJS_PROVIDER_FILE "jshookz_provider.wasm")
set(XAHAU_QUICKJS_PROVIDER_SHA256 "f60ab333acb547e50d7d087960839bd11833cb133d496af98e0b72a1bb3b84df")
set(XAHAU_QUICKJS_PROVIDER_SIZE "1116638")
set(XAHAU_QUICKJS_PROVIDER_IMPORT_COUNT "13")
set(XAHAU_QUICKJS_PROVIDER_EXPORT_COUNT "22")
set(XAHAU_QUICKJS_NATIVE_ABI_FILE "jshookz_provider.native-abi.json")
set(XAHAU_QUICKJS_NATIVE_ABI_SHA256 "328ec938dcad875f3bdf25b8d779dd77f3571589818ca9271cb98c64c7018f99")
set(XAHAU_QUICKJS_BYTECODE_ABI_ID "75ea54f357d397c4b33899e495bb385dad975a43b1c4a7a2cead30474327d33e")
set(XAHAU_QUICKJS_RUNTIME_PROFILE_ID "29acf12e170436e5ccadfbc118d02a60909f86a88262106652b2f71994b0ea25")
set(XAHAU_QUICKJS_HOOK_API_VERSION "1")
set(XAHAU_QUICKJS_WASMTIME_VERSION "47.0.3")
set(XAHAU_QUICKJS_INITIALIZATION_FUEL "5000000")
set(XAHAU_QUICKJS_INVOCATION_FUEL "50000000")
set(XAHAU_QUICKJS_HOST_WORK_METER "base-plus-addressed-byte-v1")
set(XAHAU_QUICKJS_HOST_WORK_BUDGET "1000000")
set(XAHAU_QUICKJS_HOST_WORK_BASE_PER_CALL "1")
set(XAHAU_QUICKJS_HOST_WORK_PER_ADDRESSED_BYTE "1")
set(XAHAU_QUICKJS_HOST_ADAPTER_POLICY "xahau-raw-hook-host-v1")
set(XAHAU_QUICKJS_HEAP_BYTES "16777216")
set(XAHAU_QUICKJS_STACK_BYTES "65536")
set(XAHAU_QUICKJS_SERIALIZED_OBJECT_MAX_BYTES "1048576")
set(XAHAU_QUICKJS_SERIALIZED_OBJECT_MAX_FIELDS "32768")
set(XAHAU_QUICKJS_SERIALIZED_OBJECT_MAX_SCOPES "32769")
set(XAHAU_QUICKJS_SERIALIZED_OBJECT_MAX_DEPTH "10")

View File

@@ -1,854 +0,0 @@
{
"bytecode_abi_id": "75ea54f357d397c4b33899e495bb385dad975a43b1c4a7a2cead30474327d33e",
"javascript_surface": {
"declaration": "python/jshookz/src/jshookz/types/xahau-quickjs-v1.d.ts",
"declaration_sha256": "20881232f0602e35de0fcbb8b5a3c1511606392749a0f79daebb386204f4f4da",
"manifest": "python/jshookz/src/jshookz/types/xahau-quickjs-v1.surface.json",
"schema": "jshookz.javascript-surface.v1",
"sha256": "96a9218bf38abbf1bc9f2839408700d03572e0b065d625263f70477bc32597ac"
},
"provider": {
"build": {
"wasm_memory_max_bytes": 33554432,
"wasm_stack_bytes": 131072
},
"exports": [
{
"kind": "function",
"name": "_initialize",
"params": [],
"results": []
},
{
"kind": "function",
"name": "free",
"params": [
"i32"
],
"results": []
},
{
"kind": "function",
"name": "malloc",
"params": [
"i32"
],
"results": [
"i32"
]
},
{
"kind": "memory",
"maximum_pages": 512,
"memory64": false,
"minimum_pages": 7,
"name": "memory",
"shared": false
},
{
"kind": "function",
"name": "qjs_cbak",
"params": [
"i32",
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_compile",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_compile_module",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_destroy",
"params": [],
"results": []
},
{
"kind": "function",
"name": "qjs_enable_coverage",
"params": [
"i32"
],
"results": []
},
{
"kind": "function",
"name": "qjs_eval",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_eval_bytecode",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_eval_module",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_get_bytecode_len",
"params": [],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_get_bytecode_ptr",
"params": [],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_get_result_len",
"params": [],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_get_result_ptr",
"params": [],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_hook",
"params": [
"i32",
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_init",
"params": [],
"results": []
},
{
"kind": "function",
"name": "qjs_set_max_stack_size",
"params": [
"i32"
],
"results": []
},
{
"kind": "function",
"name": "qjs_set_memory_limit",
"params": [
"i32"
],
"results": []
},
{
"kind": "function",
"name": "qjs_set_seed",
"params": [
"i32"
],
"results": []
},
{
"kind": "function",
"name": "qjs_validate_hook_module",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
}
],
"imports": [
{
"module": "env",
"name": "accept",
"params": [
"i32",
"i32",
"i64"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "emit",
"params": [
"i32",
"i32",
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "etxn_reserve",
"params": [
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "hook_account",
"params": [
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "ledger_last_hash",
"params": [
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "ledger_last_time",
"params": [],
"results": [
"i64"
]
},
{
"module": "env",
"name": "ledger_seq",
"params": [],
"results": [
"i64"
]
},
{
"module": "env",
"name": "otxn_type",
"params": [],
"results": [
"i64"
]
},
{
"module": "env",
"name": "prepare",
"params": [
"i32",
"i32",
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "rollback",
"params": [
"i32",
"i32",
"i64"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "state",
"params": [
"i32",
"i32",
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "state_set",
"params": [
"i32",
"i32",
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "trace",
"params": [
"i32",
"i32",
"i32",
"i32",
"i32"
],
"results": [
"i64"
]
}
],
"sha256": "f60ab333acb547e50d7d087960839bd11833cb133d496af98e0b72a1bb3b84df",
"size": 1116638
},
"runtime_profile_id": "29acf12e170436e5ccadfbc118d02a60909f86a88262106652b2f71994b0ea25",
"schema": "xahau.quickjs.runtime-profile-lock.v1",
"source": {
"artifact": {
"envelope_version": 1,
"hook_api_version": 1,
"kind": "quickjs-bytecode"
},
"bytecode_abi": {
"entry_exports": {
"callback": "optional-callable",
"main": "required-callable"
},
"quickjs_bytecode_version": 5,
"quickjs_version": "2025-09-13",
"read_flags": [
"JS_READ_OBJ_BYTECODE"
],
"root": "es-module",
"write_flags": [
"JS_WRITE_OBJ_BYTECODE"
]
},
"engine": {
"configuration": {
"consume_fuel": true,
"cranelift_nan_canonicalization": true,
"wasi": false,
"wasm_memory64": false,
"wasm_multi_memory": false,
"wasm_relaxed_simd": false,
"wasm_tail_call": false,
"wasm_threads": false
},
"implementation": "wasmtime-native-c-api",
"module_lifecycle": "compile-once-fresh-store-and-instance-per-invocation",
"version": "47.0.3"
},
"execution": {
"host_adapter_policy": "xahau-raw-hook-host-v1",
"host_work_exhaustion": "uncatchable-wasmtime-trap-to-wasm-error",
"initialization": "finite-cold-qjs-init-budget-before-invocation-fuel-reset",
"ordinary_host_status": "returned-as-i64-never-trapped",
"pending_jobs_after_entry": "not-drained",
"result_failure_policy": "rollback.onFail-preserves-coded-failure;rollback.requirePresent-requires-success-and-non-nullish-value;rollback.requireTruthy-requires-success-and-truthy-value;accept.unlessPresent-accepts-on-failure-or-nullish-value;accept.unlessTruthy-accepts-on-failure-or-falsy-value;guards-use-explicit-message-and-optional-code-default-zero",
"sfHookInstructionCount": "initial-wasmtime-invocation-fuel-minus-remaining-fuel",
"terminals": "record-hook-result-and-uncatchable-wasmtime-trap"
},
"javascript_surface": {
"declaration": "python/jshookz/src/jshookz/types/xahau-quickjs-v1.d.ts",
"manifest": "python/jshookz/src/jshookz/types/xahau-quickjs-v1.surface.json",
"schema": "jshookz.javascript-surface.v1"
},
"limits": {
"host_work_addressed_length_indices": {
"accept": [
1
],
"emit": [
1,
3
],
"hook_account": [
1
],
"ledger_last_hash": [
1
],
"prepare": [
1,
3
],
"rollback": [
1
],
"state": [
1,
3
],
"state_set": [
1,
3
],
"trace": [
1,
3
]
},
"host_work_base_per_call": 1,
"host_work_budget": 1000000,
"host_work_meter": "base-plus-addressed-byte-v1",
"host_work_per_addressed_byte": 1,
"quickjs_heap_bytes": 16777216,
"quickjs_stack_bytes": 65536,
"serialized_object_max_bytes": 1048576,
"serialized_object_max_depth": 10,
"serialized_object_max_fields": 32768,
"serialized_object_max_scopes": 32769,
"wasmtime_fuel_per_initialization": 5000000,
"wasmtime_fuel_per_invocation": 50000000
},
"name": "xahau-quickjs-v1",
"provider": {
"allowed_exports": [
{
"kind": "function",
"name": "_initialize",
"params": [],
"results": []
},
{
"kind": "function",
"name": "free",
"params": [
"i32"
],
"results": []
},
{
"kind": "function",
"name": "malloc",
"params": [
"i32"
],
"results": [
"i32"
]
},
{
"kind": "memory",
"maximum_pages": 512,
"memory64": false,
"minimum_pages": 7,
"name": "memory",
"shared": false
},
{
"kind": "function",
"name": "qjs_cbak",
"params": [
"i32",
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_compile",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_compile_module",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_destroy",
"params": [],
"results": []
},
{
"kind": "function",
"name": "qjs_enable_coverage",
"params": [
"i32"
],
"results": []
},
{
"kind": "function",
"name": "qjs_eval",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_eval_bytecode",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_eval_module",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_get_bytecode_len",
"params": [],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_get_bytecode_ptr",
"params": [],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_get_result_len",
"params": [],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_get_result_ptr",
"params": [],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_hook",
"params": [
"i32",
"i32",
"i32"
],
"results": [
"i32"
]
},
{
"kind": "function",
"name": "qjs_init",
"params": [],
"results": []
},
{
"kind": "function",
"name": "qjs_set_max_stack_size",
"params": [
"i32"
],
"results": []
},
{
"kind": "function",
"name": "qjs_set_memory_limit",
"params": [
"i32"
],
"results": []
},
{
"kind": "function",
"name": "qjs_set_seed",
"params": [
"i32"
],
"results": []
},
{
"kind": "function",
"name": "qjs_validate_hook_module",
"params": [
"i32",
"i32"
],
"results": [
"i32"
]
}
],
"build": {
"c_flags": [
"-fwrapv",
"-funsigned-char",
"-mllvm",
"-wasm-enable-sjlj"
],
"cxx_flags": [
"-fno-exceptions",
"-fno-rtti",
"-mllvm",
"-wasm-enable-sjlj"
],
"optimization": "O2",
"target": "wasm32-wasi",
"wasi_sdk": "32",
"wasm_memory_max_bytes": 33554432,
"wasm_stack_bytes": 131072
},
"forbidden_import_modules": [
"wasi_snapshot_preview1"
],
"imports": [
{
"module": "env",
"name": "accept",
"params": [
"i32",
"i32",
"i64"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "emit",
"params": [
"i32",
"i32",
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "etxn_reserve",
"params": [
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "hook_account",
"params": [
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "ledger_last_hash",
"params": [
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "ledger_last_time",
"params": [],
"results": [
"i64"
]
},
{
"module": "env",
"name": "ledger_seq",
"params": [],
"results": [
"i64"
]
},
{
"module": "env",
"name": "otxn_type",
"params": [],
"results": [
"i64"
]
},
{
"module": "env",
"name": "prepare",
"params": [
"i32",
"i32",
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "rollback",
"params": [
"i32",
"i32",
"i64"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "state",
"params": [
"i32",
"i32",
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "state_set",
"params": [
"i32",
"i32",
"i32",
"i32"
],
"results": [
"i64"
]
},
{
"module": "env",
"name": "trace",
"params": [
"i32",
"i32",
"i32",
"i32",
"i32"
],
"results": [
"i64"
]
}
],
"javascript": {
"atomics": false,
"date_now": "previous-ledger-close-ripple-epoch-to-unix-milliseconds",
"dynamic_eval": "enabled-and-metered",
"finalization_registry": false,
"math_random": "absent-use-ledger-random-api",
"number": "enabled",
"promise": "required-for-module-evaluation-no-post-entry-job-drain",
"shared_array_buffer": false,
"timezone": "UTC",
"weak_ref": false
}
},
"schema": "xahau.quickjs.runtime-profile-source.v1"
}
}

View File

@@ -1 +0,0 @@
{"selected":[{"amendment":null,"name":"accept","param_types":["uint32_t","uint32_t","int64_t"],"return_type":"int64_t","wasm_signature":["0x7e","0x7f","0x7f","0x7e"]},{"amendment":null,"name":"rollback","param_types":["uint32_t","uint32_t","int64_t"],"return_type":"int64_t","wasm_signature":["0x7e","0x7f","0x7f","0x7e"]},{"amendment":null,"name":"ledger_seq","param_types":[],"return_type":"int64_t","wasm_signature":["0x7e"]},{"amendment":null,"name":"ledger_last_time","param_types":[],"return_type":"int64_t","wasm_signature":["0x7e"]},{"amendment":null,"name":"ledger_last_hash","param_types":["uint32_t","uint32_t"],"return_type":"int64_t","wasm_signature":["0x7e","0x7f","0x7f"]},{"amendment":null,"name":"otxn_type","param_types":[],"return_type":"int64_t","wasm_signature":["0x7e"]},{"amendment":null,"name":"hook_account","param_types":["uint32_t","uint32_t"],"return_type":"int64_t","wasm_signature":["0x7e","0x7f","0x7f"]},{"amendment":null,"name":"trace","param_types":["uint32_t","uint32_t","uint32_t","uint32_t","uint32_t"],"return_type":"int64_t","wasm_signature":["0x7e","0x7f","0x7f","0x7f","0x7f","0x7f"]},{"amendment":null,"name":"state","param_types":["uint32_t","uint32_t","uint32_t","uint32_t"],"return_type":"int64_t","wasm_signature":["0x7e","0x7f","0x7f","0x7f","0x7f"]},{"amendment":null,"name":"state_set","param_types":["uint32_t","uint32_t","uint32_t","uint32_t"],"return_type":"int64_t","wasm_signature":["0x7e","0x7f","0x7f","0x7f","0x7f"]},{"amendment":"featureHooksUpdate2","name":"prepare","param_types":["uint32_t","uint32_t","uint32_t","uint32_t"],"return_type":"int64_t","wasm_signature":["0x7e","0x7f","0x7f","0x7f","0x7f"]},{"amendment":null,"name":"etxn_reserve","param_types":["uint32_t"],"return_type":"int64_t","wasm_signature":["0x7e","0x7f"]},{"amendment":null,"name":"emit","param_types":["uint32_t","uint32_t","uint32_t","uint32_t"],"return_type":"int64_t","wasm_signature":["0x7e","0x7f","0x7f","0x7f","0x7f"]}],"source":{"commit":"bb244ef7729503a0317bcff0f8fdaa93ca5cb7d2","macro_function_count":75,"path":"include/xrpl/hook/hook_api.macro","repository":"https://github.com/Xahau/xahaud"}}

File diff suppressed because it is too large Load Diff

View File

@@ -1,581 +0,0 @@
{
"byte_policies": {
"AccountID.from": {
"0": "bytesLike"
},
"AccountID.fromHex": {
"0": "hexString"
},
"Hash256.from": {
"0": "bytesLike"
},
"Hash256.fromHex": {
"0": "hexString"
},
"STBlob.equals": {
"0": "bytesLikeOrSTBlob"
},
"STBlob.from": {
"0": "bytesLike"
},
"STBlob.fromHex": {
"0": "hexString"
},
"accept": {
"0": "lifecycleMessage"
},
"emit.prepare": {
"0": "bytesLikeOrSTBlob"
},
"emit.tx": {
"0": "bytesLikeOrSTBlob"
},
"rollback": {
"0": "lifecycleMessage"
},
"state.get": {
"0": "stateKeyLike"
},
"state.set": {
"0": "stateKeyLike",
"1": "stateValueLike"
}
},
"declaration": {
"path": "python/jshookz/src/jshookz/types/xahau-quickjs-v1.d.ts",
"sha256": "20881232f0602e35de0fcbb8b5a3c1511606392749a0f79daebb386204f4f4da"
},
"globals": {
"AccountID": "object",
"Amount": "object",
"Currency": "object",
"Field": "object",
"Hash": "object",
"Hash128": "object",
"Hash160": "object",
"Hash192": "object",
"Hash256": "object",
"IOUAmount": "object",
"Issue": "object",
"MPTAmount": "object",
"NativeAmount": "object",
"Path": "object",
"PathHop": "object",
"PathSet": "object",
"Result": "object",
"STArray": "object",
"STBlob": "object",
"STObject": "object",
"SerializedField": "object",
"UInt": "object",
"UInt16": "object",
"UInt32": "object",
"UInt64": "object",
"UInt8": "object",
"Vector256": "object",
"VoidResult": "object",
"XChainBridge": "object",
"XFLDecimal": "object",
"accept": "function",
"emit": "object",
"hook": "object",
"ledger": "object",
"otxn": "object",
"rollback": "function",
"state": "object",
"trace": "function",
"util": "object"
},
"namespaces": {
"accept": {
"unlessPresent": "function",
"unlessTruthy": "function",
"when": "function"
},
"emit": {
"prepare": "function",
"reserve": "function",
"tx": "function"
},
"hook": {
"account": "function"
},
"ledger": {
"lastHash": "value",
"lastTime": "value",
"sequence": "value"
},
"otxn": {
"type": "function"
},
"rollback": {
"onAllFail": "function",
"onAnyFail": "function",
"onFail": "function",
"requirePresent": "function",
"requireTruthy": "function",
"when": "function"
},
"state": {
"get": "function",
"set": "function"
},
"util": {
"decodeObject": "function",
"safeDecodeObject": "function",
"validateObject": "function"
}
},
"prototypes": {
"AccountID": {
"members": {
"equals": "function",
"isZero": "function",
"toBytes": "function",
"toHex": "function"
},
"own": [
"equals",
"isZero",
"toBytes",
"toHex"
],
"probe": "AccountID.from(new Uint8Array(20))"
},
"Amount": {
"members": {
"asIOU": "function",
"asMPT": "function",
"asNative": "function",
"byteLength": "value",
"compare": "function",
"currency": "value",
"drops": "value",
"equals": "function",
"isIOU": "function",
"isMPT": "function",
"isNative": "function",
"issue": "value",
"issuer": "value",
"kind": "value",
"mptIssuanceId": "value",
"toBytes": "function",
"toString": "function",
"toXFL": "function",
"value": "value"
},
"own": [
"asIOU",
"asMPT",
"asNative",
"byteLength",
"compare",
"currency",
"drops",
"equals",
"isIOU",
"isMPT",
"isNative",
"issue",
"issuer",
"kind",
"mptIssuanceId",
"toBytes",
"toString",
"toXFL",
"value"
],
"probe": "util.decodeObject(STBlob.fromHex('61D4838D7EA4C680000000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E8')).Amount"
},
"Currency": {
"members": {
"byteLength": "value",
"equals": "function",
"isNative": "value",
"toBytes": "function",
"toHex": "function",
"toString": "function"
},
"own": [
"byteLength",
"equals",
"isNative",
"toBytes",
"toHex",
"toString"
],
"probe": "util.decodeObject(new Uint8Array()).withField('BaseAsset', new Uint8Array(20)).BaseAsset"
},
"Hash128": {
"members": {
"byteLength": "value",
"compare": "function",
"equals": "function",
"isZero": "function",
"toBytes": "function",
"toHex": "function"
},
"own": [
"byteLength",
"compare",
"equals",
"isZero",
"toBytes",
"toHex"
],
"probe": "util.decodeObject(new Uint8Array()).withField('EmailHash', new Uint8Array(16)).EmailHash"
},
"Hash160": {
"members": {
"byteLength": "value",
"compare": "function",
"equals": "function",
"isZero": "function",
"toBytes": "function",
"toHex": "function"
},
"own": [
"byteLength",
"compare",
"equals",
"isZero",
"toBytes",
"toHex"
],
"probe": "util.decodeObject(new Uint8Array()).withField('TakerPaysCurrency', new Uint8Array(20)).TakerPaysCurrency"
},
"Hash192": {
"members": {
"byteLength": "value",
"compare": "function",
"equals": "function",
"isZero": "function",
"toBytes": "function",
"toHex": "function"
},
"own": [
"byteLength",
"compare",
"equals",
"isZero",
"toBytes",
"toHex"
],
"probe": "util.decodeObject(new Uint8Array()).withField('MPTokenIssuanceID', new Uint8Array(24)).MPTokenIssuanceID"
},
"Hash256": {
"members": {
"byteLength": "value",
"compare": "function",
"equals": "function",
"isZero": "function",
"toBytes": "function",
"toHex": "function"
},
"own": [
"byteLength",
"compare",
"equals",
"isZero",
"toBytes",
"toHex"
],
"probe": "Hash256.from(new Uint8Array(32))"
},
"Issue": {
"members": {
"currency": "value",
"equals": "function",
"issuer": "value",
"kind": "value",
"mptIssuanceId": "value",
"toBytes": "function"
},
"own": [
"currency",
"equals",
"issuer",
"kind",
"mptIssuanceId",
"toBytes"
],
"probe": "util.decodeObject(new Uint8Array()).withField('LockingChainIssue', new Uint8Array(20)).LockingChainIssue"
},
"Path": {
"members": {
"[Symbol.iterator]": "function",
"at": "function",
"length": "value"
},
"own": [
"[Symbol.iterator]",
"at",
"length"
],
"probe": "util.decodeObject(STBlob.fromHex('011201B5F762798A53D543A014CAF8B297CFF8F2F937E800')).Paths.at(0)"
},
"PathHop": {
"members": {
"account": "value",
"currency": "value",
"issuer": "value"
},
"own": [
"account",
"currency",
"issuer"
],
"probe": "util.decodeObject(STBlob.fromHex('011201B5F762798A53D543A014CAF8B297CFF8F2F937E800')).Paths.at(0).at(0)"
},
"PathSet": {
"members": {
"[Symbol.iterator]": "function",
"at": "function",
"length": "value",
"toBytes": "function"
},
"own": [
"[Symbol.iterator]",
"at",
"length",
"toBytes"
],
"probe": "util.decodeObject(STBlob.fromHex('011201B5F762798A53D543A014CAF8B297CFF8F2F937E800')).Paths"
},
"Result": {
"frozen": true,
"members": {
"okMapOr": "function",
"okOr": "function",
"okOrHandle": "function"
},
"own": [
"okMapOr",
"okOr",
"okOrHandle"
],
"probe": "UInt64.from(0n)"
},
"STArray": {
"exotic": {
"array": false,
"enumerable": [
"0"
],
"extensible": false,
"own": [
"0",
"length"
]
},
"members": {
"[Symbol.iterator]": "function",
"at": "function",
"length": "value",
"toJSON": "function"
},
"own": [
"[Symbol.iterator]",
"at",
"toJSON"
],
"probe": "util.decodeObject(new Uint8Array([0xF9, 0xEA, 0x22, 0, 0, 0, 1, 0xE1, 0xF1])).Memos"
},
"STBlob": {
"members": {
"byteAt": "function",
"byteLength": "value",
"equals": "function",
"toBytes": "function",
"toHex": "function"
},
"own": [
"byteAt",
"byteLength",
"equals",
"toBytes",
"toHex"
],
"probe": "STBlob.from(new Uint8Array(0))"
},
"STObject": {
"exotic": {
"array": false,
"enumerable": [
"Flags"
],
"extensible": false,
"own": [
"Flags"
]
},
"members": {
"fieldBytes": "function",
"get": "function",
"has": "function",
"toBytes": "function",
"toJSON": "function",
"withField": "function",
"withoutField": "function"
},
"own": [
"fieldBytes",
"get",
"has",
"toBytes",
"toJSON",
"withField",
"withoutField"
],
"probe": "util.decodeObject(new Uint8Array([0x22, 0, 0, 0, 9]))"
},
"UInt": {
"members": {
"add": "function",
"bits": "value",
"byteLength": "value",
"compare": "function",
"equals": "function",
"isZero": "function",
"saturatingAdd": "function",
"saturatingSubtract": "function",
"subtract": "function",
"toBigInt": "function",
"toNumber": "function",
"toString": "function",
"wrappingAdd": "function",
"wrappingMultiply": "function",
"wrappingSubtract": "function"
},
"own": [
"add",
"bits",
"byteLength",
"compare",
"equals",
"isZero",
"saturatingAdd",
"saturatingSubtract",
"subtract",
"toBigInt",
"toNumber",
"toString",
"wrappingAdd",
"wrappingMultiply",
"wrappingSubtract"
],
"probe": "UInt8.zero"
},
"Vector256": {
"exotic": {
"array": false,
"enumerable": [
"0"
],
"extensible": false,
"own": [
"0",
"length"
]
},
"members": {
"[Symbol.iterator]": "function",
"at": "function",
"length": "value",
"toBytes": "function"
},
"own": [
"[Symbol.iterator]",
"at",
"toBytes"
],
"probe": "util.decodeObject(STBlob.fromHex('011320000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F')).Indexes"
},
"VoidResult": {
"frozen": true,
"members": {
"moot": "function",
"okMapOr": "function",
"okOr": "function",
"okOrHandle": "function"
},
"own": [
"moot"
],
"probe": "state.set('surface-probe', new Uint8Array(0))"
},
"XChainBridge": {
"members": {
"IssuingChainDoor": "value",
"IssuingChainIssue": "value",
"LockingChainDoor": "value",
"LockingChainIssue": "value",
"equals": "function",
"toBytes": "function"
},
"own": [
"IssuingChainDoor",
"IssuingChainIssue",
"LockingChainDoor",
"LockingChainIssue",
"equals",
"toBytes"
],
"probe": "util.decodeObject(STBlob.fromHex('011914B5F762798A53D543A014CAF8B297CFF8F2F937E8000000000000000000000000000000000000000014B5F762798A53D543A014CAF8B297CFF8F2F937E80000000000000000000000000000000000000000')).XChainBridge"
},
"XFLDecimal": {
"members": {
"isNegative": "function",
"isZero": "function"
},
"own": [
"isNegative",
"isZero"
],
"probe": "util.decodeObject(STBlob.fromHex('61D4838D7EA4C680000000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E8')).Amount.toXFL()"
}
},
"schema": "jshookz.javascript-surface.v1",
"statics": {
"AccountID": {
"from": "function",
"fromHex": "function",
"one": "value",
"zero": "value"
},
"Hash256": {
"from": "function",
"fromHex": "function",
"zero": "value"
},
"STBlob": {
"from": "function",
"fromHex": "function"
},
"UInt16": {
"from": "function",
"max": "value",
"mulDiv": "function",
"zero": "value"
},
"UInt32": {
"from": "function",
"max": "value",
"mulDiv": "function",
"zero": "value"
},
"UInt64": {
"from": "function",
"max": "value",
"mulDiv": "function",
"mulDivXfl": "function",
"zero": "value"
},
"UInt8": {
"from": "function",
"max": "value",
"mulDiv": "function",
"zero": "value"
}
}
}

View File

@@ -1,27 +0,0 @@
sources:
47.0.3:
Linux:
armv8:
sha256: c1ef99bb4ef0151282f339e22a67f8229d9ab336f9a17387e65f140b79c45be1
url: https://github.com/bytecodealliance/wasmtime/releases/download/v47.0.3/wasmtime-v47.0.3-aarch64-linux-c-api.tar.xz
x86_64:
sha256: aaa3621f2a3d8393696702897f8f78a1cc504437d500701496d560125aefd732
url: https://github.com/bytecodealliance/wasmtime/releases/download/v47.0.3/wasmtime-v47.0.3-x86_64-linux-c-api.tar.xz
Macos:
armv8:
sha256: 1854c8f03a764c89afe77fa88d9092ab89a368e527cd27a12959b1d91152324e
url: https://github.com/bytecodealliance/wasmtime/releases/download/v47.0.3/wasmtime-v47.0.3-aarch64-macos-c-api.tar.xz
x86_64:
sha256: 627622087b77b92c163e826ec6ebf834a70d78735828043edf7ace263f8a9e62
url: https://github.com/bytecodealliance/wasmtime/releases/download/v47.0.3/wasmtime-v47.0.3-x86_64-macos-c-api.tar.xz
MinGW:
x86_64:
sha256: 355a0c7b49b92bb011e74a4047cc1186271aeb8c8cfcc4360248caaf3c4d5f38
url: https://github.com/bytecodealliance/wasmtime/releases/download/v47.0.3/wasmtime-v47.0.3-x86_64-mingw-c-api.zip
Windows:
armv8:
sha256: 57107b14b28ac2152e903501fe1722007b90fc11ccd63ad6d62ed574c5dd90db
url: https://github.com/bytecodealliance/wasmtime/releases/download/v47.0.3/wasmtime-v47.0.3-aarch64-windows-c-api.zip
x86_64:
sha256: 952dfbc864295eccc89caa92bc303686017ca4ea205a1f21878809f374bb77c5
url: https://github.com/bytecodealliance/wasmtime/releases/download/v47.0.3/wasmtime-v47.0.3-x86_64-windows-c-api.zip

View File

@@ -1,162 +0,0 @@
import os
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.files import copy, get
from conan.tools.microsoft import is_msvc
required_conan_version = ">=2.0"
class WasmtimeConan(ConanFile):
name = "wasmtime"
description = "Standalone WebAssembly runtime using Cranelift"
license = "Apache-2.0 WITH LLVM-exception"
url = "https://github.com/Xahau/xahaud"
homepage = "https://github.com/bytecodealliance/wasmtime"
topics = ("webassembly", "wasm")
package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {"shared": [True, False]}
default_options = {"shared": False}
no_copy_source = True
@property
def _sources_os_key(self):
if is_msvc(self):
return "Windows"
if self.settings.os == "Windows" and self.settings.compiler == "gcc":
return "MinGW"
return str(self.settings.os)
def configure(self):
self.settings.rm_safe("compiler.libcxx")
self.settings.rm_safe("compiler.cppstd")
def package_id(self):
# Official release archives contain a prebuilt C ABI. Compiler patch
# versions do not change the packaged bytes.
if self.info.settings.compiler == "clang":
self.info.settings.compiler = "gcc"
del self.info.settings.compiler.version
def validate(self):
try:
self.conan_data["sources"][self.version][self._sources_os_key][
str(self.settings.arch)
]
except KeyError as error:
raise ConanInvalidConfiguration(
"No official Wasmtime C-API archive for "
f"{self.settings.os}/{self.settings.arch}"
) from error
def build(self):
get(
self,
**self.conan_data["sources"][self.version][self._sources_os_key][
str(self.settings.arch)
],
destination=self.build_folder,
strip_root=True,
)
def package(self):
copy(
self,
"*.h",
dst=os.path.join(self.package_folder, "include"),
src=os.path.join(self.build_folder, "include"),
)
copy(
self,
"*.hh",
dst=os.path.join(self.package_folder, "include"),
src=os.path.join(self.build_folder, "include"),
)
source_lib = os.path.join(self.build_folder, "lib")
package_lib = os.path.join(self.package_folder, "lib")
package_bin = os.path.join(self.package_folder, "bin")
if self.options.shared:
copy(
self,
"wasmtime.dll.lib",
dst=package_lib,
src=source_lib,
keep_path=False,
)
copy(
self,
"wasmtime.dll",
dst=package_bin,
src=source_lib,
keep_path=False,
)
copy(
self,
"libwasmtime.dll.a",
dst=package_lib,
src=source_lib,
keep_path=False,
)
copy(
self,
"libwasmtime.so*",
dst=package_lib,
src=source_lib,
keep_path=False,
)
copy(
self,
"libwasmtime.dylib",
dst=package_lib,
src=source_lib,
keep_path=False,
)
else:
copy(
self,
"wasmtime.lib",
dst=package_lib,
src=source_lib,
keep_path=False,
)
copy(
self,
"libwasmtime.a",
dst=package_lib,
src=source_lib,
keep_path=False,
)
copy(
self,
"LICENSE",
dst=os.path.join(self.package_folder, "licenses"),
src=self.build_folder,
)
def package_info(self):
if self.options.shared:
self.cpp_info.libs = [
"wasmtime.dll" if self.settings.os == "Windows" else "wasmtime"
]
else:
if self.settings.os == "Windows":
self.cpp_info.defines = ["WASM_API_EXTERN=", "WASI_API_EXTERN="]
self.cpp_info.libs = ["wasmtime"]
if self.settings.os == "Windows":
self.cpp_info.system_libs = [
"ws2_32",
"bcrypt",
"advapi32",
"userenv",
"ntdll",
"shell32",
"ole32",
]
elif self.settings.os in ("Linux", "FreeBSD"):
self.cpp_info.system_libs = ["pthread", "dl", "m", "rt"]

View File

@@ -2,9 +2,6 @@
// Generated using generate_extern.sh
#include <stdint.h>
#ifndef HOOK_EXTERN
#ifdef __cplusplus
extern "C" {
#endif
extern int32_t __attribute__((noduplicate))
_g(uint32_t guard_id, uint32_t maxiter);
@@ -332,15 +329,5 @@ meta_slot(uint32_t slot_no);
extern int64_t
xpop_slot(uint32_t slot_no_tx, uint32_t slot_no_meta);
extern int64_t
prepare(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len);
#ifdef __cplusplus
}
#endif
#define HOOK_EXTERN
#endif // HOOK_EXTERN

View File

@@ -9,7 +9,7 @@ ENUM_FILE="$SCRIPT_DIR/../include/xrpl/hook/Enum.h"
echo '// For documentation please see: https://xrpl-hooks.readme.io/reference/'
echo '// Generated using generate_error.sh'
echo '#ifndef HOOK_ERROR_CODES'
sed -n '/enum class hook_return_code/,/};/p' "$ENUM_FILE" |
sed -n '/enum hook_return_code/,/};/p' "$ENUM_FILE" |
awk '
function ltrim(s) { sub(/^[[:space:]]+/, "", s); return s }
function rtrim(s) { sub(/[[:space:]]+$/, "", s); return s }
@@ -31,7 +31,7 @@ sed -n '/enum class hook_return_code/,/};/p' "$ENUM_FILE" |
{
line = $0
if (line ~ /enum[[:space:]]+class[[:space:]]+hook_return_code/)
if (line ~ /enum[[:space:]]+hook_return_code/)
next
if (line ~ /^[[:space:]]*\{/)
next

View File

@@ -11,9 +11,6 @@ APPLY_HOOK="$SCRIPT_DIR/../include/xrpl/hook/hook_api.macro"
echo '// Generated using generate_extern.sh'
echo '#include <stdint.h>'
echo '#ifndef HOOK_EXTERN'
echo '#ifdef __cplusplus'
echo 'extern "C" {'
echo '#endif'
echo
awk '
function trim(s) {
@@ -49,9 +46,6 @@ APPLY_HOOK="$SCRIPT_DIR/../include/xrpl/hook/hook_api.macro"
}
' "$APPLY_HOOK"
echo '#ifdef __cplusplus'
echo '}'
echo '#endif'
echo '#define HOOK_EXTERN'
echo '#endif // HOOK_EXTERN'
} | (

View File

@@ -1,82 +0,0 @@
#!/bin/bash
set -eu
SCRIPT_DIR=$(dirname "$0")
SCRIPT_DIR=$(cd "$SCRIPT_DIR" && pwd)
RIPPLED_ROOT="$SCRIPT_DIR/../include/xrpl"
LEDGER_FORMATS="$RIPPLED_ROOT/protocol/LedgerFormats.h"
echo '// Generated using generate_lsflags.sh'
echo ''
echo '#ifndef HOOKLSFLAGS_INCLUDED'
echo '#define HOOKLSFLAGS_INCLUDED 1'
echo ''
awk '
function ltrim(s) { sub(/^[[:space:]]+/, "", s); return s }
function rtrim(s) { sub(/[[:space:]]+$/, "", s); return s }
function trim(s) { return rtrim(ltrim(s)) }
function flush_group() {
if (entry_count > 0 && group != "") {
printf "enum %s {\n", group
for (i = 1; i <= entry_count; i++) {
printf " %s,\n", entries[i]
}
printf "};\n"
}
delete entries
entry_count = 0
}
/enum LedgerSpecificFlags \{/ { inside = 1; next }
inside && /^\};/ { inside = 0; flush_group(); next }
!inside { next }
# Group header comments: // ltFOO or // remarks
/^[[:space:]]*\/\/[[:space:]]*(lt[A-Z_]+|remarks)[[:space:]]*$/ {
flush_group()
line = $0
sub(/.*\/\/[[:space:]]*/, "", line)
group = trim(line)
next
}
# Skip pure comment lines (not group headers)
/^[[:space:]]*\/\// { next }
# Skip blank lines
/^[[:space:]]*$/ { next }
# Accumulate flag lines (handle multi-line values)
{
line = $0
# Strip inline comments
sub(/\/\/.*/, "", line)
line = trim(line)
if (line == "") next
if (pending != "") {
pending = pending " " line
} else {
pending = line
}
# If line ends with comma, the entry is complete
if (pending ~ /,$/) {
# Remove trailing comma
sub(/,$/, "", pending)
entries[++entry_count] = pending
pending = ""
}
}
BEGIN {
inside = 0
group = ""
pending = ""
entry_count = 0
}
' "$LEDGER_FORMATS"
echo ''
echo '#endif // HOOKLSFLAGS_INCLUDED'

View File

@@ -1,25 +0,0 @@
#!/bin/bash
set -eu
SCRIPT_DIR=$(dirname "$0")
SCRIPT_DIR=$(cd "$SCRIPT_DIR" && pwd)
RIPPLED_ROOT="$SCRIPT_DIR/../include/xrpl"
TX_FLAGS="$RIPPLED_ROOT/protocol/TxFlags.h"
echo '// Generated using generate_txflags.sh'
echo '#include "ls_flags.h"'
echo '#include <stdint.h>'
echo ''
cat "$TX_FLAGS" |
awk '
/^[[:space:]]*enum / {
if (count > 0) print ""
inside = 1
count++
}
inside {
print
if (/};/) inside = 0
}
'

View File

@@ -1,203 +0,0 @@
#!/bin/bash
# build_xahau_h.sh
# Builds genesis hook WASMs and updates xahau.h with hex arrays
set -euo pipefail
# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Script directory and path constants
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
XAHAU_H="${SCRIPT_DIR}/../../include/xrpl/hook/xahau.h"
TEMP_DIR="${SCRIPT_DIR}/.temp"
# Hook file mappings (space-separated: name:file)
HOOK_FILES=(
"GovernanceHook:govern.wasm"
"RewardHook:reward.wasm"
# "MintHook:mint.wasm"
)
# Cleanup function
cleanup() {
local exit_code=$?
if [ ${exit_code} -eq 0 ] && [ -d "${TEMP_DIR}" ]; then
rm -rf "${TEMP_DIR}"
elif [ ${exit_code} -ne 0 ]; then
echo -e "${RED}Error: Script failed with exit code ${exit_code}${NC}" >&2
if [ -d "${TEMP_DIR}" ]; then
echo -e "${YELLOW}Temp files preserved at: ${TEMP_DIR}${NC}" >&2
fi
fi
exit ${exit_code}
}
trap cleanup EXIT INT TERM
# Tool verification
echo -e "${BLUE}==> Checking required tools...${NC}"
REQUIRED_TOOLS=("make" "xxd" "sed" "clang-format" "wasm-opt")
for tool in "${REQUIRED_TOOLS[@]}"; do
if ! command -v "${tool}" &> /dev/null; then
echo -e "${RED}Error: Required tool '${tool}' not found${NC}" >&2
exit 1
fi
echo -e "${GREEN}${tool}${NC}"
done
# Verify wasm-opt version is exactly 100
WASM_OPT_VERSION=$(wasm-opt --version | grep -oE '[0-9]+' | head -1)
if [ "${WASM_OPT_VERSION}" != "100" ]; then
echo -e "${RED}Error: wasm-opt version must be 100, but found ${WASM_OPT_VERSION}${NC}" >&2
exit 1
fi
echo -e "${GREEN} ✓ wasm-opt version 100${NC}"
# Verify xahau.h exists
if [ ! -f "${XAHAU_H}" ]; then
echo -e "${RED}Error: xahau.h not found at ${XAHAU_H}${NC}" >&2
exit 1
fi
# Create temp directory
mkdir -p "${TEMP_DIR}"
# Build all WASM files
echo -e "${BLUE}==> Building WASM files with 'make all'...${NC}"
cd "${SCRIPT_DIR}"
make all
echo -e "${GREEN} Build completed successfully${NC}"
# Function to convert WASM to hex array
wasm_to_hex_array() {
local wasm_file="$1"
local indent=" "
if [ ! -f "${wasm_file}" ]; then
echo -e "${RED}Error: WASM file not found: ${wasm_file}${NC}" >&2
return 1
fi
# Convert to hex with xxd, format with sed
xxd -p -u -c 10 "${wasm_file}" | \
sed 's/../0x&U,/g' | \
sed "s/^/${indent}/g" | \
sed '$ s/,$//'
}
# Function to update hook array in xahau.h
update_hook_array() {
local hook_name="$1"
local hex_array="$2"
local temp_file="${TEMP_DIR}/xahau.h.tmp"
echo -e "${BLUE}==> Updating ${hook_name}...${NC}"
# Check if hook already exists
if grep -q "static const std::vector<uint8_t> ${hook_name} = {" "${XAHAU_H}"; then
echo -e "${YELLOW} Replacing existing ${hook_name}${NC}"
# Use awk to replace the array content
awk -v hook="${hook_name}" -v hex="${hex_array}" '
BEGIN { in_array=0 }
{
if ($0 ~ "static const std::vector<uint8_t> " hook " = {") {
print $0
print hex
in_array=1
next
}
if (in_array && $0 ~ /};/) {
print "};"
in_array=0
next
}
if (!in_array) {
print $0
}
}
' "${XAHAU_H}" > "${temp_file}"
mv "${temp_file}" "${XAHAU_H}"
else
echo -e "${YELLOW} Adding new ${hook_name}${NC}"
# Find the position before #endif and add the new hook
awk -v hook="${hook_name}" -v hex="${hex_array}" '
{
if ($0 ~ /#endif.*XAHAU_GENESIS_HOOKS/) {
print ""
print "static const std::vector<uint8_t> " hook " = {"
print hex
print "};"
print ""
print $0
} else {
print $0
}
}
' "${XAHAU_H}" > "${temp_file}"
mv "${temp_file}" "${XAHAU_H}"
fi
echo -e "${GREEN}${hook_name} updated${NC}"
}
# Process each hook
for hook_entry in "${HOOK_FILES[@]}"; do
hook_name="${hook_entry%%:*}"
wasm_file="${SCRIPT_DIR}/${hook_entry##*:}"
echo -e "${BLUE}==> Converting ${wasm_file} to hex array...${NC}"
hex_array=$(wasm_to_hex_array "${wasm_file}")
if [ $? -ne 0 ]; then
echo -e "${RED}Error: Failed to convert ${wasm_file}${NC}" >&2
exit 1
fi
echo -e "${GREEN} Conversion successful ($(echo "${hex_array}" | wc -l) lines)${NC}"
update_hook_array "${hook_name}" "${hex_array}"
done
# Format with clang-format
echo -e "${BLUE}==> Formatting with clang-format...${NC}"
cp "${XAHAU_H}" "${TEMP_DIR}/xahau.h.before_format"
clang-format -i "${XAHAU_H}"
echo -e "${GREEN} Formatting completed${NC}"
# Verification
echo -e "${BLUE}==> Verifying changes...${NC}"
for hook_entry in "${HOOK_FILES[@]}"; do
hook_name="${hook_entry%%:*}"
if grep -q "static const std::vector<uint8_t> ${hook_name} = {" "${XAHAU_H}"; then
echo -e "${GREEN}${hook_name} found in xahau.h${NC}"
else
echo -e "${RED}${hook_name} NOT found in xahau.h${NC}" >&2
exit 1
fi
done
# Show summary
echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}Successfully updated xahau.h${NC}"
echo -e "${GREEN}========================================${NC}"
echo -e "Updated hooks:"
for hook_entry in "${HOOK_FILES[@]}"; do
hook_name="${hook_entry%%:*}"
wasm_file="${SCRIPT_DIR}/${hook_entry##*:}"
size=$(wc -c < "${wasm_file}" | tr -d ' ')
echo -e " - ${hook_name}: ${size} bytes"
done
echo ""
echo -e "File location: ${XAHAU_H}"
echo ""

View File

@@ -1,46 +0,0 @@
// For documentation please see: https://xrpl-hooks.readme.io/reference/
// Generated using generate_error.sh
#ifndef HOOK_ERROR_CODES
#define SUCCESS 0
#define OUT_OF_BOUNDS -1
#define INTERNAL_ERROR -2
#define TOO_BIG -3
#define TOO_SMALL -4
#define DOESNT_EXIST -5
#define NO_FREE_SLOTS -6
#define INVALID_ARGUMENT -7
#define ALREADY_SET -8
#define PREREQUISITE_NOT_MET -9
#define FEE_TOO_LARGE -10
#define EMISSION_FAILURE -11
#define TOO_MANY_NONCES -12
#define TOO_MANY_EMITTED_TXN -13
#define NOT_IMPLEMENTED -14
#define INVALID_ACCOUNT -15
#define GUARD_VIOLATION -16
#define INVALID_FIELD -17
#define PARSE_ERROR -18
#define RC_ROLLBACK -19
#define RC_ACCEPT -20
#define NO_SUCH_KEYLET -21
#define NOT_AN_ARRAY -22
#define NOT_AN_OBJECT -23
#define INVALID_FLOAT -10024
#define DIVISION_BY_ZERO -25
#define MANTISSA_OVERSIZED -26
#define MANTISSA_UNDERSIZED -27
#define EXPONENT_OVERSIZED -28
#define EXPONENT_UNDERSIZED -29
#define OVERFLOW -30
#define NOT_IOU_AMOUNT -31
#define NOT_AN_AMOUNT -32
#define CANT_RETURN_NEGATIVE -33
#define NOT_AUTHORIZED -34
#define PREVIOUS_FAILURE_PREVENTS_RETRY -35
#define TOO_MANY_PARAMS -36
#define INVALID_TXN -37
#define RESERVE_INSUFFICIENT -38
#define COMPLEX_NOT_SUPPORTED -39
#define DOES_NOT_MATCH -40
#define HOOK_ERROR_CODES
#endif //HOOK_ERROR_CODES

View File

@@ -1,352 +0,0 @@
// For documentation please see: https://xrpl-hooks.readme.io/reference/
// Generated using generate_extern.sh
#include <stdint.h>
#ifndef HOOK_EXTERN
extern int32_t __attribute__((noduplicate))
_g(uint32_t guard_id, uint32_t maxiter);
extern int64_t
accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t
emit(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len);
extern int64_t
etxn_burden(void);
extern int64_t
etxn_details(uint32_t write_ptr, uint32_t write_len);
extern int64_t
etxn_fee_base(uint32_t read_ptr, uint32_t read_len);
extern int64_t
etxn_generation(void);
extern int64_t
etxn_nonce(uint32_t write_ptr, uint32_t write_len);
extern int64_t
etxn_reserve(uint32_t count);
extern int64_t
fee_base(void);
extern int64_t
float_compare(int64_t float1, int64_t float2, uint32_t mode);
extern int64_t
float_divide(int64_t float1, int64_t float2);
extern int64_t
float_exponent(int64_t float1);
extern int64_t
float_exponent_set(int64_t float1, int32_t exponent);
extern int64_t
float_int(int64_t float1, uint32_t decimal_places, uint32_t abs);
extern int64_t
float_invert(int64_t float1);
extern int64_t
float_log(int64_t float1);
extern int64_t
float_mantissa(int64_t float1);
extern int64_t
float_mantissa_set(int64_t float1, int64_t mantissa);
extern int64_t
float_mulratio(
int64_t float1,
uint32_t round_up,
uint32_t numerator,
uint32_t denominator);
extern int64_t
float_multiply(int64_t float1, int64_t float2);
extern int64_t
float_negate(int64_t float1);
extern int64_t
float_one(void);
extern int64_t
float_root(int64_t float1, uint32_t n);
extern int64_t
float_set(int32_t exponent, int64_t mantissa);
extern int64_t
float_sign(int64_t float1);
extern int64_t
float_sign_set(int64_t float1, uint32_t negative);
extern int64_t
float_sto(
uint32_t write_ptr,
uint32_t write_len,
uint32_t cread_ptr,
uint32_t cread_len,
uint32_t iread_ptr,
uint32_t iread_len,
int64_t float1,
uint32_t field_code);
extern int64_t
float_sto_set(uint32_t read_ptr, uint32_t read_len);
extern int64_t
float_sum(int64_t float1, int64_t float2);
extern int64_t
hook_account(uint32_t write_ptr, uint32_t write_len);
extern int64_t
hook_again(void);
extern int64_t
hook_hash(uint32_t write_ptr, uint32_t write_len, int32_t hook_no);
extern int64_t
hook_param(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len);
extern int64_t
otxn_param(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len);
extern int64_t
hook_param_set(
uint32_t read_ptr,
uint32_t read_len,
uint32_t kread_ptr,
uint32_t kread_len,
uint32_t hread_ptr,
uint32_t hread_len);
extern int64_t
hook_pos(void);
extern int64_t
hook_skip(uint32_t read_ptr, uint32_t read_len, uint32_t flags);
extern int64_t
ledger_keylet(
uint32_t write_ptr,
uint32_t write_len,
uint32_t lread_ptr,
uint32_t lread_len,
uint32_t hread_ptr,
uint32_t hread_len);
extern int64_t
ledger_last_hash(uint32_t write_ptr, uint32_t write_len);
extern int64_t
ledger_last_time(void);
extern int64_t
ledger_nonce(uint32_t write_ptr, uint32_t write_len);
extern int64_t
ledger_seq(void);
extern int64_t
meta_slot(uint32_t slot_no);
extern int64_t
otxn_burden(void);
extern int64_t
otxn_field(uint32_t write_ptr, uint32_t write_len, uint32_t field_id);
extern int64_t
otxn_field_txt(uint32_t write_ptr, uint32_t write_len, uint32_t field_id);
extern int64_t
otxn_generation(void);
extern int64_t
otxn_id(uint32_t write_ptr, uint32_t write_len, uint32_t flags);
extern int64_t
otxn_slot(uint32_t slot_no);
extern int64_t
otxn_type(void);
extern int64_t
rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t
slot(uint32_t write_ptr, uint32_t write_len, uint32_t slot);
extern int64_t
slot_clear(uint32_t slot);
extern int64_t
slot_count(uint32_t slot);
extern int64_t
slot_float(uint32_t slot_no);
extern int64_t
slot_id(uint32_t write_ptr, uint32_t write_len, uint32_t slot);
extern int64_t
slot_set(uint32_t read_ptr, uint32_t read_len, uint32_t slot);
extern int64_t
slot_size(uint32_t slot);
extern int64_t
slot_subarray(uint32_t parent_slot, uint32_t array_id, uint32_t new_slot);
extern int64_t
slot_subfield(uint32_t parent_slot, uint32_t field_id, uint32_t new_slot);
extern int64_t
slot_type(uint32_t slot_no, uint32_t flags);
extern int64_t
state(
uint32_t write_ptr,
uint32_t write_len,
uint32_t kread_ptr,
uint32_t kread_len);
extern int64_t
state_foreign(
uint32_t write_ptr,
uint32_t write_len,
uint32_t kread_ptr,
uint32_t kread_len,
uint32_t nread_ptr,
uint32_t nread_len,
uint32_t aread_ptr,
uint32_t aread_len);
extern int64_t
state_foreign_set(
uint32_t read_ptr,
uint32_t read_len,
uint32_t kread_ptr,
uint32_t kread_len,
uint32_t nread_ptr,
uint32_t nread_len,
uint32_t aread_ptr,
uint32_t aread_len);
extern int64_t
state_set(
uint32_t read_ptr,
uint32_t read_len,
uint32_t kread_ptr,
uint32_t kread_len);
extern int64_t
sto_emplace(
uint32_t write_ptr,
uint32_t write_len,
uint32_t sread_ptr,
uint32_t sread_len,
uint32_t fread_ptr,
uint32_t fread_len,
uint32_t field_id);
extern int64_t
sto_erase(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len,
uint32_t field_id);
extern int64_t
sto_subarray(uint32_t read_ptr, uint32_t read_len, uint32_t array_id);
extern int64_t
sto_subfield(uint32_t read_ptr, uint32_t read_len, uint32_t field_id);
extern int64_t
sto_validate(uint32_t tread_ptr, uint32_t tread_len);
extern int64_t
trace(
uint32_t mread_ptr,
uint32_t mread_len,
uint32_t dread_ptr,
uint32_t dread_len,
uint32_t as_hex);
extern int64_t
trace_float(uint32_t read_ptr, uint32_t read_len, int64_t float1);
extern int64_t
trace_num(uint32_t read_ptr, uint32_t read_len, int64_t number);
extern int64_t
trace_slot(uint32_t read_ptr, uint32_t read_len, uint32_t slot);
extern int64_t
util_accid(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len);
extern int64_t
util_keylet(
uint32_t write_ptr,
uint32_t write_len,
uint32_t keylet_type,
uint32_t a,
uint32_t b,
uint32_t c,
uint32_t d,
uint32_t e,
uint32_t f);
extern int64_t
util_raddr(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len);
extern int64_t
util_sha512h(
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len);
extern int64_t
util_verify(
uint32_t dread_ptr,
uint32_t dread_len,
uint32_t sread_ptr,
uint32_t sread_len,
uint32_t kread_ptr,
uint32_t kread_len);
extern int64_t xpop_slot(uint32_t, uint32_t);
#define HOOK_EXTERN
#endif // HOOK_EXTERN

View File

@@ -1,50 +0,0 @@
/**
* Hook API include file
*
* Note to the reader:
* This include defines two types of things: external functions and macros
* Functions are used sparingly because a non-inlining compiler may produce
* undesirable output.
*
* Find documentation here: https://xrpl-hooks.readme.io/reference/
*/
#ifndef HOOKAPI_INCLUDED
#define HOOKAPI_INCLUDED 1
#define KEYLET_HOOK 1
#define KEYLET_HOOK_STATE 2
#define KEYLET_ACCOUNT 3
#define KEYLET_AMENDMENTS 4
#define KEYLET_CHILD 5
#define KEYLET_SKIP 6
#define KEYLET_FEES 7
#define KEYLET_NEGATIVE_UNL 8
#define KEYLET_LINE 9
#define KEYLET_OFFER 10
#define KEYLET_QUALITY 11
#define KEYLET_EMITTED_DIR 12
#define KEYLET_TICKET 13
#define KEYLET_SIGNERS 14
#define KEYLET_CHECK 15
#define KEYLET_DEPOSIT_PREAUTH 16
#define KEYLET_UNCHECKED 17
#define KEYLET_OWNER_DIR 18
#define KEYLET_PAGE 19
#define KEYLET_ESCROW 20
#define KEYLET_PAYCHAN 21
#define KEYLET_EMITTED 22
#define KEYLET_NFT_OFFER 23
#define KEYLET_HOOK_DEFINITION 24
#define COMPARE_EQUAL 1U
#define COMPARE_LESS 2U
#define COMPARE_GREATER 4U
#include "error.h"
#include "extern.h"
#include "sfcodes.h"
#include "macro.h"
#include "types.h"
#endif

View File

@@ -1,671 +0,0 @@
/**
* These are helper macros for writing hooks, all of them are optional as is including hookmacro.h at all
*/
#include <stdint.h>
#include "hookapi.h"
#include "sfcodes.h"
#ifndef HOOKMACROS_INCLUDED
#define HOOKMACROS_INCLUDED 1
#ifdef NDEBUG
#define DEBUG 0
#else
#define DEBUG 1
#endif
#define TRACEVAR(v) if (DEBUG) trace_num((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (int64_t)v);
#define TRACEHEX(v) if (DEBUG) trace((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (uint32_t)(v), (uint32_t)(sizeof(v)), 1);
#define TRACEXFL(v) if (DEBUG) trace_float((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (int64_t)v);
#define TRACESTR(v) if (DEBUG) trace((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (uint32_t)(v), sizeof(v), 0);
// hook developers should use this guard macro, simply GUARD(<maximum iterations>)
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
#define GUARDM(maxiter, n) _g(( (1ULL << 31U) + (__LINE__ << 16) + n), (maxiter)+1)
#define SBUF(str) (uint32_t)(str), sizeof(str)
#define REQUIRE(cond, str)\
{\
if (!(cond))\
rollback(SBUF(str), __LINE__);\
}
// make a report buffer as a c-string
// provide a name for a buffer to declare (buf)
// provide a static string
// provide an integer to print after the string
#define RBUF(buf, out_len, str, num)\
unsigned char buf[sizeof(str) + 21];\
int out_len = 0;\
{\
int i = 0;\
for (; GUARDM(sizeof(str),1),i < sizeof(str); ++i)\
(buf)[i] = str[i];\
if ((buf)[sizeof(str)-1] == 0) i--;\
if ((num) < 0) (buf)[i++] = '-';\
uint64_t unsigned_num = (uint64_t)( (num) < 0 ? (num) * -1 : (num) );\
uint64_t j = 10000000000000000000ULL;\
int start = 1;\
for (; GUARDM(20,2), unsigned_num > 0 && j > 0; j /= 10)\
{\
unsigned char digit = ( unsigned_num / j ) % 10;\
if (digit == 0 && start)\
continue;\
start = 0;\
(buf)[i++] = '0' + digit;\
}\
(buf)[i] = '\0';\
out_len = i;\
}
#define RBUF2(buff, out_len, str, num, str2, num2)\
unsigned char buff[sizeof(str) + sizeof(str2) + 42];\
int out_len = 0;\
{\
unsigned char* buf = buff;\
int i = 0;\
for (; GUARDM(sizeof(str),1),i < sizeof(str); ++i)\
(buf)[i] = str[i];\
if ((buf)[sizeof(str)-1] == 0) i--;\
if ((num) < 0) (buf)[i++] = '-';\
uint64_t unsigned_num = (uint64_t)( (num) < 0 ? (num) * -1 : (num) );\
uint64_t j = 10000000000000000000ULL;\
int start = 1;\
for (; GUARDM(20,2), unsigned_num > 0 && j > 0; j /= 10)\
{\
unsigned char digit = ( unsigned_num / j ) % 10;\
if (digit == 0 && start)\
continue;\
start = 0;\
(buf)[i++] = '0' + digit;\
}\
buf += i;\
out_len += i;\
i = 0;\
for (; GUARDM(sizeof(str2),3),i < sizeof(str2); ++i)\
(buf)[i] = str2[i];\
if ((buf)[sizeof(str2)-1] == 0) i--;\
if ((num2) < 0) (buf)[i++] = '-';\
unsigned_num = (uint64_t)( (num2) < 0 ? (num2) * -1 : (num2) );\
j = 10000000000000000000ULL;\
start = 1;\
for (; GUARDM(20,4), unsigned_num > 0 && j > 0; j /= 10)\
{\
unsigned char digit = ( unsigned_num / j ) % 10;\
if (digit == 0 && start)\
continue;\
start = 0;\
(buf)[i++] = '0' + digit;\
}\
(buf)[i] = '\0';\
out_len += i;\
}
#define CLEARBUF(b)\
{\
for (int x = 0; GUARD(sizeof(b)), x < sizeof(b); ++x)\
b[x] = 0;\
}
// returns an in64_t, negative if error, non-negative if valid drops
#define AMOUNT_TO_DROPS(amount_buffer)\
(((amount_buffer)[0] >> 7) ? -2 : (\
((((uint64_t)((amount_buffer)[0])) & 0xb00111111) << 56) +\
(((uint64_t)((amount_buffer)[1])) << 48) +\
(((uint64_t)((amount_buffer)[2])) << 40) +\
(((uint64_t)((amount_buffer)[3])) << 32) +\
(((uint64_t)((amount_buffer)[4])) << 24) +\
(((uint64_t)((amount_buffer)[5])) << 16) +\
(((uint64_t)((amount_buffer)[6])) << 8) +\
(((uint64_t)((amount_buffer)[7])))))
#define SUB_OFFSET(x) ((int32_t)(x >> 32))
#define SUB_LENGTH(x) ((int32_t)(x & 0xFFFFFFFFULL))
#define BUFFER_EQUAL_20(buf1, buf2)\
(\
*(((uint64_t*)(buf1)) + 0) == *(((uint64_t*)(buf2)) + 0) &&\
*(((uint64_t*)(buf1)) + 1) == *(((uint64_t*)(buf2)) + 1) &&\
*(((uint32_t*)(buf1)) + 4) == *(((uint32_t*)(buf2)) + 4))
#define BUFFER_EQUAL_32(buf1, buf2)\
(\
*(((uint64_t*)(buf1)) + 0) == *(((uint64_t*)(buf2)) + 0) &&\
*(((uint64_t*)(buf1)) + 1) == *(((uint64_t*)(buf2)) + 1) &&\
*(((uint64_t*)(buf1)) + 2) == *(((uint64_t*)(buf2)) + 2) &&\
*(((uint64_t*)(buf1)) + 3) == *(((uint64_t*)(buf2)) + 3))
// when using this macro buf1len may be dynamic but buf2len must be static
// provide n >= 1 to indicate how many times the macro will be hit on the line of code
// e.g. if it is in a loop that loops 10 times n = 10
#define BUFFER_EQUAL_GUARD(output, buf1, buf1len, buf2, buf2len, n)\
{\
output = ((buf1len) == (buf2len) ? 1 : 0);\
for (int x = 0; GUARDM( (buf2len) * (n), 1 ), output && x < (buf2len);\
++x)\
output = *(((uint8_t*)(buf1)) + x) == *(((uint8_t*)(buf2)) + x);\
}
#define BUFFER_SWAP(x,y)\
{\
uint8_t* z = x;\
x = y;\
y = z;\
}
#define ACCOUNT_COMPARE(compare_result, buf1, buf2)\
{\
compare_result = 0;\
for (int i = 0; GUARD(20), i < 20; ++i)\
{\
if (buf1[i] > buf2[i])\
{\
compare_result = 1;\
break;\
}\
else if (buf1[i] < buf2[i])\
{\
compare_result = -1;\
break;\
}\
}\
}
#define BUFFER_EQUAL_STR_GUARD(output, buf1, buf1len, str, n)\
BUFFER_EQUAL_GUARD(output, buf1, buf1len, str, (sizeof(str)-1), n)
#define BUFFER_EQUAL_STR(output, buf1, buf1len, str)\
BUFFER_EQUAL_GUARD(output, buf1, buf1len, str, (sizeof(str)-1), 1)
#define BUFFER_EQUAL(output, buf1, buf2, compare_len)\
BUFFER_EQUAL_GUARD(output, buf1, compare_len, buf2, compare_len, 1)
#define UINT16_TO_BUF(buf_raw, i)\
{\
unsigned char* buf = (unsigned char*)buf_raw;\
buf[0] = (((uint64_t)i) >> 8) & 0xFFUL;\
buf[1] = (((uint64_t)i) >> 0) & 0xFFUL;\
}
#define UINT16_FROM_BUF(buf)\
(((uint64_t)((buf)[0]) << 8) +\
((uint64_t)((buf)[1]) << 0))
#define UINT32_TO_BUF(buf_raw, i)\
{\
unsigned char* buf = (unsigned char*)buf_raw;\
buf[0] = (((uint64_t)i) >> 24) & 0xFFUL;\
buf[1] = (((uint64_t)i) >> 16) & 0xFFUL;\
buf[2] = (((uint64_t)i) >> 8) & 0xFFUL;\
buf[3] = (((uint64_t)i) >> 0) & 0xFFUL;\
}
#define UINT32_FROM_BUF(buf)\
(((uint64_t)((buf)[0]) << 24) +\
((uint64_t)((buf)[1]) << 16) +\
((uint64_t)((buf)[2]) << 8) +\
((uint64_t)((buf)[3]) << 0))
#define UINT64_TO_BUF(buf_raw, i)\
{\
unsigned char* buf = (unsigned char*)buf_raw;\
buf[0] = (((uint64_t)i) >> 56) & 0xFFUL;\
buf[1] = (((uint64_t)i) >> 48) & 0xFFUL;\
buf[2] = (((uint64_t)i) >> 40) & 0xFFUL;\
buf[3] = (((uint64_t)i) >> 32) & 0xFFUL;\
buf[4] = (((uint64_t)i) >> 24) & 0xFFUL;\
buf[5] = (((uint64_t)i) >> 16) & 0xFFUL;\
buf[6] = (((uint64_t)i) >> 8) & 0xFFUL;\
buf[7] = (((uint64_t)i) >> 0) & 0xFFUL;\
}
#define UINT64_FROM_BUF(buf)\
(((uint64_t)((buf)[0]) << 56) +\
((uint64_t)((buf)[1]) << 48) +\
((uint64_t)((buf)[2]) << 40) +\
((uint64_t)((buf)[3]) << 32) +\
((uint64_t)((buf)[4]) << 24) +\
((uint64_t)((buf)[5]) << 16) +\
((uint64_t)((buf)[6]) << 8) +\
((uint64_t)((buf)[7]) << 0))
#define INT64_FROM_BUF(buf)\
((((uint64_t)((buf)[0] & 0x7FU) << 56) +\
((uint64_t)((buf)[1]) << 48) +\
((uint64_t)((buf)[2]) << 40) +\
((uint64_t)((buf)[3]) << 32) +\
((uint64_t)((buf)[4]) << 24) +\
((uint64_t)((buf)[5]) << 16) +\
((uint64_t)((buf)[6]) << 8) +\
((uint64_t)((buf)[7]) << 0)) * (buf[0] & 0x80U ? -1 : 1))
#define INT64_TO_BUF(buf_raw, i)\
{\
unsigned char* buf = (unsigned char*)buf_raw;\
buf[0] = (((uint64_t)i) >> 56) & 0x7FUL;\
buf[1] = (((uint64_t)i) >> 48) & 0xFFUL;\
buf[2] = (((uint64_t)i) >> 40) & 0xFFUL;\
buf[3] = (((uint64_t)i) >> 32) & 0xFFUL;\
buf[4] = (((uint64_t)i) >> 24) & 0xFFUL;\
buf[5] = (((uint64_t)i) >> 16) & 0xFFUL;\
buf[6] = (((uint64_t)i) >> 8) & 0xFFUL;\
buf[7] = (((uint64_t)i) >> 0) & 0xFFUL;\
if (i < 0) buf[0] |= 0x80U;\
}
#define ttPAYMENT 0
#define ttESCROW_CREATE 1
#define ttESCROW_FINISH 2
#define ttACCOUNT_SET 3
#define ttESCROW_CANCEL 4
#define ttREGULAR_KEY_SET 5
#define ttOFFER_CREATE 7
#define ttOFFER_CANCEL 8
#define ttTICKET_CREATE 10
#define ttSIGNER_LIST_SET 12
#define ttPAYCHAN_CREATE 13
#define ttPAYCHAN_FUND 14
#define ttPAYCHAN_CLAIM 15
#define ttCHECK_CREATE 16
#define ttCHECK_CASH 17
#define ttCHECK_CANCEL 18
#define ttDEPOSIT_PREAUTH 19
#define ttTRUST_SET 20
#define ttACCOUNT_DELETE 21
#define ttHOOK_SET 22
#define ttNFTOKEN_MINT 25
#define ttNFTOKEN_BURN 26
#define ttNFTOKEN_CREATE_OFFER 27
#define ttNFTOKEN_CANCEL_OFFER 28
#define ttNFTOKEN_ACCEPT_OFFER 29
#define ttURITOKEN_MINT 45
#define ttURITOKEN_BURN 46
#define ttURITOKEN_BUY 47
#define ttURITOKEN_CREATE_SELL_OFFER 48
#define ttURITOKEN_CANCEL_SELL_OFFER 49
#define ttCLAIM_REWARD 98
#define ttINVOKE 99
#define ttAMENDMENT 100
#define ttFEE 101
#define ttUNL_MODIFY 102
#define ttEMIT_FAILURE 103
#define tfCANONICAL 0x80000000UL
#define atACCOUNT 1U
#define atOWNER 2U
#define atDESTINATION 3U
#define atISSUER 4U
#define atAUTHORIZE 5U
#define atUNAUTHORIZE 6U
#define atTARGET 7U
#define atREGULARKEY 8U
#define atPSEUDOCALLBACK 9U
#define amAMOUNT 1U
#define amBALANCE 2U
#define amLIMITAMOUNT 3U
#define amTAKERPAYS 4U
#define amTAKERGETS 5U
#define amLOWLIMIT 6U
#define amHIGHLIMIT 7U
#define amFEE 8U
#define amSENDMAX 9U
#define amDELIVERMIN 10U
#define amMINIMUMOFFER 16U
#define amRIPPLEESCROW 17U
#define amDELIVEREDAMOUNT 18U
/**
* RH NOTE -- PAY ATTENTION
*
* ALL 'ENCODE' MACROS INCREMENT BUF_OUT
* THIS IS TO MAKE CHAINING EASY
* BUF_OUT IS A SACRIFICIAL POINTER
*
* 'ENCODE' MACROS WITH CONSTANTS HAVE
* ALIASING TO ASSIST YOU WITH ORDER
* _TYPECODE_FIELDCODE_ENCODE_MACRO
* TO PRODUCE A SERIALIZED OBJECT
* IN CANONICAL FORMAT YOU MUST ORDER
* FIRST BY TYPE CODE THEN BY FIELD CODE
*
* ALL 'PREPARE' MACROS PRESERVE POINTERS
*
**/
#define ENCODE_TL_SIZE 49
#define ENCODE_TL(buf_out, tlamt, amount_type)\
{\
uint8_t uat = amount_type; \
buf_out[0] = 0x60U +(uat & 0x0FU ); \
for (int i = 1; GUARDM(48, 1), i < 49; ++i)\
buf_out[i] = tlamt[i-1];\
buf_out += ENCODE_TL_SIZE;\
}
#define _06_XX_ENCODE_TL(buf_out, drops, amount_type )\
ENCODE_TL(buf_out, drops, amount_type );
#define ENCODE_TL_AMOUNT(buf_out, drops )\
ENCODE_TL(buf_out, drops, amAMOUNT );
#define _06_01_ENCODE_TL_AMOUNT(buf_out, drops )\
ENCODE_TL_AMOUNT(buf_out, drops );
// Encode drops to serialization format
// consumes 9 bytes
#define ENCODE_DROPS_SIZE 9
#define ENCODE_DROPS(buf_out, drops, amount_type ) \
{\
uint8_t uat = amount_type; \
uint64_t udrops = drops; \
buf_out[0] = 0x60U +(uat & 0x0FU ); \
buf_out[1] = 0b01000000 + (( udrops >> 56 ) & 0b00111111 ); \
buf_out[2] = (udrops >> 48) & 0xFFU; \
buf_out[3] = (udrops >> 40) & 0xFFU; \
buf_out[4] = (udrops >> 32) & 0xFFU; \
buf_out[5] = (udrops >> 24) & 0xFFU; \
buf_out[6] = (udrops >> 16) & 0xFFU; \
buf_out[7] = (udrops >> 8) & 0xFFU; \
buf_out[8] = (udrops >> 0) & 0xFFU; \
buf_out += ENCODE_DROPS_SIZE; \
}
#define _06_XX_ENCODE_DROPS(buf_out, drops, amount_type )\
ENCODE_DROPS(buf_out, drops, amount_type );
#define ENCODE_DROPS_AMOUNT(buf_out, drops )\
ENCODE_DROPS(buf_out, drops, amAMOUNT );
#define _06_01_ENCODE_DROPS_AMOUNT(buf_out, drops )\
ENCODE_DROPS_AMOUNT(buf_out, drops );
#define ENCODE_DROPS_FEE(buf_out, drops )\
ENCODE_DROPS(buf_out, drops, amFEE );
#define _06_08_ENCODE_DROPS_FEE(buf_out, drops )\
ENCODE_DROPS_FEE(buf_out, drops );
#define ENCODE_TT_SIZE 3
#define ENCODE_TT(buf_out, tt )\
{\
uint8_t utt = tt;\
buf_out[0] = 0x12U;\
buf_out[1] =(utt >> 8 ) & 0xFFU;\
buf_out[2] =(utt >> 0 ) & 0xFFU;\
buf_out += ENCODE_TT_SIZE; \
}
#define _01_02_ENCODE_TT(buf_out, tt)\
ENCODE_TT(buf_out, tt);
#define ENCODE_ACCOUNT_SIZE 22
#define ENCODE_ACCOUNT(buf_out, account_id, account_type)\
{\
uint8_t uat = account_type;\
buf_out[0] = 0x80U + uat;\
buf_out[1] = 0x14U;\
*(uint64_t*)(buf_out + 2) = *(uint64_t*)(account_id + 0);\
*(uint64_t*)(buf_out + 10) = *(uint64_t*)(account_id + 8);\
*(uint32_t*)(buf_out + 18) = *(uint32_t*)(account_id + 16);\
buf_out += ENCODE_ACCOUNT_SIZE;\
}
#define _08_XX_ENCODE_ACCOUNT(buf_out, account_id, account_type)\
ENCODE_ACCOUNT(buf_out, account_id, account_type);
#define ENCODE_ACCOUNT_SRC_SIZE 22
#define ENCODE_ACCOUNT_SRC(buf_out, account_id)\
ENCODE_ACCOUNT(buf_out, account_id, atACCOUNT);
#define _08_01_ENCODE_ACCOUNT_SRC(buf_out, account_id)\
ENCODE_ACCOUNT_SRC(buf_out, account_id);
#define ENCODE_ACCOUNT_DST_SIZE 22
#define ENCODE_ACCOUNT_DST(buf_out, account_id)\
ENCODE_ACCOUNT(buf_out, account_id, atDESTINATION);
#define _08_03_ENCODE_ACCOUNT_DST(buf_out, account_id)\
ENCODE_ACCOUNT_DST(buf_out, account_id);
#define ENCODE_ACCOUNT_OWNER_SIZE 22
#define ENCODE_ACCOUNT_OWNER(buf_out, account_id) \
ENCODE_ACCOUNT(buf_out, account_id, atOWNER);
#define _08_02_ENCODE_ACCOUNT_OWNER(buf_out, account_id) \
ENCODE_ACCOUNT_OWNER(buf_out, account_id);
#define ENCODE_UINT32_COMMON_SIZE 5U
#define ENCODE_UINT32_COMMON(buf_out, i, field)\
{\
uint32_t ui = i; \
uint8_t uf = field; \
buf_out[0] = 0x20U +(uf & 0x0FU); \
buf_out[1] =(ui >> 24 ) & 0xFFU; \
buf_out[2] =(ui >> 16 ) & 0xFFU; \
buf_out[3] =(ui >> 8 ) & 0xFFU; \
buf_out[4] =(ui >> 0 ) & 0xFFU; \
buf_out += ENCODE_UINT32_COMMON_SIZE; \
}
#define _02_XX_ENCODE_UINT32_COMMON(buf_out, i, field)\
ENCODE_UINT32_COMMON(buf_out, i, field)\
#define ENCODE_UINT32_UNCOMMON_SIZE 6U
#define ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
{\
uint32_t ui = i; \
uint8_t uf = field; \
buf_out[0] = 0x20U; \
buf_out[1] = uf; \
buf_out[2] =(ui >> 24 ) & 0xFFU; \
buf_out[3] =(ui >> 16 ) & 0xFFU; \
buf_out[4] =(ui >> 8 ) & 0xFFU; \
buf_out[5] =(ui >> 0 ) & 0xFFU; \
buf_out += ENCODE_UINT32_UNCOMMON_SIZE; \
}
#define _02_XX_ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
#define ENCODE_LLS_SIZE 6U
#define ENCODE_LLS(buf_out, lls )\
ENCODE_UINT32_UNCOMMON(buf_out, lls, 0x1B );
#define _02_27_ENCODE_LLS(buf_out, lls )\
ENCODE_LLS(buf_out, lls );
#define ENCODE_FLS_SIZE 6U
#define ENCODE_FLS(buf_out, fls )\
ENCODE_UINT32_UNCOMMON(buf_out, fls, 0x1A );
#define _02_26_ENCODE_FLS(buf_out, fls )\
ENCODE_FLS(buf_out, fls );
#define ENCODE_TAG_SRC_SIZE 5
#define ENCODE_TAG_SRC(buf_out, tag )\
ENCODE_UINT32_COMMON(buf_out, tag, 0x3U );
#define _02_03_ENCODE_TAG_SRC(buf_out, tag )\
ENCODE_TAG_SRC(buf_out, tag );
#define ENCODE_TAG_DST_SIZE 5
#define ENCODE_TAG_DST(buf_out, tag )\
ENCODE_UINT32_COMMON(buf_out, tag, 0xEU );
#define _02_14_ENCODE_TAG_DST(buf_out, tag )\
ENCODE_TAG_DST(buf_out, tag );
#define ENCODE_SEQUENCE_SIZE 5
#define ENCODE_SEQUENCE(buf_out, sequence )\
ENCODE_UINT32_COMMON(buf_out, sequence, 0x4U );
#define _02_04_ENCODE_SEQUENCE(buf_out, sequence )\
ENCODE_SEQUENCE(buf_out, sequence );
#define ENCODE_FLAGS_SIZE 5
#define ENCODE_FLAGS(buf_out, tag )\
ENCODE_UINT32_COMMON(buf_out, tag, 0x2U );
#define _02_02_ENCODE_FLAGS(buf_out, tag )\
ENCODE_FLAGS(buf_out, tag );
#define ENCODE_SIGNING_PUBKEY_SIZE 35
#define ENCODE_SIGNING_PUBKEY(buf_out, pkey )\
{\
buf_out[0] = 0x73U;\
buf_out[1] = 0x21U;\
*(uint64_t*)(buf_out + 2) = *(uint64_t*)(pkey + 0);\
*(uint64_t*)(buf_out + 10) = *(uint64_t*)(pkey + 8);\
*(uint64_t*)(buf_out + 18) = *(uint64_t*)(pkey + 16);\
*(uint64_t*)(buf_out + 26) = *(uint64_t*)(pkey + 24);\
buf[34] = pkey[32];\
buf_out += ENCODE_SIGNING_PUBKEY_SIZE;\
}
#define _07_03_ENCODE_SIGNING_PUBKEY(buf_out, pkey )\
ENCODE_SIGNING_PUBKEY(buf_out, pkey );
#define ENCODE_SIGNING_PUBKEY_NULL_SIZE 2
#define ENCODE_SIGNING_PUBKEY_NULL(buf_out )\
{\
*buf_out++ = 0x73U;\
*buf_out++ = 0x00U;\
}
#define _07_03_ENCODE_SIGNING_PUBKEY_NULL(buf_out )\
ENCODE_SIGNING_PUBKEY_NULL(buf_out );
#define _0E_0E_ENCODE_HOOKOBJ(buf_out, hhash)\
{\
uint8_t* hook0 = (hhash);\
*buf_out++ = 0xEEU; /* hook obj start */ \
if (hook0 == 0) /* noop */\
{\
/* do nothing */ \
}\
else\
{\
*buf_out++ = 0x22U; /* flags = override */\
*buf_out++ = 0x00U;\
*buf_out++ = 0x00U;\
*buf_out++ = 0x00U;\
*buf_out++ = 0x01U;\
if (hook0 == 0xFFFFFFFFUL) /* delete operation */ \
{\
*buf_out++ = 0x7BU; /* empty createcode */ \
*buf_out++ = 0x00U;\
}\
else\
{\
*buf_out++ = 0x50U; /* HookHash */\
*buf_out++ = 0x1FU;\
uint64_t* d = (uint64_t*)buf_out;\
uint64_t* s = (uint64_t*)hook0;\
*d++ = *s++;\
*d++ = *s++;\
*d++ = *s++;\
*d++ = *s++;\
buf_out+=32;\
}\
}\
*buf_out++ = 0xE1U;\
}
#define PREPARE_HOOKSET(buf_out_master, maxlen, h, sizeout)\
{\
uint8_t* buf_out = (buf_out_master); \
uint8_t acc[20]; \
uint32_t cls = (uint32_t)ledger_seq(); \
hook_account(SBUF(acc)); \
_01_02_ENCODE_TT (buf_out, ttHOOK_SET ); \
_02_02_ENCODE_FLAGS (buf_out, tfCANONICAL ); \
_02_04_ENCODE_SEQUENCE (buf_out, 0 ); \
_02_26_ENCODE_FLS (buf_out, cls + 1 ); \
_02_27_ENCODE_LLS (buf_out, cls + 5 ); \
uint8_t* fee_ptr = buf_out; \
_06_08_ENCODE_DROPS_FEE (buf_out, 0 ); \
_07_03_ENCODE_SIGNING_PUBKEY_NULL (buf_out ); \
_08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); \
uint32_t remaining_size = (maxlen) - (buf_out - (buf_out_master)); \
int64_t edlen = etxn_details((uint32_t)buf_out, remaining_size); \
buf_out += edlen; \
*buf_out++ = 0xFBU; /* hook array start */ \
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[0]); \
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[1]); \
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[2]); \
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[3]); \
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[4]); \
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[5]); \
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[6]); \
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[7]); \
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[8]); \
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[9]); \
*buf_out++ = 0xF1U; /* hook array end */ \
sizeout = (buf_out - (buf_out_master)); \
int64_t fee = etxn_fee_base(buf_out_master, sizeout); \
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
}
#ifdef HAS_CALLBACK
#define PREPARE_PAYMENT_SIMPLE_SIZE 270U
#else
#define PREPARE_PAYMENT_SIMPLE_SIZE 248U
#endif
#define PREPARE_PAYMENT_SIMPLE(buf_out_master, drops_amount_raw, to_address, dest_tag_raw, src_tag_raw)\
{\
uint8_t* buf_out = buf_out_master;\
uint8_t acc[20];\
uint64_t drops_amount = (drops_amount_raw);\
uint32_t dest_tag = (dest_tag_raw);\
uint32_t src_tag = (src_tag_raw);\
uint32_t cls = (uint32_t)ledger_seq();\
hook_account(SBUF(acc));\
_01_02_ENCODE_TT (buf_out, ttPAYMENT ); /* uint16 | size 3 */ \
_02_02_ENCODE_FLAGS (buf_out, tfCANONICAL ); /* uint32 | size 5 */ \
_02_03_ENCODE_TAG_SRC (buf_out, src_tag ); /* uint32 | size 5 */ \
_02_04_ENCODE_SEQUENCE (buf_out, 0 ); /* uint32 | size 5 */ \
_02_14_ENCODE_TAG_DST (buf_out, dest_tag ); /* uint32 | size 5 */ \
_02_26_ENCODE_FLS (buf_out, cls + 1 ); /* uint32 | size 6 */ \
_02_27_ENCODE_LLS (buf_out, cls + 5 ); /* uint32 | size 6 */ \
_06_01_ENCODE_DROPS_AMOUNT (buf_out, drops_amount ); /* amount | size 9 */ \
uint8_t* fee_ptr = buf_out;\
_06_08_ENCODE_DROPS_FEE (buf_out, 0 ); /* amount | size 9 */ \
_07_03_ENCODE_SIGNING_PUBKEY_NULL (buf_out ); /* pk | size 35 */ \
_08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); /* account | size 22 */ \
_08_03_ENCODE_ACCOUNT_DST (buf_out, to_address ); /* account | size 22 */ \
int64_t edlen = etxn_details((uint32_t)buf_out, PREPARE_PAYMENT_SIMPLE_SIZE); /* emitdet | size 1?? */ \
int64_t fee = etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_SIZE); \
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
}
#ifdef HAS_CALLBACK
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE 309
#else
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE 287
#endif
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE(buf_out_master, tlamt, to_address, dest_tag_raw, src_tag_raw)\
{\
uint8_t* buf_out = buf_out_master;\
uint8_t acc[20];\
uint32_t dest_tag = (dest_tag_raw);\
uint32_t src_tag = (src_tag_raw);\
uint32_t cls = (uint32_t)ledger_seq();\
hook_account(SBUF(acc));\
_01_02_ENCODE_TT (buf_out, ttPAYMENT ); /* uint16 | size 3 */ \
_02_02_ENCODE_FLAGS (buf_out, tfCANONICAL ); /* uint32 | size 5 */ \
_02_03_ENCODE_TAG_SRC (buf_out, src_tag ); /* uint32 | size 5 */ \
_02_04_ENCODE_SEQUENCE (buf_out, 0 ); /* uint32 | size 5 */ \
_02_14_ENCODE_TAG_DST (buf_out, dest_tag ); /* uint32 | size 5 */ \
_02_26_ENCODE_FLS (buf_out, cls + 1 ); /* uint32 | size 6 */ \
_02_27_ENCODE_LLS (buf_out, cls + 5 ); /* uint32 | size 6 */ \
_06_01_ENCODE_TL_AMOUNT (buf_out, tlamt ); /* amount | size 48 */ \
uint8_t* fee_ptr = buf_out;\
_06_08_ENCODE_DROPS_FEE (buf_out, 0 ); /* amount | size 9 */ \
_07_03_ENCODE_SIGNING_PUBKEY_NULL (buf_out ); /* pk | size 35 */ \
_08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); /* account | size 22 */ \
_08_03_ENCODE_ACCOUNT_DST (buf_out, to_address ); /* account | size 22 */ \
etxn_details((uint32_t)buf_out, PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE); /* emitdet | size 1?? */ \
int64_t fee = etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE); \
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
}
#endif

View File

@@ -1,215 +0,0 @@
// For documentation please see: https://xrpl-hooks.readme.io/reference/
// Generated using generate_sfcodes.sh
#define sfCloseResolution ((16U << 16U) + 1U)
#define sfMethod ((16U << 16U) + 2U)
#define sfTransactionResult ((16U << 16U) + 3U)
#define sfTickSize ((16U << 16U) + 16U)
#define sfUNLModifyDisabling ((16U << 16U) + 17U)
#define sfHookResult ((16U << 16U) + 18U)
#define sfLedgerEntryType ((1U << 16U) + 1U)
#define sfTransactionType ((1U << 16U) + 2U)
#define sfSignerWeight ((1U << 16U) + 3U)
#define sfTransferFee ((1U << 16U) + 4U)
#define sfVersion ((1U << 16U) + 16U)
#define sfHookStateChangeCount ((1U << 16U) + 17U)
#define sfHookEmitCount ((1U << 16U) + 18U)
#define sfHookExecutionIndex ((1U << 16U) + 19U)
#define sfHookApiVersion ((1U << 16U) + 20U)
#define sfNetworkID ((2U << 16U) + 1U)
#define sfFlags ((2U << 16U) + 2U)
#define sfSourceTag ((2U << 16U) + 3U)
#define sfSequence ((2U << 16U) + 4U)
#define sfPreviousTxnLgrSeq ((2U << 16U) + 5U)
#define sfLedgerSequence ((2U << 16U) + 6U)
#define sfCloseTime ((2U << 16U) + 7U)
#define sfParentCloseTime ((2U << 16U) + 8U)
#define sfSigningTime ((2U << 16U) + 9U)
#define sfExpiration ((2U << 16U) + 10U)
#define sfTransferRate ((2U << 16U) + 11U)
#define sfWalletSize ((2U << 16U) + 12U)
#define sfOwnerCount ((2U << 16U) + 13U)
#define sfDestinationTag ((2U << 16U) + 14U)
#define sfHighQualityIn ((2U << 16U) + 16U)
#define sfHighQualityOut ((2U << 16U) + 17U)
#define sfLowQualityIn ((2U << 16U) + 18U)
#define sfLowQualityOut ((2U << 16U) + 19U)
#define sfQualityIn ((2U << 16U) + 20U)
#define sfQualityOut ((2U << 16U) + 21U)
#define sfStampEscrow ((2U << 16U) + 22U)
#define sfBondAmount ((2U << 16U) + 23U)
#define sfLoadFee ((2U << 16U) + 24U)
#define sfOfferSequence ((2U << 16U) + 25U)
#define sfFirstLedgerSequence ((2U << 16U) + 26U)
#define sfLastLedgerSequence ((2U << 16U) + 27U)
#define sfTransactionIndex ((2U << 16U) + 28U)
#define sfOperationLimit ((2U << 16U) + 29U)
#define sfReferenceFeeUnits ((2U << 16U) + 30U)
#define sfReserveBase ((2U << 16U) + 31U)
#define sfReserveIncrement ((2U << 16U) + 32U)
#define sfSetFlag ((2U << 16U) + 33U)
#define sfClearFlag ((2U << 16U) + 34U)
#define sfSignerQuorum ((2U << 16U) + 35U)
#define sfCancelAfter ((2U << 16U) + 36U)
#define sfFinishAfter ((2U << 16U) + 37U)
#define sfSignerListID ((2U << 16U) + 38U)
#define sfSettleDelay ((2U << 16U) + 39U)
#define sfTicketCount ((2U << 16U) + 40U)
#define sfTicketSequence ((2U << 16U) + 41U)
#define sfNFTokenTaxon ((2U << 16U) + 42U)
#define sfMintedNFTokens ((2U << 16U) + 43U)
#define sfBurnedNFTokens ((2U << 16U) + 44U)
#define sfHookStateCount ((2U << 16U) + 45U)
#define sfEmitGeneration ((2U << 16U) + 46U)
#define sfLockCount ((2U << 16U) + 47U)
#define sfRewardTime ((2U << 16U) + 98U)
#define sfRewardLgrFirst ((2U << 16U) + 99U)
#define sfRewardLgrLast ((2U << 16U) + 100U)
#define sfIndexNext ((3U << 16U) + 1U)
#define sfIndexPrevious ((3U << 16U) + 2U)
#define sfBookNode ((3U << 16U) + 3U)
#define sfOwnerNode ((3U << 16U) + 4U)
#define sfBaseFee ((3U << 16U) + 5U)
#define sfExchangeRate ((3U << 16U) + 6U)
#define sfLowNode ((3U << 16U) + 7U)
#define sfHighNode ((3U << 16U) + 8U)
#define sfDestinationNode ((3U << 16U) + 9U)
#define sfCookie ((3U << 16U) + 10U)
#define sfServerVersion ((3U << 16U) + 11U)
#define sfNFTokenOfferNode ((3U << 16U) + 12U)
#define sfEmitBurden ((3U << 16U) + 13U)
#define sfHookInstructionCount ((3U << 16U) + 17U)
#define sfHookReturnCode ((3U << 16U) + 18U)
#define sfReferenceCount ((3U << 16U) + 19U)
#define sfRewardAccumulator ((3U << 16U) + 100U)
#define sfEmailHash ((4U << 16U) + 1U)
#define sfTakerPaysCurrency ((10U << 16U) + 1U)
#define sfTakerPaysIssuer ((10U << 16U) + 2U)
#define sfTakerGetsCurrency ((10U << 16U) + 3U)
#define sfTakerGetsIssuer ((10U << 16U) + 4U)
#define sfLedgerHash ((5U << 16U) + 1U)
#define sfParentHash ((5U << 16U) + 2U)
#define sfTransactionHash ((5U << 16U) + 3U)
#define sfAccountHash ((5U << 16U) + 4U)
#define sfPreviousTxnID ((5U << 16U) + 5U)
#define sfLedgerIndex ((5U << 16U) + 6U)
#define sfWalletLocator ((5U << 16U) + 7U)
#define sfRootIndex ((5U << 16U) + 8U)
#define sfAccountTxnID ((5U << 16U) + 9U)
#define sfNFTokenID ((5U << 16U) + 10U)
#define sfEmitParentTxnID ((5U << 16U) + 11U)
#define sfEmitNonce ((5U << 16U) + 12U)
#define sfEmitHookHash ((5U << 16U) + 13U)
#define sfBookDirectory ((5U << 16U) + 16U)
#define sfInvoiceID ((5U << 16U) + 17U)
#define sfNickname ((5U << 16U) + 18U)
#define sfAmendment ((5U << 16U) + 19U)
#define sfHookOn ((5U << 16U) + 20U)
#define sfDigest ((5U << 16U) + 21U)
#define sfChannel ((5U << 16U) + 22U)
#define sfConsensusHash ((5U << 16U) + 23U)
#define sfCheckID ((5U << 16U) + 24U)
#define sfValidatedHash ((5U << 16U) + 25U)
#define sfPreviousPageMin ((5U << 16U) + 26U)
#define sfNextPageMin ((5U << 16U) + 27U)
#define sfNFTokenBuyOffer ((5U << 16U) + 28U)
#define sfNFTokenSellOffer ((5U << 16U) + 29U)
#define sfHookStateKey ((5U << 16U) + 30U)
#define sfHookHash ((5U << 16U) + 31U)
#define sfHookNamespace ((5U << 16U) + 32U)
#define sfHookSetTxnID ((5U << 16U) + 33U)
#define sfOfferID ((5U << 16U) + 34U)
#define sfEscrowID ((5U << 16U) + 35U)
#define sfURITokenID ((5U << 16U) + 36U)
#define sfAmount ((6U << 16U) + 1U)
#define sfBalance ((6U << 16U) + 2U)
#define sfLimitAmount ((6U << 16U) + 3U)
#define sfTakerPays ((6U << 16U) + 4U)
#define sfTakerGets ((6U << 16U) + 5U)
#define sfLowLimit ((6U << 16U) + 6U)
#define sfHighLimit ((6U << 16U) + 7U)
#define sfFee ((6U << 16U) + 8U)
#define sfSendMax ((6U << 16U) + 9U)
#define sfDeliverMin ((6U << 16U) + 10U)
#define sfMinimumOffer ((6U << 16U) + 16U)
#define sfRippleEscrow ((6U << 16U) + 17U)
#define sfDeliveredAmount ((6U << 16U) + 18U)
#define sfNFTokenBrokerFee ((6U << 16U) + 19U)
#define sfHookCallbackFee ((6U << 16U) + 20U)
#define sfLockedBalance ((6U << 16U) + 21U)
#define sfPublicKey ((7U << 16U) + 1U)
#define sfMessageKey ((7U << 16U) + 2U)
#define sfSigningPubKey ((7U << 16U) + 3U)
#define sfTxnSignature ((7U << 16U) + 4U)
#define sfURI ((7U << 16U) + 5U)
#define sfSignature ((7U << 16U) + 6U)
#define sfDomain ((7U << 16U) + 7U)
#define sfFundCode ((7U << 16U) + 8U)
#define sfRemoveCode ((7U << 16U) + 9U)
#define sfExpireCode ((7U << 16U) + 10U)
#define sfCreateCode ((7U << 16U) + 11U)
#define sfMemoType ((7U << 16U) + 12U)
#define sfMemoData ((7U << 16U) + 13U)
#define sfMemoFormat ((7U << 16U) + 14U)
#define sfFulfillment ((7U << 16U) + 16U)
#define sfCondition ((7U << 16U) + 17U)
#define sfMasterSignature ((7U << 16U) + 18U)
#define sfUNLModifyValidator ((7U << 16U) + 19U)
#define sfValidatorToDisable ((7U << 16U) + 20U)
#define sfValidatorToReEnable ((7U << 16U) + 21U)
#define sfHookStateData ((7U << 16U) + 22U)
#define sfHookReturnString ((7U << 16U) + 23U)
#define sfHookParameterName ((7U << 16U) + 24U)
#define sfHookParameterValue ((7U << 16U) + 25U)
#define sfBlob ((7U << 16U) + 26U)
#define sfAccount ((8U << 16U) + 1U)
#define sfOwner ((8U << 16U) + 2U)
#define sfDestination ((8U << 16U) + 3U)
#define sfIssuer ((8U << 16U) + 4U)
#define sfAuthorize ((8U << 16U) + 5U)
#define sfUnauthorize ((8U << 16U) + 6U)
#define sfRegularKey ((8U << 16U) + 8U)
#define sfNFTokenMinter ((8U << 16U) + 9U)
#define sfEmitCallback ((8U << 16U) + 10U)
#define sfHookAccount ((8U << 16U) + 16U)
#define sfIndexes ((19U << 16U) + 1U)
#define sfHashes ((19U << 16U) + 2U)
#define sfAmendments ((19U << 16U) + 3U)
#define sfNFTokenOffers ((19U << 16U) + 4U)
#define sfHookNamespaces ((19U << 16U) + 5U)
#define sfPaths ((18U << 16U) + 1U)
#define sfTransactionMetaData ((14U << 16U) + 2U)
#define sfCreatedNode ((14U << 16U) + 3U)
#define sfDeletedNode ((14U << 16U) + 4U)
#define sfModifiedNode ((14U << 16U) + 5U)
#define sfPreviousFields ((14U << 16U) + 6U)
#define sfFinalFields ((14U << 16U) + 7U)
#define sfNewFields ((14U << 16U) + 8U)
#define sfTemplateEntry ((14U << 16U) + 9U)
#define sfMemo ((14U << 16U) + 10U)
#define sfSignerEntry ((14U << 16U) + 11U)
#define sfNFToken ((14U << 16U) + 12U)
#define sfEmitDetails ((14U << 16U) + 13U)
#define sfHook ((14U << 16U) + 14U)
#define sfSigner ((14U << 16U) + 16U)
#define sfMajority ((14U << 16U) + 18U)
#define sfDisabledValidator ((14U << 16U) + 19U)
#define sfEmittedTxn ((14U << 16U) + 20U)
#define sfHookExecution ((14U << 16U) + 21U)
#define sfHookDefinition ((14U << 16U) + 22U)
#define sfHookParameter ((14U << 16U) + 23U)
#define sfHookGrant ((14U << 16U) + 24U)
#define sfSigners ((15U << 16U) + 3U)
#define sfSignerEntries ((15U << 16U) + 4U)
#define sfTemplate ((15U << 16U) + 5U)
#define sfNecessary ((15U << 16U) + 6U)
#define sfSufficient ((15U << 16U) + 7U)
#define sfAffectedNodes ((15U << 16U) + 8U)
#define sfMemos ((15U << 16U) + 9U)
#define sfNFTokens ((15U << 16U) + 10U)
#define sfHooks ((15U << 16U) + 11U)
#define sfMajorities ((15U << 16U) + 16U)
#define sfDisabledValidators ((15U << 16U) + 17U)
#define sfHookExecutions ((15U << 16U) + 18U)
#define sfHookParameters ((15U << 16U) + 19U)
#define sfHookGrants ((15U << 16U) + 20U)
#define sfActiveValidators ((15U << 16U) + 95U)

View File

@@ -1,239 +0,0 @@
#include <stdint.h>
// 8 byte-int = 1 bytes
#define SFL_CLOSERESOLUTION 1
#define SFL_METHOD 1
#define SFL_TRANSACTIONRESULT 1
#define SFL_TICKSIZE 1
#define SFL_UNLMODIFYDISABLING 1
#define SFL_HOOKRESULT 1
// 16 byte-int = 2 bytes
#define SFL_LEDGERENTRYTYPE 2
#define SFL_TRANSACTIONTYPE 2
#define SFL_SIGNERWEIGHT 2
#define SFL_TRANSFERFEE 2
#define SFL_VERSION 2
#define SFL_HOOKSTATECHANGECOUNT 2
#define SFL_HOOKEMITCOUNT 2
#define SFL_HOOKEXECUTIONINDEX 2
#define SFL_HOOKAPIVERSION 2
// 32 byte-int = 4 bytes
#define SFL_NETWORKID 4
#define SFL_FLAGS 4
#define SFL_SOURCETAG 4
#define SFL_SEQUENCE 4
#define SFL_PREVIOUSTXNLGRSEQ 4
#define SFL_LEDGERSEQUENCE 4
#define SFL_CLOSETIME 4
#define SFL_PARENTCLOSETIME 4
#define SFL_SIGNINGTIME 4
#define SFL_EXPIRATION 4
#define SFL_TRANSFERRATE 4
#define SFL_WALLETSIZE 4
#define SFL_OWNERCOUNT 4
#define SFL_DESTINATIONTAG 4
#define SFL_HIGHQUALITYIN 4
#define SFL_HIGHQUALITYOUT 4
#define SFL_LOWQUALITYIN 4
#define SFL_LOWQUALITYOUT 4
#define SFL_QUALITYIN 4
#define SFL_QUALITYOUT 4
#define SFL_STAMPESCROW 4
#define SFL_BONDAMOUNT 4
#define SFL_LOADFEE 4
#define SFL_OFFERSEQUENCE 4
#define SFL_FIRSTLEDGERSEQUENCE 4
#define SFL_LASTLEDGERSEQUENCE 4
#define SFL_TRANSACTIONINDEX 4
#define SFL_OPERATIONLIMIT 4
#define SFL_REFERENCEFEEUNITS 4
#define SFL_RESERVEBASE 4
#define SFL_RESERVEINCREMENT 4
#define SFL_SETFLAG 4
#define SFL_CLEARFLAG 4
#define SFL_SIGNERQUORUM 4
#define SFL_CANCELAFTER 4
#define SFL_FINISHAFTER 4
#define SFL_SIGNERLISTID 4
#define SFL_SETTLEDELAY 4
#define SFL_TICKETCOUNT 4
#define SFL_TICKETSEQUENCE 4
#define SFL_NFTOKENTAXON 4
#define SFL_MINTEDNFTOKENS 4
#define SFL_BURNEDNFTOKENS 4
#define SFL_HOOKSTATECOUNT 4
#define SFL_EMITGENERATION 4
#define SFL_LOCKCOUNT 4
#define SFL_REWARDTIME 4
#define SFL_REWARDLGRFIRST 4
#define SFL_REWARDLGRLAST 4
#define SFL_FIRSTNFTOKENSEQUENCE 4
// 64 byte-int = 8 bytes
#define SFL_INDEX_NEXT 8
#define SFL_INDEX_PREVIOUS 8
#define SFL_BOOK_NODE 8
#define SFL_OWNER_NODE 8
#define SFL_BASE_FEE 8
#define SFL_EXCHANGE_RATE 8
#define SFL_LOW_NODE 8
#define SFL_HIGH_NODE 8
#define SFL_DESTINATION_NODE 8
#define SFL_COOKIE 8
#define SFL_SERVER_VERSION 8
#define SFL_EMIT_BURDEN 8
#define SFL_NFTOKEN_OFFER_NODE 8
#define SFL_HOOK_INSTRUCTION_COUNT 8
#define SFL_HOOK_RETURN_CODE 8
#define SFL_REFERENCE_COUNT 8
#define SFL_REWARD_ACCUMULATOR 8
// 128 byte-int = 4 bytes
#define SFL_EMAIL_HASH 128
// 160 byte-int = 4 bytes
#define SFL_TAKER_PAYS_CURRENCY 160
#define SFL_TAKER_PAYS_ISSUER 160
#define SFL_TAKER_GETS_CURRENCY 160
#define SFL_TAKER_GETS_ISSUER 160
// 256 byte-int = ??? bytes
#define SFL_LEDGER_HASH 256
#define SFL_PARENT_HASH 256
#define SFL_TRANSACTION_HASH 256
#define SFL_ACCOUNT_HASH 256
#define SFL_HOOK_ON 256
#define SFL_PREVIOUS_TXN_ID 256
#define SFL_LEDGER_INDEX 256
#define SFL_WALLET_LOCATOR 256
#define SFL_ROOT_INDEX 256
#define SFL_ACCOUNT_TXN_ID 256
#define SFL_NFTOKEN_ID 256
#define SFL_EMIT_PARENT_TXN_ID 256
#define SFL_EMIT_NONCE 256
#define SFL_EMIT_HOOK_HASH 256
// 256 byte-int = ??? bytes
#define SFL_BOOK_DIRECTORY 256
#define SFL_INVOICE_ID 256
#define SFL_NICKNAME 256
#define SFL_AMENDMENT 256
#define SFL_DIGEST 256
#define SFL_CHANNEL 256
#define SFL_CONSENSUS_HASH 256
#define SFL_CHECK_ID 256
#define SFL_VALIDATED_HASH 256
#define SFL_PREVIOUS_PAGE_MIN 256
#define SFL_NEXT_PAGE_MIN 256
#define SFL_NFTOKEN_BUY_OFFER 256
#define SFL_NFTOKEN_SELL_OFFER 256
#define SFL_HOOK_STATE_KEY 256
#define SFL_HOOK_HASH 256
#define SFL_HOOK_NAMESPACE 256
#define SFL_HOOK_SET_TXN_ID 256
#define SFL_OFFER_ID 256
#define SFL_ESCROW_ID 256
#define SFL_URITOKEN_ID 256
// 20 bytes
#define SFL_AMOUNT 20
#define SFL_BALANCE 20
#define SFL_LIMIT_AMOUNT 20
#define SFL_TAKER_PAYS 20
#define SFL_TAKER_GETS 20
#define SFL_LOW_LIMIT 20
#define SFL_HIGH_LIMIT 20
#define SFL_FEE 20
#define SFL_SEND_MAX 20
#define SFL_DELIVER_MIN 20
#define SFL_LOCKED_BALANCE 20
// Unimplemented
#define SFL_AMOUNT_MINIMUM_OFFER 8
#define SFL_AMOUNT_RIPPLE_ESCROW 8
#define SFL_AMOUNT_DELIVERED_AMOUNT 8
#define SFL_AMOUNT_NFTOKEN_BROKER_FEE 8
#define SFL_AMOUNT_HOOK_CALLBACK_FEE 8
#define SFL_AMOUNT_BASE_FEE_DROPS 8
#define SFL_AMOUNT_RESERVE_BASE_DROPS 8
#define SFL_AMOUNT_RESERVE_INCREMENT_DROPS 8
// Unimplemented
#define SFL_VL_PUBLIC_KEY 64
#define SFL_VL_MESSAGE_KEY 64
#define SFL_VL_SIGNING_PUB_KEY 64
// Unimplemented
#define SFL_VL_TXN_SIGNATURE 96
// Unimplemented
#define SFL_VL_URI 256
// Unimplemented
#define SFL_VL_SIGNATURE 96
// Unimplemented
#define SFL_VL_DOMAIN 256
#define SFL_VL_FUND_CODE 256
#define SFL_VL_REMOVE_CODE 256
#define SFL_VL_EXPIRE_CODE 256
#define SFL_VL_CREATE_CODE 256
#define SFL_VL_MEMO_TYPE 256
#define SFL_VL_MEMO_DATA 256
#define SFL_VL_MEMO_FORMAT 256
#define SFL_VL_FULFILLMENT 256
#define SFL_VL_CONDITION 256
// Unimplemented
#define SFL_VL_MASTER_SIGNATURE 96
// Unimplemented
#define SFL_VL_UNL_MODIFY_VALIDATOR 256
#define SFL_VL_VALIDATOR_TO_DISABLE 256
#define SFL_VL_VALIDATOR_TO_RE_ENABLE 256
#define SFL_VL_HOOK_STATE_DATA 256
#define SFL_VL_HOOK_RETURN_STRING 256
#define SFL_VL_HOOK_PARAMETER_NAME 256
#define SFL_VL_HOOK_PARAMETER_VALUE 256
#define SFL_VL_BLOB 256
// 20 bytes
#define SFL_ACCOUNT 20
#define SFL_OWNER 20
#define SFL_DESTINATION 20
#define SFL_ISSUER 20
#define SFL_AUTHORIZE 20
#define SFL_UNAUTHORIZE 20
#define SFL_REGULAR_KEY 20
#define SFL_NFTOKEN_MINTER 20
#define SFL_EMIT_CALLBACK 20
#define SFL_HOOK_ACCOUNT 20
#define SFL_NFTOKEN_MINTER 20
// Unimplemented
#define SFL_PATHS 1
// Unimplemented
#define SFL_VECTOR256_INDEXES 32
#define SFL_VECTOR256_HASHES 32
#define SFL_VECTOR256_AMENDMENTS 32
#define SFL_VECTOR256_NFTOKEN_OFFERS 32
#define SFL_VECTOR256_HOOK_NAMESPACES 32
// Unimplemented
#define SFL_TRANSACTION_META_DATA 1
#define SFL_CREATED_NODE 1
#define SFL_DELETED_NODE 1
#define SFL_MODIFIED_NODE 1
#define SFL_PREVIOUS_FIELDS 1
#define SFL_FINAL_FIELDS 1
#define SFL_NEW_FIELDS 1
#define SFL_TEMPLATE_ENTRY 1
#define SFL_MEMO 1
#define SFL_SIGNER_ENTRY 1
#define SFL_NFTOKEN 1
#define SFL_EMIT_DETAILS 1
#define SFL_HOOK 1
#define SFL_SIGNER 1
#define SFL_MAJORITY 1
#define SFL_DISABLED_VALIDATOR 1
#define SFL_EMITTED_TXN 1
#define SFL_HOOK_EXECUTION 1
#define SFL_HOOK_DEFINITION 1
#define SFL_HOOK_PARAMETER 1
#define SFL_HOOK_GRANT 1
#define SFL_SIGNERS 1
#define SFL_SIGNER_ENTRIES 1
#define SFL_TEMPLATE 1
#define SFL_NECESSARY 1
#define SFL_SUFFICIENT 1
#define SFL_AFFECTED_NODES 1
#define SFL_MEMOS 1
#define SFL_NFTOKENS 1
#define SFL_HOOKS 1
#define SFL_MAJORITIES 1
#define SFL_DISABLED_VALIDATORS 1
#define SFL_HOOK_EXECUTIONS 1
#define SFL_HOOK_EXECUTION 1

View File

@@ -1,9 +1,9 @@
all: reward govern mint
accept:
wasmcc accept.c -o accept.wasm -Oz -Wl,--allow-undefined -I./headers
wasmcc accept.c -o accept.wasm -Oz -Wl,--allow-undefined -I../
hook-cleaner accept.wasm
reward:
wasmcc reward.c -o reward.wasm -Oz -Wl,--allow-undefined -I./headers
wasmcc reward.c -o reward.wasm -Oz -Wl,--allow-undefined -I../
wasm-opt reward.wasm -o reward.wasm \
--shrink-level=100000000 \
--coalesce-locals-learning \
@@ -58,7 +58,7 @@ reward:
hook-cleaner reward.wasm
guard_checker reward.wasm
govern:
wasmcc govern.c -o govern.wasm -Oz -Wl,--allow-undefined -I./headers
wasmcc govern.c -o govern.wasm -Oz -Wl,--allow-undefined -I../
wasm-opt govern.wasm -o govern.wasm \
--shrink-level=100000000 \
--coalesce-locals-learning \
@@ -113,7 +113,7 @@ govern:
hook-cleaner govern.wasm
guard_checker govern.wasm
mint:
wasmcc mint.c -o mint.wasm -Oz -Wl,--allow-undefined -I./headers
wasmcc mint.c -o mint.wasm -Oz -Wl,--allow-undefined -I../
wasm-opt mint.wasm -o mint.wasm \
--shrink-level=100000000 \
--coalesce-locals-learning \
@@ -142,5 +142,5 @@ mint:
hook-cleaner mint.wasm
guard_checker mint.wasm
nftoken:
wasmcc nftoken.c -o nftoken.wasm -Oz -Wl,--allow-undefined -I./headers
wasmcc nftoken.c -o nftoken.wasm -Oz -Wl,--allow-undefined -I../
hook-cleaner nftoken.wasm

View File

@@ -49,7 +49,4 @@
#include "macro.h"
#include "tts.h"
#include "ls_flags.h"
#include "tx_flags.h"
#endif

View File

@@ -1,75 +0,0 @@
// Generated using generate_lsflags.sh
#ifndef HOOKLSFLAGS_INCLUDED
#define HOOKLSFLAGS_INCLUDED 1
enum ltACCOUNT_ROOT {
lsfPasswordSpent = 0x00010000,
lsfRequireDestTag = 0x00020000,
lsfRequireAuth = 0x00040000,
lsfDisallowXRP = 0x00080000,
lsfDisableMaster = 0x00100000,
lsfNoFreeze = 0x00200000,
lsfGlobalFreeze = 0x00400000,
lsfDefaultRipple = 0x00800000,
lsfDepositAuth = 0x01000000,
lsfTshCollect = 0x02000000,
lsfDisallowIncomingNFTokenOffer = 0x04000000,
lsfDisallowIncomingCheck = 0x08000000,
lsfDisallowIncomingPayChan = 0x10000000,
lsfDisallowIncomingTrustline = 0x20000000,
lsfURITokenIssuer = 0x40000000,
lsfDisallowIncomingRemit = 0x80000000,
lsfAllowTrustLineClawback = 0x00001000,
};
enum ltOFFER {
lsfPassive = 0x00010000,
lsfSell = 0x00020000,
};
enum ltRIPPLE_STATE {
lsfLowReserve = 0x00010000,
lsfHighReserve = 0x00020000,
lsfLowAuth = 0x00040000,
lsfHighAuth = 0x00080000,
lsfLowNoRipple = 0x00100000,
lsfHighNoRipple = 0x00200000,
lsfLowFreeze = 0x00400000,
lsfHighFreeze = 0x00800000,
lsfLowDeepFreeze = 0x02000000,
lsfHighDeepFreeze = 0x04000000,
lsfAMMNode = 0x01000000,
};
enum ltSIGNER_LIST {
lsfOneOwnerCount = 0x00010000,
};
enum ltDIR_NODE {
lsfNFTokenBuyOffers = 0x00000001,
lsfNFTokenSellOffers = 0x00000002,
lsfEmittedDir = 0x00000004,
};
enum ltNFTOKEN_OFFER {
lsfSellNFToken = 0x00000001,
};
enum ltURI_TOKEN {
lsfBurnable = 0x00000001,
};
enum remarks {
lsfImmutable = 1,
};
enum ltMPTOKEN_ISSUANCE {
lsfMPTLocked = 0x00000001,
lsfMPTCanLock = 0x00000002,
lsfMPTRequireAuth = 0x00000004,
lsfMPTCanEscrow = 0x00000008,
lsfMPTCanTrade = 0x00000010,
lsfMPTCanTransfer = 0x00000020,
lsfMPTCanClawback = 0x00000040,
};
enum ltMPTOKEN {
lsfMPTAuthorized = 0x00000002,
};
enum ltCREDENTIAL {
lsfAccepted = 0x00010000,
};
#endif // HOOKLSFLAGS_INCLUDED

View File

@@ -152,13 +152,11 @@
#define sfEscrowID ((5U << 16U) + 35U)
#define sfURITokenID ((5U << 16U) + 36U)
#define sfDomainID ((5U << 16U) + 37U)
#define sfHookOnOutgoing ((5U << 16U) + 93U)
#define sfHookOnIncoming ((5U << 16U) + 94U)
#define sfCron ((5U << 16U) + 95U)
#define sfHookCanEmit ((5U << 16U) + 96U)
#define sfEmittedTxnID ((5U << 16U) + 97U)
#define sfGovernanceMarks ((5U << 16U) + 98U)
#define sfGovernanceFlags ((5U << 16U) + 99U)
#define sfGovernanceMarks ((5U << 16U) + 98U)
#define sfEmittedTxnID ((5U << 16U) + 97U)
#define sfHookCanEmit ((5U << 16U) + 96U)
#define sfCron ((5U << 16U) + 95U)
#define sfNumber ((9U << 16U) + 1U)
#define sfAmount ((6U << 16U) + 1U)
#define sfBalance ((6U << 16U) + 2U)
@@ -189,7 +187,6 @@
#define sfSignatureReward ((6U << 16U) + 29U)
#define sfMinAccountCreateAmount ((6U << 16U) + 30U)
#define sfLPTokenBalance ((6U << 16U) + 31U)
#define sfTrustLineRewardAccumulator ((6U << 16U) + 99U)
#define sfPublicKey ((7U << 16U) + 1U)
#define sfMessageKey ((7U << 16U) + 2U)
#define sfSigningPubKey ((7U << 16U) + 3U)
@@ -221,7 +218,6 @@
#define sfProvider ((7U << 16U) + 30U)
#define sfMPTokenMetadata ((7U << 16U) + 31U)
#define sfCredentialType ((7U << 16U) + 32U)
#define sfHookName ((7U << 16U) + 97U)
#define sfRemarkValue ((7U << 16U) + 98U)
#define sfRemarkName ((7U << 16U) + 99U)
#define sfAccount ((8U << 16U) + 1U)
@@ -257,7 +253,6 @@
#define sfIssuingChainIssue ((24U << 16U) + 2U)
#define sfAsset ((24U << 16U) + 3U)
#define sfAsset2 ((24U << 16U) + 4U)
#define sfClaimCurrency ((24U << 16U) + 5U)
#define sfXChainBridge ((25U << 16U) + 1U)
#define sfTransactionMetaData ((14U << 16U) + 2U)
#define sfCreatedNode ((14U << 16U) + 3U)
@@ -277,6 +272,7 @@
#define sfDisabledValidator ((14U << 16U) + 19U)
#define sfEmittedTxn ((14U << 16U) + 20U)
#define sfHookExecution ((14U << 16U) + 21U)
#define sfHookDefinition ((14U << 16U) + 22U)
#define sfHookParameter ((14U << 16U) + 23U)
#define sfHookGrant ((14U << 16U) + 24U)
#define sfVoteEntry ((14U << 16U) + 25U)
@@ -295,8 +291,6 @@
#define sfActiveValidator ((14U << 16U) + 95U)
#define sfGenesisMint ((14U << 16U) + 96U)
#define sfRemark ((14U << 16U) + 97U)
#define sfHighReward ((14U << 16U) + 98U)
#define sfLowReward ((14U << 16U) + 99U)
#define sfSigners ((15U << 16U) + 3U)
#define sfSignerEntries ((15U << 16U) + 4U)
#define sfTemplate ((15U << 16U) + 5U)
@@ -319,9 +313,9 @@
#define sfAuthorizeCredentials ((15U << 16U) + 26U)
#define sfUnauthorizeCredentials ((15U << 16U) + 27U)
#define sfAcceptedCredentials ((15U << 16U) + 28U)
#define sfAmounts ((15U << 16U) + 92U)
#define sfHookEmissions ((15U << 16U) + 93U)
#define sfImportVLKeys ((15U << 16U) + 94U)
#define sfActiveValidators ((15U << 16U) + 95U)
#define sfGenesisMints ((15U << 16U) + 96U)
#define sfRemarks ((15U << 16U) + 97U)
#define sfGenesisMints ((15U << 16U) + 96U)
#define sfActiveValidators ((15U << 16U) + 95U)
#define sfImportVLKeys ((15U << 16U) + 94U)
#define sfHookEmissions ((15U << 16U) + 93U)
#define sfAmounts ((15U << 16U) + 92U)

View File

@@ -1,117 +0,0 @@
// Generated using generate_txflags.sh
#include "ls_flags.h"
#include <stdint.h>
enum UniversalFlags : uint32_t {
tfFullyCanonicalSig = 0x80000000,
};
enum AccountSetFlags : uint32_t {
tfRequireDestTag = 0x00010000,
tfOptionalDestTag = 0x00020000,
tfRequireAuth = 0x00040000,
tfOptionalAuth = 0x00080000,
tfDisallowXRP = 0x00100000,
tfAllowXRP = 0x00200000,
};
enum AccountFlags : uint32_t {
asfRequireDest = 1,
asfRequireAuth = 2,
asfDisallowXRP = 3,
asfDisableMaster = 4,
asfAccountTxnID = 5,
asfNoFreeze = 6,
asfGlobalFreeze = 7,
asfDefaultRipple = 8,
asfDepositAuth = 9,
asfAuthorizedNFTokenMinter = 10,
asfTshCollect = 11,
asfDisallowIncomingNFTokenOffer = 12,
asfDisallowIncomingCheck = 13,
asfDisallowIncomingPayChan = 14,
asfDisallowIncomingTrustline = 15,
asfDisallowIncomingRemit = 16,
asfAllowTrustLineClawback = 17,
};
enum OfferCreateFlags : uint32_t {
tfPassive = 0x00010000,
tfImmediateOrCancel = 0x00020000,
tfFillOrKill = 0x00040000,
tfSell = 0x00080000,
};
enum PaymentFlags : uint32_t {
tfNoRippleDirect = 0x00010000,
tfPartialPayment = 0x00020000,
tfLimitQuality = 0x00040000,
};
enum TrustSetFlags : uint32_t {
tfSetfAuth = 0x00010000,
tfSetNoRipple = 0x00020000,
tfClearNoRipple = 0x00040000,
tfSetFreeze = 0x00100000,
tfClearFreeze = 0x00200000,
tfSetDeepFreeze = 0x00400000,
tfClearDeepFreeze = 0x00800000
};
enum EnableAmendmentFlags : uint32_t {
tfGotMajority = 0x00010000,
tfLostMajority = 0x00020000,
tfTestSuite = 0x80000000,
};
enum PaymentChannelClaimFlags : uint32_t {
tfRenew = 0x00010000,
tfClose = 0x00020000,
};
enum NFTokenMintFlags : uint32_t {
tfBurnable = 0x00000001,
tfOnlyXRP = 0x00000002,
tfTrustLine = 0x00000004,
tfTransferable = 0x00000008,
tfMutable = 0x00000010,
tfStrongTSH = 0x00008000,
};
enum MPTokenIssuanceCreateFlags : uint32_t {
tfMPTCanLock = lsfMPTCanLock,
tfMPTRequireAuth = lsfMPTRequireAuth,
tfMPTCanEscrow = lsfMPTCanEscrow,
tfMPTCanTrade = lsfMPTCanTrade,
tfMPTCanTransfer = lsfMPTCanTransfer,
tfMPTCanClawback = lsfMPTCanClawback,
};
enum MPTokenAuthorizeFlags : uint32_t {
tfMPTUnauthorize = 0x00000001,
};
enum MPTokenIssuanceSetFlags : uint32_t {
tfMPTLock = 0x00000001,
tfMPTUnlock = 0x00000002,
};
enum NFTokenCreateOfferFlags : uint32_t {
tfSellNFToken = 0x00000001,
};
enum ClaimRewardFlags : uint32_t {
tfOptOut = 0x00000001,
};
enum CronSetFlags : uint32_t {
tfCronUnset = 0x00000001,
};
enum AMMClawbackFlags : uint32_t {
tfClawTwoAssets = 0x00000001,
};
enum BridgeModifyFlags : uint32_t {
tfClearAccountCreateAmount = 0x00010000,
};

View File

@@ -138,14 +138,14 @@ public:
template <typename U>
requires std::convertible_to<U, T>
constexpr Expected(U&& r)
: Base(boost::outcome_v2::in_place_type_t<T>{}, std::forward<U>(r))
: Base(boost::outcome_v2::success(T(std::forward<U>(r))))
{
}
template <typename U>
requires std::convertible_to<U, E> && (!std::is_reference_v<U>)
constexpr Expected(Unexpected<U> e)
: Base(boost::outcome_v2::in_place_type_t<E>{}, std::move(e.value()))
: Base(boost::outcome_v2::failure(E(std::move(e.value()))))
{
}

View File

@@ -25,7 +25,6 @@
#include <boost/beast/core/string.hpp>
#include <boost/filesystem.hpp>
#include <fstream>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
@@ -166,8 +165,6 @@ private:
beast::severities::Severity thresh_;
File file_;
bool silent_ = false;
using Transform = std::function<std::string(std::string const&)>;
Transform transform_;
public:
Logs(beast::severities::Severity level);
@@ -206,28 +203,6 @@ public:
std::string const& text,
bool console);
/** Rewrite test log lines. Not synchronized.
*
* Test-only. Installed once for the life of Logs. Empty is a null check.
*/
void
setTransform(Transform fn)
{
transform_ = std::move(fn);
}
bool
hasTransform() const
{
return static_cast<bool>(transform_);
}
std::string
applyTransform(std::string const& text) const
{
return transform_ ? transform_(text) : text;
}
std::string
rotate();

View File

@@ -14,9 +14,7 @@
// Override uint256, Feature and Rules for guard checker build
#define uint256 std::string
#define featureHooksUpdate1 "1"
#define featureHooksUpdate2 "1"
#define fix20250131 "1"
#define fixGuardDepth32 "1"
namespace hook_api {
struct Rules
{
@@ -320,7 +318,7 @@ namespace compare_mode {
enum compare_mode : uint32_t { EQUAL = 1, LESS = 2, GREATER = 4 };
}
enum class hook_return_code : int64_t {
enum hook_return_code : int64_t {
SUCCESS =
0, // return codes > 0 are reserved for hook apis to return "success"
OUT_OF_BOUNDS =
@@ -387,7 +385,7 @@ enum class hook_return_code : int64_t {
TOO_MANY_NAMESPACES = -45
};
enum class ExitType : uint8_t {
enum ExitType : uint8_t {
UNSET = 0,
WASM_ERROR = 1,
ROLLBACK = 2,
@@ -444,7 +442,6 @@ getImportWhitelist(Rules const& rules)
enum GuardRulesVersion : uint64_t {
GuardRuleFix20250131 = 0x00000001,
GuardRuleDepth32 = 0x00000002,
};
inline uint64_t
@@ -453,8 +450,6 @@ getGuardRulesVersion(Rules const& rules)
uint64_t version = 0;
if (rules.enabled(fix20250131))
version |= GuardRuleFix20250131;
if (rules.enabled(fixGuardDepth32))
version |= GuardRuleDepth32;
return version;
}

View File

@@ -204,13 +204,9 @@ struct WasmBlkInf
}
// compute worst case execution time
inline uint64_t
compute_wce(
const WasmBlkInf* blk,
int level,
int max_level,
bool* recursion_limit_reached)
compute_wce(const WasmBlkInf* blk, int level, bool* recursion_limit_reached)
{
if (level > max_level)
if (level > 16)
{
*recursion_limit_reached = true;
return 0;
@@ -237,8 +233,8 @@ compute_wce(
if (blk->children.size() > 0)
for (auto const& child : blk->children)
worst_case_execution += compute_wce(
child, level + 1, max_level, recursion_limit_reached);
worst_case_execution +=
compute_wce(child, level + 1, recursion_limit_reached);
if (parent == 0 ||
parent->iteration_bound ==
@@ -792,17 +788,12 @@ check_guard(
}
bool recursion_limit_reached = false;
int max_level = 16;
if (rulesVersion & hook_api::GuardRuleDepth32)
max_level = 32;
uint64_t wce =
compute_wce(&(*root), 0, max_level, &recursion_limit_reached);
uint64_t wce = compute_wce(&(*root), 0, &recursion_limit_reached);
if (recursion_limit_reached)
{
GUARDLOG(hook::log::NESTING_LIMIT)
<< "GuardCheck "
<< "Maximum allowable depth of blocks reached (" << max_level
<< " levels). Flatten "
<< "Maximum allowable depth of blocks reached (16 levels). Flatten "
"your loops and conditions!.\n";
return {};
}

View File

@@ -3,297 +3,10 @@
#include <xrpld/app/misc/Transaction.h>
#include <xrpl/hook/Enum.h>
#include <cfenv>
namespace hook {
using HookReturnCode = hook_api::hook_return_code;
namespace hook_float {
using enum hook_api::hook_return_code;
// power of 10 LUT for fast integer math
static int64_t power_of_ten[19] = {
1LL,
10LL,
100LL,
1000LL,
10000LL,
100000LL,
1000000LL,
10000000LL,
100000000LL,
1000000000LL,
10000000000LL,
100000000000LL,
1000000000000LL,
10000000000000LL,
100000000000000LL,
1000000000000000LL, // 15
10000000000000000LL,
100000000000000000LL,
1000000000000000000LL,
};
using namespace hook_api;
static int64_t const minMantissa = 1000000000000000ull;
static int64_t const maxMantissa = 9999999999999999ull;
static int32_t const minExponent = -96;
static int32_t const maxExponent = 80;
inline Expected<int32_t, HookReturnCode>
get_exponent(int64_t float1)
{
using enum hook_api::hook_return_code;
if (float1 < 0)
return Unexpected(INVALID_FLOAT);
if (float1 == 0)
return 0u;
uint64_t float_in = (uint64_t)float1;
float_in >>= 54U;
float_in &= 0xFFU;
return static_cast<int32_t>(float_in) - 97;
}
inline Expected<uint64_t, HookReturnCode>
get_mantissa(int64_t float1)
{
using enum hook_api::hook_return_code;
if (float1 < 0)
return Unexpected(INVALID_FLOAT);
if (float1 == 0)
return 0ULL;
float1 -= ((((uint64_t)float1) >> 54U) << 54U);
return float1;
}
inline bool
is_negative(int64_t float1)
{
return ((float1 >> 62U) & 1ULL) == 0;
}
inline int64_t
invert_sign(int64_t float1)
{
int64_t r = (int64_t)(((uint64_t)float1) ^ (1ULL << 62U));
return r;
}
inline int64_t
set_sign(int64_t float1, bool set_negative)
{
bool neg = is_negative(float1);
if ((neg && set_negative) || (!neg && !set_negative))
return float1;
return invert_sign(float1);
}
inline Expected<uint64_t, HookReturnCode>
set_mantissa(int64_t float1, uint64_t mantissa)
{
using enum hook_api::hook_return_code;
if (mantissa > maxMantissa)
return Unexpected(MANTISSA_OVERSIZED);
if (mantissa < minMantissa)
return Unexpected(MANTISSA_UNDERSIZED);
return float1 - get_mantissa(float1).value() + mantissa;
}
inline Expected<uint64_t, HookReturnCode>
set_exponent(int64_t float1, int32_t exponent)
{
using enum hook_api::hook_return_code;
if (exponent > maxExponent)
return Unexpected(EXPONENT_OVERSIZED);
if (exponent < minExponent)
return Unexpected(EXPONENT_UNDERSIZED);
uint64_t exp = (exponent + 97);
exp <<= 54U;
float1 &= ~(0xFFLL << 54);
float1 += (int64_t)exp;
return float1;
}
inline Expected<uint64_t, HookReturnCode>
make_float(ripple::IOUAmount& amt)
{
using enum hook_api::hook_return_code;
int64_t man_out = amt.mantissa();
int64_t float_out = 0;
bool neg = man_out < 0;
if (neg)
man_out *= -1;
float_out = set_sign(float_out, neg);
auto const mantissa = set_mantissa(float_out, (uint64_t)man_out);
if (!mantissa)
// TODO: This change requires the amendment.
// return Unexpected(mantissa.error());
float_out = (int64_t)mantissa.error();
else
float_out = mantissa.value();
auto const exponent = set_exponent(float_out, amt.exponent());
if (!exponent)
return Unexpected(exponent.error());
float_out = exponent.value();
return float_out;
}
inline Expected<uint64_t, HookReturnCode>
make_float(uint64_t mantissa, int32_t exponent, bool neg)
{
using enum hook_api::hook_return_code;
if (mantissa == 0)
return 0ULL;
if (mantissa > maxMantissa)
return Unexpected(MANTISSA_OVERSIZED);
if (mantissa < minMantissa)
return Unexpected(MANTISSA_UNDERSIZED);
if (exponent > maxExponent)
return Unexpected(EXPONENT_OVERSIZED);
if (exponent < minExponent)
return Unexpected(EXPONENT_UNDERSIZED);
int64_t out = 0;
auto const m = set_mantissa(out, mantissa);
if (!m)
return Unexpected(m.error()); // LCOV_EXCL_LINE
out = m.value();
auto const e = set_exponent(out, exponent);
if (!e)
return Unexpected(e.error()); // LCOV_EXCL_LINE
out = e.value();
out = set_sign(out, neg);
return out;
}
/**
* This function normalizes the mantissa and exponent passed, if it can.
* It returns the XFL and mutates the supplied manitssa and exponent.
* If a negative mantissa is provided then the returned XFL has the negative
* flag set. If there is an overflow error return XFL_OVERFLOW. On underflow
* returns canonical 0
*/
template <typename T>
inline Expected<uint64_t, HookReturnCode>
normalize_xfl(T& man, int32_t& exp, bool neg = false)
{
if (man == 0)
return 0ULL;
if (man == std::numeric_limits<int64_t>::min())
man++;
constexpr bool sman = std::is_same<T, int64_t>::value;
static_assert(sman || std::is_same<T, uint64_t>());
if constexpr (sman)
{
if (man < 0)
{
man *= -1LL;
neg = true;
}
}
// mantissa order
std::feclearexcept(FE_ALL_EXCEPT);
int32_t mo = log10(man);
// defensively ensure log10 produces a sane result; we'll borrow the
// overflow error code if it didn't
if (std::fetestexcept(FE_INVALID))
return Unexpected(XFL_OVERFLOW); // LCOV_EXCL_LINE
int32_t adjust = 15 - mo;
if (adjust > 0)
{
// defensive check
if (adjust > 18)
return 0ULL; // LCOV_EXCL_LINE
man *= power_of_ten[adjust];
exp -= adjust;
}
else if (adjust < 0)
{
// defensive check
if (-adjust > 18)
return Unexpected(XFL_OVERFLOW); // LCOV_EXCL_LINE
man /= power_of_ten[-adjust];
exp -= adjust;
}
if (man == 0)
{
exp = 0;
return 0ULL;
}
// even after adjustment the mantissa can be outside the range by one place
// improving the math above would probably alleviate the need for these
// branches
if (man < minMantissa)
{
if (man == minMantissa - 1LL)
man += 1LL;
else
{
man *= 10LL;
exp--;
}
}
if (man > maxMantissa)
{
if (man == maxMantissa + 1LL)
man -= 1LL;
else
{
man /= 10LL;
exp++;
}
}
if (exp < minExponent)
{
man = 0;
exp = 0;
return 0ULL;
}
if (man == 0)
{
exp = 0;
return 0ULL;
}
if (exp > maxExponent)
return Unexpected(XFL_OVERFLOW);
auto const ret = make_float((uint64_t)man, exp, neg);
if constexpr (sman)
{
if (neg)
man *= -1LL;
}
if (!ret)
return Unexpected(ret.error());
return ret;
}
const int64_t float_one_internal =
make_float(1000000000000000ull, -15, false).value();
} // namespace hook_float
using namespace ripple;
using HookReturnCode = hook_api::hook_return_code;
using Bytes = std::vector<std::uint8_t>;
@@ -345,9 +58,6 @@ public:
// sto_erase(): same as sto_emplace with field_object = nullopt
/// etxn APIs
Expected<Bytes, HookReturnCode>
prepare(Slice const& txBlob) const;
Expected<std::shared_ptr<Transaction>, HookReturnCode>
emit(Slice const& txBlob) const;
@@ -457,7 +167,7 @@ public:
Expected<ripple::uint256, HookReturnCode>
hook_hash(int32_t hook_no) const;
Expected<uint64_t, HookReturnCode>
Expected<int64_t, HookReturnCode>
hook_again() const;
Expected<Blob, HookReturnCode>
@@ -607,7 +317,7 @@ private:
bool modified) const;
// these are only used by get_stobject_length below
enum class STOParseErrorCode {
enum parse_error {
pe_unexpected_end = -1,
pe_unknown_type_early = -2, // detected early
pe_unknown_type_late = -3, // end of function
@@ -616,8 +326,8 @@ private:
};
inline Expected<
uint32_t,
STOParseErrorCode>
int32_t,
parse_error>
get_stobject_length(
unsigned char* start, // in - begin iterator
unsigned char* maxptr, // in - end iterator

View File

@@ -1,102 +0,0 @@
//------------------------------------------------------------------------------
/*
Canonical Hook artifact classification and QuickJS deployment envelope.
Legacy C Hooks remain raw WebAssembly. QuickJS bytecode is never deployed
raw: it is carried in a fixed-width, big-endian XQJS envelope whose exact
bytes participate in HookHash.
*/
//==============================================================================
#ifndef XRPL_HOOK_HOOKARTIFACT_H_INCLUDED
#define XRPL_HOOK_HOOKARTIFACT_H_INCLUDED
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/Slice.h>
#include <array>
#include <cstddef>
#include <cstdint>
#include <string_view>
namespace hook::artifact {
inline constexpr std::size_t identitySize = 32;
inline constexpr std::size_t quickJSHeaderSize = 80;
inline constexpr std::size_t maxCreateCodeSize = 65'535;
inline constexpr std::array<std::uint8_t, 4> quickJSMagic = {
'X',
'Q',
'J',
'S'};
inline constexpr std::uint8_t quickJSEnvelopeVersion = 1;
inline constexpr std::uint8_t quickJSBytecodeKind = 1;
using Identity = std::array<std::uint8_t, identitySize>;
enum class Kind : std::uint8_t {
legacyWasm,
quickJSBytecode,
};
enum class Error : std::uint8_t {
tooLarge,
tooShort,
unknownMagic,
truncatedQuickJSHeader,
unsupportedEnvelopeVersion,
unsupportedArtifactKind,
nonCanonicalHeaderSize,
nonZeroReserved,
emptyPayload,
lengthMismatch,
zeroBytecodeABI,
zeroRuntimeProfile,
};
struct View
{
Kind kind;
std::uint16_t hookApiVersion;
Identity bytecodeABI;
Identity runtimeProfile;
ripple::Slice payload;
};
/** Parse either a legacy raw-Wasm Hook or a canonical QuickJS artifact.
The returned slices retain no ownership and must not outlive `code`.
*/
ripple::Expected<View, Error>
parse(ripple::Slice code) noexcept;
std::string_view
toString(Error error) noexcept;
extern Identity const quickJSBytecodeABI;
extern Identity const quickJSRuntimeProfile;
extern Identity const quickJSProviderSHA256;
extern std::size_t const quickJSProviderSize;
extern std::uint16_t const quickJSHookApiVersion;
extern std::uint64_t const quickJSInitializationFuel;
extern std::uint64_t const quickJSInvocationFuel;
extern std::string_view const quickJSHostWorkMeter;
extern std::uint64_t const quickJSHostWorkBudget;
extern std::uint64_t const quickJSHostWorkBasePerCall;
extern std::uint64_t const quickJSHostWorkPerAddressedByte;
extern std::string_view const quickJSHostAdapterPolicy;
extern std::uint32_t const quickJSHeapBytes;
extern std::uint32_t const quickJSStackBytes;
extern std::uint32_t const quickJSSerializedObjectMaxBytes;
extern std::uint32_t const quickJSSerializedObjectMaxFields;
extern std::uint32_t const quickJSSerializedObjectMaxScopes;
extern std::uint32_t const quickJSSerializedObjectMaxDepth;
extern std::uint32_t const quickJSProviderMemoryMinimumPages;
extern std::uint32_t const quickJSProviderMemoryMaximumPages;
extern std::uint32_t const quickJSProviderWasmStackBytes;
bool
isCurrentQuickJS(View const& artifact) noexcept;
} // namespace hook::artifact
#endif // XRPL_HOOK_HOOKARTIFACT_H_INCLUDED

View File

@@ -89,7 +89,73 @@
#define WASM_VAL_TYPE(T, b) CAT2(TYP_, T)
#define UNSIGNED_TYPE(T) std::make_unsigned_t<T>
#define DECLARE_HOOK_FUNCTION(R, F, ...) \
R F(hook::HookContext& hookCtx, \
WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \
COMMA __VA_ARGS__)); \
extern WasmEdge_Result WasmFunction##F( \
void* data_ptr, \
const WasmEdge_CallingFrameContext* frameCtx, \
const WasmEdge_Value* in, \
WasmEdge_Value* out); \
extern WasmEdge_ValType WasmFunctionParams##F[]; \
extern WasmEdge_ValType WasmFunctionResult##F[]; \
extern WasmEdge_FunctionTypeContext* WasmFunctionType##F; \
extern WasmEdge_String WasmFunctionName##F;
#define DEFINE_HOOK_FUNCTION(R, F, ...) \
WasmEdge_Result hook_api::WasmFunction##F( \
void* data_ptr, \
const WasmEdge_CallingFrameContext* frameCtx, \
const WasmEdge_Value* in, \
WasmEdge_Value* out) \
{ \
__VA_OPT__(int _stack = 0;) \
__VA_OPT__(FOR_VARS(VAR_ASSIGN, 2, __VA_ARGS__);) \
hook::HookContext* hookCtx = \
reinterpret_cast<hook::HookContext*>(data_ptr); \
R return_code = hook_api::F( \
*hookCtx, \
*const_cast<WasmEdge_CallingFrameContext*>(frameCtx) \
__VA_OPT__(COMMA STRIP_TYPES(__VA_ARGS__))); \
if (return_code == RC_ROLLBACK || return_code == RC_ACCEPT) \
return WasmEdge_Result_Terminate; \
out[0] = RET_ASSIGN(R, return_code); \
return WasmEdge_Result_Success; \
}; \
WasmEdge_ValType hook_api::WasmFunctionParams##F[] = { \
__VA_OPT__(FOR_VARS(WASM_VAL_TYPE, 0, __VA_ARGS__))}; \
WasmEdge_ValType hook_api::WasmFunctionResult##F[1] = { \
WASM_VAL_TYPE(R, dummy)}; \
WasmEdge_FunctionTypeContext* hook_api::WasmFunctionType##F = \
WasmEdge_FunctionTypeCreate( \
WasmFunctionParams##F, \
VA_NARGS(NULL __VA_OPT__(, __VA_ARGS__)), \
WasmFunctionResult##F, \
1); \
WasmEdge_String hook_api::WasmFunctionName##F = \
WasmEdge_StringCreateByCString(#F); \
R hook_api::F( \
hook::HookContext& hookCtx, \
WasmEdge_CallingFrameContext const& frameCtx __VA_OPT__( \
COMMA __VA_ARGS__))
#define HOOK_SETUP() \
try \
{ \
[[maybe_unused]] ApplyContext& applyCtx = hookCtx.applyCtx; \
[[maybe_unused]] auto& view = applyCtx.view(); \
[[maybe_unused]] auto j = applyCtx.app.journal("View"); \
[[maybe_unused]] WasmEdge_MemoryInstanceContext* memoryCtx = \
WasmEdge_CallingFrameGetMemoryInstance(&frameCtx, 0); \
[[maybe_unused]] unsigned char* memory = \
WasmEdge_MemoryInstanceGetPointer(memoryCtx, 0, 0); \
[[maybe_unused]] const uint64_t memory_length = \
WasmEdge_MemoryInstanceGetPageSize(memoryCtx) * \
WasmEdge_kPageSize; \
[[maybe_unused]] auto& api = hookCtx.api(); \
if (!memoryCtx || !memory || !memory_length) \
return INTERNAL_ERROR;
#define HOOK_TEARDOWN() \
} \
@@ -101,6 +167,54 @@
return INTERNAL_ERROR; \
}
#define WRITE_WASM_MEMORY( \
bytes_written, \
guest_dst_ptr, \
guest_dst_len, \
host_src_ptr, \
host_src_len, \
host_memory_ptr, \
guest_memory_length) \
{ \
int64_t bytes_to_write = std::min( \
static_cast<int64_t>(host_src_len), \
static_cast<int64_t>(guest_dst_len)); \
if (guest_dst_ptr + bytes_to_write > guest_memory_length) \
{ \
JLOG(j.warn()) << "HookError[" << HC_ACC() << "]: " << __func__ \
<< " tried to retreive blob of " << host_src_len \
<< " bytes past end of wasm memory"; \
return OUT_OF_BOUNDS; \
} \
if (!WasmEdge_ResultOK(WasmEdge_MemoryInstanceSetData( \
memoryCtx, \
reinterpret_cast<const uint8_t*>(host_src_ptr), \
guest_dst_ptr, \
bytes_to_write))) \
return INTERNAL_ERROR; \
bytes_written += bytes_to_write; \
}
#define WRITE_WASM_MEMORY_AND_RETURN( \
guest_dst_ptr, \
guest_dst_len, \
host_src_ptr, \
host_src_len, \
host_memory_ptr, \
guest_memory_length) \
{ \
int64_t bytes_written = 0; \
WRITE_WASM_MEMORY( \
bytes_written, \
guest_dst_ptr, \
guest_dst_len, \
host_src_ptr, \
host_src_len, \
host_memory_ptr, \
guest_memory_length); \
return bytes_written; \
}
// ptr = pointer inside the wasm memory space
#define NOT_IN_BOUNDS(ptr, len, memory_length) \
((static_cast<uint64_t>(ptr) >= static_cast<uint64_t>(memory_length)) || \
@@ -158,7 +272,7 @@
data_ptr < (data_ptr_in)) \
return INTERNAL_ERROR; \
if (data_len == 0) \
return 0ULL; \
return 0; \
if ((write_ptr_in) == 0) \
return data_as_int64(data_ptr, data_len); \
if (data_len > (write_len_in)) \

View File

@@ -367,8 +367,3 @@ HOOK_API_DEFINITION(
HOOK_API_DEFINITION(
int64_t, xpop_slot, (uint32_t, uint32_t),
featureHooksUpdate1)
// int64_t prepare(uint32_t write_ptr, uint32_t write_len, uint32_t read_ptr, uint32_t read_len);
HOOK_API_DEFINITION(
int64_t, prepare, (uint32_t, uint32_t, uint32_t, uint32_t),
featureHooksUpdate2)

File diff suppressed because it is too large Load Diff

View File

@@ -33,39 +33,35 @@
*
* Steps required to add new features to the code:
*
* 1) Add the appropriate XRPL_FEATURE or XRPL_FIX macro definition for the
* feature to features.macro with the feature's name, `Supported::no`, and
* `VoteBehavior::DefaultNo`.
*
* 2) Use the generated variable name as the parameter to `view.rules.enabled()`
* to control flow into new code that this feature limits. (featureName or
* fixName)
*
* 3) If the feature development is COMPLETE, and the feature is ready to be
* SUPPORTED, change the macro parameter in features.macro to Supported::yes.
*
* 4) In general, any newly supported amendments (`Supported::yes`) should have
* a `VoteBehavior::DefaultNo` indefinitely so that external governance can
* make the decision on when to activate it. High priority bug fixes can be
* an exception to this rule. In such cases, ensure the fix has been
* clearly communicated to the community using appropriate channels,
* then change the macro parameter in features.macro to
* `VoteBehavior::DefaultYes`. The communication process is beyond
* the scope of these instructions.
*
* 1) In this file, increment `numFeatures` and add a uint256 declaration
* for the feature at the bottom
* 2) Add a uint256 definition for the feature to the corresponding source
* file (Feature.cpp). Use `registerFeature` to create the feature with
* the feature's name, `Supported::no`, and `VoteBehavior::DefaultNo`. This
* should be the only place the feature's name appears in code as a string.
* 3) Use the uint256 as the parameter to `view.rules.enabled()` to
* control flow into new code that this feature limits.
* 4) If the feature development is COMPLETE, and the feature is ready to be
* SUPPORTED, change the `registerFeature` parameter to Supported::yes.
* 5) When the feature is ready to be ENABLED, change the `registerFeature`
* parameter to `VoteBehavior::DefaultYes`.
* In general, any newly supported amendments (`Supported::yes`) should have
* a `VoteBehavior::DefaultNo` for at least one full release cycle. High
* priority bug fixes can be an exception to this rule of thumb.
*
* When a feature has been enabled for several years, the conditional code
* may be removed, and the feature "retired". To retire a feature:
*
* 1) MOVE the macro definition in features.macro to the "retired features"
* section at the end of the file, and change the macro to XRPL_RETIRE.
*
* 1) Remove the uint256 declaration from this file.
* 2) MOVE the uint256 definition in Feature.cpp to the "retired features"
* section at the end of the file.
* 3) CHANGE the name of the variable to start with "retired".
* 4) CHANGE the parameters of the `registerFeature` call to `Supported::yes`
* and `VoteBehavior::DefaultNo`.
* The feature must remain registered and supported indefinitely because it
* may exist in the Amendments object on ledger. There is no need to vote
* for it because there's nothing to vote for. If the feature definition is
* removed completely from the code, any instances running that code will get
* amendment blocked. Removing the feature from the ledger is beyond the scope
* of these instructions.
* still exists in the ledger, but there is no need to vote for it because
* there's nothing to vote for. If it is removed completely from the code, any
* instances running that code will get amendment blocked. Removing the
* feature from the ledger is beyond the scope of these instructions.
*
*/
@@ -80,32 +76,11 @@ allAmendments();
namespace detail {
#pragma push_macro("XRPL_FEATURE")
#undef XRPL_FEATURE
#pragma push_macro("XRPL_FIX")
#undef XRPL_FIX
#pragma push_macro("XRPL_RETIRE")
#undef XRPL_RETIRE
#define XRPL_FEATURE(name, supported, vote) +1
#define XRPL_FIX(name, supported, vote) +1
#define XRPL_RETIRE(name) +1
// This value SHOULD be equal to the number of amendments registered in
// Feature.cpp. Because it's only used to reserve storage, and determine how
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
// the actual number of amendments. A LogicError on startup will verify this.
static constexpr std::size_t numFeatures =
(0 +
#include <xrpl/protocol/detail/features.macro>
);
#undef XRPL_RETIRE
#pragma pop_macro("XRPL_RETIRE")
#undef XRPL_FIX
#pragma pop_macro("XRPL_FIX")
#undef XRPL_FEATURE
#pragma pop_macro("XRPL_FEATURE")
static constexpr std::size_t numFeatures = 111;
/** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated
@@ -345,17 +320,12 @@ foreachFeature(FeatureBitset bs, F&& f)
#undef XRPL_FEATURE
#pragma push_macro("XRPL_FIX")
#undef XRPL_FIX
#pragma push_macro("XRPL_RETIRE")
#undef XRPL_RETIRE
#define XRPL_FEATURE(name, supported, vote) extern uint256 const feature##name;
#define XRPL_FIX(name, supported, vote) extern uint256 const fix##name;
#define XRPL_RETIRE(name)
#include <xrpl/protocol/detail/features.macro>
#undef XRPL_RETIRE
#pragma pop_macro("XRPL_RETIRE")
#undef XRPL_FIX
#pragma pop_macro("XRPL_FIX")
#undef XRPL_FEATURE

View File

@@ -97,12 +97,6 @@ public:
static IOUAmount
minPositiveAmount();
friend std::ostream&
operator<<(std::ostream& os, IOUAmount const& x)
{
return os << to_string(x);
}
};
inline IOUAmount::IOUAmount(beast::Zero)

View File

@@ -20,8 +20,8 @@
#ifndef RIPPLE_PROTOCOL_IMPORT_H_INCLUDED
#define RIPPLE_PROTOCOL_IMPORT_H_INCLUDED
// #include <ripple/basics/Log.h>
#include <xrpld/app/misc/Manifest.h>
#include <xrpl/basics/Log.h>
#include <xrpl/basics/StringUtilities.h>
#include <xrpl/basics/base64.h>
#include <xrpl/json/json_reader.h>

View File

@@ -147,9 +147,8 @@ enum LedgerSpecificFlags {
0x40000000, // True, has minted tokens in the past
lsfDisallowIncomingRemit = // True, no remits allowed to this account
0x80000000,
// 0x0004000 is available
lsfAllowTrustLineClawback =
0x00001000, // True, enable clawback
lsfAllowTrustLineClawback =
0x00001000, // True, enable clawback
// ltOFFER
lsfPassive = 0x00010000,
@@ -164,10 +163,10 @@ enum LedgerSpecificFlags {
lsfHighNoRipple = 0x00200000,
lsfLowFreeze = 0x00400000, // True, low side has set freeze flag
lsfHighFreeze = 0x00800000, // True, high side has set freeze flag
lsfAMMNode = 0x01000000, // True, trust line to AMM. Used by client
// apps to identify payments via AMM.
lsfLowDeepFreeze = 0x02000000, // True, low side has set deep freeze flag
lsfHighDeepFreeze = 0x04000000, // True, high side has set deep freeze flag
lsfAMMNode = 0x01000000, // True, trust line to AMM. Used by client
// apps to identify payments via AMM.
// ltSIGNER_LIST
lsfOneOwnerCount = 0x00010000, // True, uses only one OwnerCount

View File

@@ -28,9 +28,6 @@
namespace ripple {
bool
isFeatureEnabled(uint256 const& feature);
class DigestAwareReadView;
/** Rules controlling protocol behavior. */

View File

@@ -137,7 +137,6 @@ enum TEMcodes : TERUnderlyingType {
temXCHAIN_BRIDGE_NONDOOR_OWNER,
temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT,
temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT,
temXCHAIN_TOO_MANY_ATTESTATIONS, // RESERVED - not used
temHOOK_DATA_TOO_LARGE,
temEMPTY_DID,

View File

@@ -125,14 +125,14 @@ enum TrustSetFlags : uint32_t {
tfSetFreeze = 0x00100000,
tfClearFreeze = 0x00200000,
tfSetDeepFreeze = 0x00400000,
tfClearDeepFreeze = 0x00800000
tfClearDeepFreeze = 0x00800000,
};
constexpr std::uint32_t tfTrustSetMask =
~(tfUniversal | tfSetfAuth | tfSetNoRipple | tfClearNoRipple | tfSetFreeze |
tfClearFreeze | tfSetDeepFreeze | tfClearDeepFreeze);
// EnableAmendment flags:
enum EnableAmendmentFlags : uint32_t {
enum EnableAmendmentFlags : std::uint32_t {
tfGotMajority = 0x00010000,
tfLostMajority = 0x00020000,
tfTestSuite = 0x80000000,

View File

@@ -23,24 +23,12 @@
#if !defined(XRPL_FIX)
#error "undefined macro: XRPL_FIX"
#endif
#if !defined(XRPL_RETIRE)
#error "undefined macro: XRPL_RETIRE"
#endif
// clang-format off
// Add new amendments to the top of this list.
// 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(JSHooks, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (HookMap, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (GuardDepth32, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(NamedHooks, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(IOURewardClaim, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (IOULockedBalanceInvariant, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (ImportIssuer, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(HookAPISerializedType240, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(PermissionedDomains, Supported::no, VoteBehavior::DefaultNo)
XRPL_FEATURE(DynamicNFT, Supported::no, VoteBehavior::DefaultNo)
@@ -62,19 +50,17 @@ XRPL_FIX (FillOrKill, Supported::yes, VoteBehavior::DefaultYe
XRPL_FEATURE(DID, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (DisallowIncomingV1, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(XChainBridge, Supported::no, VoteBehavior::DefaultNo)
XRPL_FEATURE(AMM, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (ReducedOffersV1, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(HooksUpdate2, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(HookOnV2, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(AMM, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (HookAPI20251128, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (CronStacking, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(ExtendedHookState, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(Cron, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(IOUIssuerWeakTSH, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (ProvisionalDoubleThreading, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(Clawback, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (ReducedOffersV1, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (ProvisionalDoubleThreading, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (RewardClaimFlags, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FEATURE(HookCanEmit, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (20250131, Supported::yes, VoteBehavior::DefaultYes)
@@ -157,24 +143,3 @@ XRPL_FIX (NFTokenDirV1, Supported::yes, VoteBehavior::Obsolete)
XRPL_FEATURE(NonFungibleTokensV1, Supported::yes, VoteBehavior::Obsolete)
XRPL_FEATURE(CryptoConditionsSuite, Supported::yes, VoteBehavior::Obsolete)
// The following amendments have been active for at least two years. Their
// pre-amendment code has been removed and the identifiers are deprecated.
// All known amendments and amendments that may appear in a validated
// ledger must be registered either here or above with the "active" amendments
XRPL_RETIRE(MultiSign)
XRPL_RETIRE(TrustSetAuth)
XRPL_RETIRE(FeeEscalation)
XRPL_RETIRE(PayChan)
XRPL_RETIRE(CryptoConditions)
XRPL_RETIRE(TickSize)
XRPL_RETIRE(fix1368)
XRPL_RETIRE(Escrow)
XRPL_RETIRE(fix1373)
XRPL_RETIRE(EnforceInvariants)
XRPL_RETIRE(SortedDirectories)
XRPL_RETIRE(fix1201)
XRPL_RETIRE(fix1512)
XRPL_RETIRE(fix1523)
XRPL_RETIRE(fix1528)
// clang-format on

View File

@@ -65,7 +65,7 @@ LEDGER_ENTRY_DUPLICATE(ltCRON, 0x0041, Cron, cron, ({
{sfRepeatCount, soeREQUIRED},
{sfOwnerNode, soeREQUIRED},
{sfPreviousTxnID, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED},
{sfPreviousTxnLgrSeq, soeREQUIRED}
}))
/** A ledger object which describes a check.
@@ -93,9 +93,7 @@ LEDGER_ENTRY(ltCHECK, 0x0043, Check, check, ({
*/
LEDGER_ENTRY(ltHOOK_DEFINITION, 'D', HookDefinition, hook_definition, ({
{sfHookHash, soeREQUIRED},
{sfHookOn, soeOPTIONAL},
{sfHookOnIncoming, soeOPTIONAL},
{sfHookOnOutgoing, soeOPTIONAL},
{sfHookOn, soeREQUIRED},
{sfHookCanEmit, soeOPTIONAL},
{sfHookNamespace, soeREQUIRED},
{sfHookParameters, soeREQUIRED},
@@ -132,8 +130,6 @@ LEDGER_ENTRY(ltHOOK, 'H', Hook, hook, ({
/** The ledger object which records the last (and largest) sequence for a validator list key
* as used in the Import amendment
\sa keylet::import_vlseq
*/
LEDGER_ENTRY(ltIMPORT_VLSEQ, 0x0049, ImportVLSequence, import_vlseq, ({
{sfPublicKey, soeREQUIRED},
@@ -396,8 +392,6 @@ LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, ({
{sfHighQualityOut, soeOPTIONAL},
{sfLockedBalance, soeOPTIONAL},
{sfLockCount, soeOPTIONAL},
{sfHighReward, soeOPTIONAL},
{sfLowReward, soeOPTIONAL},
}))
/** The ledger object which lists the network's fee settings.

View File

@@ -210,13 +210,11 @@ TYPED_SFIELD(sfOfferID, UINT256, 34)
TYPED_SFIELD(sfEscrowID, UINT256, 35)
TYPED_SFIELD(sfURITokenID, UINT256, 36)
TYPED_SFIELD(sfDomainID, UINT256, 37)
TYPED_SFIELD(sfHookOnOutgoing, UINT256, 93)
TYPED_SFIELD(sfHookOnIncoming, UINT256, 94)
TYPED_SFIELD(sfCron, UINT256, 95)
TYPED_SFIELD(sfHookCanEmit, UINT256, 96)
TYPED_SFIELD(sfEmittedTxnID, UINT256, 97)
TYPED_SFIELD(sfGovernanceMarks, UINT256, 98)
TYPED_SFIELD(sfGovernanceFlags, UINT256, 99)
TYPED_SFIELD(sfGovernanceMarks, UINT256, 98)
TYPED_SFIELD(sfEmittedTxnID, UINT256, 97)
TYPED_SFIELD(sfHookCanEmit, UINT256, 96)
TYPED_SFIELD(sfCron, UINT256, 95)
// number (common)
TYPED_SFIELD(sfNumber, NUMBER, 1)
@@ -257,7 +255,6 @@ TYPED_SFIELD(sfPrice, AMOUNT, 28)
TYPED_SFIELD(sfSignatureReward, AMOUNT, 29)
TYPED_SFIELD(sfMinAccountCreateAmount, AMOUNT, 30)
TYPED_SFIELD(sfLPTokenBalance, AMOUNT, 31)
TYPED_SFIELD(sfTrustLineRewardAccumulator,AMOUNT, 99)
// variable length (common)
TYPED_SFIELD(sfPublicKey, VL, 1)
@@ -293,7 +290,6 @@ TYPED_SFIELD(sfAssetClass, VL, 29)
TYPED_SFIELD(sfProvider, VL, 30)
TYPED_SFIELD(sfMPTokenMetadata, VL, 31)
TYPED_SFIELD(sfCredentialType, VL, 32)
TYPED_SFIELD(sfHookName, VL, 97)
TYPED_SFIELD(sfRemarkValue, VL, 98)
TYPED_SFIELD(sfRemarkName, VL, 99)
@@ -342,7 +338,6 @@ TYPED_SFIELD(sfLockingChainIssue, ISSUE, 1)
TYPED_SFIELD(sfIssuingChainIssue, ISSUE, 2)
TYPED_SFIELD(sfAsset, ISSUE, 3)
TYPED_SFIELD(sfAsset2, ISSUE, 4)
TYPED_SFIELD(sfClaimCurrency, ISSUE, 5)
// bridge
TYPED_SFIELD(sfXChainBridge, XCHAIN_BRIDGE, 1)
@@ -370,7 +365,7 @@ UNTYPED_SFIELD(sfMajority, OBJECT, 18)
UNTYPED_SFIELD(sfDisabledValidator, OBJECT, 19)
UNTYPED_SFIELD(sfEmittedTxn, OBJECT, 20)
UNTYPED_SFIELD(sfHookExecution, OBJECT, 21)
// 22 unused
UNTYPED_SFIELD(sfHookDefinition, OBJECT, 22)
UNTYPED_SFIELD(sfHookParameter, OBJECT, 23)
UNTYPED_SFIELD(sfHookGrant, OBJECT, 24)
UNTYPED_SFIELD(sfVoteEntry, OBJECT, 25)
@@ -389,8 +384,6 @@ UNTYPED_SFIELD(sfImportVLKey, OBJECT, 94)
UNTYPED_SFIELD(sfActiveValidator, OBJECT, 95)
UNTYPED_SFIELD(sfGenesisMint, OBJECT, 96)
UNTYPED_SFIELD(sfRemark, OBJECT, 97)
UNTYPED_SFIELD(sfHighReward, OBJECT, 98)
UNTYPED_SFIELD(sfLowReward, OBJECT, 99)
// array of objects (common)
// ARRAY/1 is reserved for end of array
@@ -421,9 +414,9 @@ UNTYPED_SFIELD(sfAuthAccounts, ARRAY, 25)
UNTYPED_SFIELD(sfAuthorizeCredentials, ARRAY, 26)
UNTYPED_SFIELD(sfUnauthorizeCredentials, ARRAY, 27)
UNTYPED_SFIELD(sfAcceptedCredentials, ARRAY, 28)
UNTYPED_SFIELD(sfAmounts, ARRAY, 92)
UNTYPED_SFIELD(sfHookEmissions, ARRAY, 93)
UNTYPED_SFIELD(sfImportVLKeys, ARRAY, 94)
UNTYPED_SFIELD(sfActiveValidators, ARRAY, 95)
UNTYPED_SFIELD(sfGenesisMints, ARRAY, 96)
UNTYPED_SFIELD(sfRemarks, ARRAY, 97)
UNTYPED_SFIELD(sfGenesisMints, ARRAY, 96)
UNTYPED_SFIELD(sfActiveValidators, ARRAY, 95)
UNTYPED_SFIELD(sfImportVLKeys, ARRAY, 94)
UNTYPED_SFIELD(sfHookEmissions, ARRAY, 93)
UNTYPED_SFIELD(sfAmounts, ARRAY, 92)

View File

@@ -513,6 +513,7 @@ TRANSACTION(ttCRON_SET, 93, CronSet, ({
{sfStartTime, soeOPTIONAL},
}))
/* A note attaching transactor that allows the owner or issuer (on a object by object basis) to attach remarks */
TRANSACTION(ttREMARKS_SET, 94, SetRemarks, ({
{sfObjectID, soeREQUIRED},
@@ -550,7 +551,6 @@ TRANSACTION(ttIMPORT, 97, Import, ({
* from a specified hook */
TRANSACTION(ttCLAIM_REWARD, 98, ClaimReward, ({
{sfIssuer, soeOPTIONAL},
{sfClaimCurrency, soeOPTIONAL},
}))
/** This transaction invokes a hook, providing arbitrary data. Essentially as a 0 drop payment. **/

View File

@@ -76,11 +76,8 @@ JSS(Holder); // field.
JSS(HookApiVersion); // field
JSS(HookCanEmit); // field
JSS(HookHash); // field
JSS(HookName); // field
JSS(HookNamespace); // field
JSS(HookOn); // field
JSS(HookOnIncoming); // field
JSS(HookOnOutgoing); // field
JSS(Hooks); // field
JSS(HookGrants); // field
JSS(HookParameters); // field
@@ -98,7 +95,6 @@ JSS(Invalid); //
JSS(Issuer); // in: Credential transactions
JSS(InvoiceID); // field
JSS(LastLedgerSequence); // in: TransactionSign; field
JSS(FirstLedgerSequence); // in: TransactionSign; field
JSS(LastUpdateTime); // field.
JSS(LimitAmount); // field.
JSS(NetworkID); // field.
@@ -123,7 +119,6 @@ JSS(Signer); // field.
JSS(Signers); // field.
JSS(HookStateData); // field.
JSS(HookStateKey); // field.
JSS(EmitDetails); // field.
JSS(SigningPubKey); // field.
JSS(Subject); // in: Credential transactions
JSS(TakerGets); // field.

View File

@@ -11,11 +11,11 @@ echo "START BUILDING (HOST)"
echo "Cleaning previously built binary"
rm -f release-build/xahaud
BUILD_CORES=$(echo "scale=0 ; $(nproc) / 1.337" | bc)
BUILD_CORES=$(echo "scale=0 ; `nproc` / 1.337" | bc)
if [[ "$GITHUB_REPOSITORY" == "" ]]; then
#Default
BUILD_CORES=${BUILD_CORES:-8}
BUILD_CORES=${BUILD_CORES:-8}
fi
# Ensure still works outside of GH Actions by setting these to /dev/null
@@ -31,19 +31,21 @@ echo "-- GITHUB_SHA: $GITHUB_SHA"
echo "-- GITHUB_RUN_NUMBER: $GITHUB_RUN_NUMBER"
echo "-- CONTAINER_NAME: $CONTAINER_NAME"
which docker 2>/dev/null 2>/dev/null
if [ "$?" -eq "1" ]; then
which docker 2> /dev/null 2> /dev/null
if [ "$?" -eq "1" ]
then
echo 'Docker not found. Install it first.'
exit 1
fi
stat .git 2>/dev/null 2>/dev/null
if [ "$?" -eq "1" ]; then
stat .git 2> /dev/null 2> /dev/null
if [ "$?" -eq "1" ]
then
echo 'Run this inside the source directory. (.git dir not found).'
exit 1
fi
STATIC_CONTAINER=$(docker ps -a | grep $CONTAINER_NAME | wc -l)
STATIC_CONTAINER=$(docker ps -a | grep $CONTAINER_NAME |wc -l)
CACHE_VOLUME_NAME="xahau-release-builder-cache"
@@ -55,14 +57,13 @@ if false; then
docker stop $CONTAINER_NAME
else
echo "No static container, build on temp container"
rm -rf release-build
mkdir -p release-build
rm -rf release-build;
mkdir -p release-build;
docker volume create $CACHE_VOLUME_NAME
# Create inline Dockerfile with environment setup for build-full.sh
DOCKERFILE_CONTENT=$(
cat <<'DOCKERFILE_EOF'
DOCKERFILE_CONTENT=$(cat <<'DOCKERFILE_EOF'
FROM ghcr.io/phusion/holy-build-box:4.0.1-amd64
ARG BUILD_CORES=8
@@ -128,9 +129,6 @@ ENV CMAKE_EXE_LINKER_FLAGS="-static-libstdc++"
ENV LLVM_DIR=/usr/lib64/llvm14/lib/cmake/llvm
ENV WasmEdge_LIB=/usr/local/lib64/libwasmedge.a
ENV CC='ccache gcc'
ENV CXX='ccache g++'
# Install LLD
RUN /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && \
cd /tmp && \
@@ -195,7 +193,6 @@ ENV PATH=/usr/local/bin:$PATH
RUN /hbb_exe/activate-exec bash -c "ccache -M 100G && \
ccache -o cache_dir=/cache/ccache && \
ccache -o compiler_check=content && \
ccache -o direct_mode=true && \
mkdir -p ~/.conan2 /cache/conan2 /cache/conan2_download /cache/conan2_sources && \
echo 'core.cache:storage_path=/cache/conan2' > ~/.conan2/global.conf && \
echo 'core.download:download_cache=/cache/conan2_download' >> ~/.conan2/global.conf && \
@@ -217,7 +214,7 @@ RUN /hbb_exe/activate-exec bash -c "ccache -M 100G && \
ln -s ../../bin/ccache /usr/lib64/ccache/c++"
DOCKERFILE_EOF
)
)
# Build custom Docker image
IMAGE_NAME="xahaud-builder:latest"
@@ -227,14 +224,14 @@ DOCKERFILE_EOF
if [[ "$GITHUB_REPOSITORY" == "" ]]; then
# Non GH, local building
echo "Non-GH runner, local building, temp container"
docker run -i --user 0:$(id -g) --rm -v /data/builds:/data/builds -v $(pwd):/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && bash -x /io/build-full.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
docker run -i --user 0:$(id -g) --rm -v /data/builds:/data/builds -v `pwd`:/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && bash -x /io/build-full.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
else
# GH Action, runner
echo "GH Action, runner, clean & re-create create persistent container"
docker rm -f $CONTAINER_NAME
echo "echo 'Stopping container: $CONTAINER_NAME'" >>"$JOB_CLEANUP_SCRIPT"
echo "docker stop --time=15 \"$CONTAINER_NAME\" || echo 'Failed to stop container or container not running'" >>"$JOB_CLEANUP_SCRIPT"
docker run -di --user 0:$(id -g) --name $CONTAINER_NAME -v /data/builds:/data/builds -v $(pwd):/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" /hbb_exe/activate-exec bash
echo "echo 'Stopping container: $CONTAINER_NAME'" >> "$JOB_CLEANUP_SCRIPT"
echo "docker stop --time=15 \"$CONTAINER_NAME\" || echo 'Failed to stop container or container not running'" >> "$JOB_CLEANUP_SCRIPT"
docker run -di --user 0:$(id -g) --name $CONTAINER_NAME -v /data/builds:/data/builds -v `pwd`:/io -v "$CACHE_VOLUME_NAME":/cache --network host "$IMAGE_NAME" /hbb_exe/activate-exec bash
docker exec -i $CONTAINER_NAME /hbb_exe/activate-exec bash -c "source /opt/rh/gcc-toolset-11/enable && bash -x /io/build-full.sh '$GITHUB_REPOSITORY' '$GITHUB_SHA' '$BUILD_CORES' '$GITHUB_RUN_NUMBER'"
docker stop $CONTAINER_NAME
fi

View File

@@ -22,11 +22,11 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/basics/contract.h>
#include <xrpl/beast/utility/instrumentation.h>
#ifdef BEAST_ENHANCED_LOGGING
#include <xrpl/beast/utility/EnhancedLogging.h>
#include <date/tz.h>
#endif
#include <xrpl/beast/utility/instrumentation.h>
#include <boost/algorithm/string.hpp>
#include <cassert>
#include <cstring>

View File

@@ -66,7 +66,7 @@ invalidAMMAsset(
Issue const& issue,
std::optional<std::pair<Issue, Issue>> const& pair)
{
if (isBadCurrency(issue.currency))
if (badCurrency() == issue.currency)
return temBAD_CURRENCY;
if (isXRP(issue) && issue.account.isNonZero())
return temBAD_ISSUER;

View File

@@ -250,9 +250,12 @@ FeatureCollections::registerFeature(
Feature const* i = getByName(name);
if (!i)
{
// If this check fails, and you just added a feature, increase the
// numFeatures value in Feature.h
check(
features.size() < detail::numFeatures,
"More features defined than allocated.");
"More features defined than allocated. Adjust numFeatures in "
"Feature.h.");
auto const f = sha512Half(Slice(name.data(), name.size()));
@@ -421,26 +424,45 @@ featureToName(uint256 const& f)
#undef XRPL_FEATURE
#pragma push_macro("XRPL_FIX")
#undef XRPL_FIX
#pragma push_macro("XRPL_RETIRE")
#undef XRPL_RETIRE
#define XRPL_FEATURE(name, supported, vote) \
uint256 const feature##name = registerFeature(#name, supported, vote);
#define XRPL_FIX(name, supported, vote) \
uint256 const fix##name = registerFeature("fix" #name, supported, vote);
#define XRPL_RETIRE(name) \
[[deprecated("The referenced amendment has been retired"), maybe_unused]] \
uint256 const retired##name = retireFeature(#name);
#include <xrpl/protocol/detail/features.macro>
#undef XRPL_RETIRE
#pragma pop_macro("XRPL_RETIRE")
#undef XRPL_FIX
#pragma pop_macro("XRPL_FIX")
#undef XRPL_FEATURE
#pragma pop_macro("XRPL_FEATURE")
// clang-format off
// The following amendments have been active for at least two years. Their
// pre-amendment code has been removed and the identifiers are deprecated.
// All known amendments and amendments that may appear in a validated
// ledger must be registered either here or above with the "active" amendments
[[deprecated("The referenced amendment has been retired"), maybe_unused]]
uint256 const
retiredMultiSign = retireFeature("MultiSign"),
retiredTrustSetAuth = retireFeature("TrustSetAuth"),
retiredFeeEscalation = retireFeature("FeeEscalation"),
retiredPayChan = retireFeature("PayChan"),
retiredCryptoConditions = retireFeature("CryptoConditions"),
retiredTickSize = retireFeature("TickSize"),
retiredFix1368 = retireFeature("fix1368"),
retiredEscrow = retireFeature("Escrow"),
retiredFix1373 = retireFeature("fix1373"),
retiredEnforceInvariants = retireFeature("EnforceInvariants"),
retiredSortedDirectories = retireFeature("SortedDirectories"),
retiredFix1201 = retireFeature("fix1201"),
retiredFix1512 = retireFeature("fix1512"),
retiredFix1523 = retireFeature("fix1523"),
retiredFix1528 = retireFeature("fix1528");
// clang-format on
// All of the features should now be registered, since variables in a cpp file
// are initialized from top to bottom.
//

View File

@@ -31,8 +31,6 @@
namespace ripple {
#define LEDGER_NAMESPACE2(value1, value2) (uint16_t(value1) << 8) | value2
/** Type-specific prefix for calculating ledger indices.
The identifier for a given object within the ledger is calculated based
@@ -82,14 +80,14 @@ enum class LedgerNameSpace : std::uint16_t {
UNL_REPORT = 'R',
CRON = 'L',
AMM = 'A',
BRIDGE = LEDGER_NAMESPACE2(0x01, 'H'),
BRIDGE = 'H',
XCHAIN_CLAIM_ID = 'Q',
XCHAIN_CREATE_ACCOUNT_CLAIM_ID = 'K',
DID = LEDGER_NAMESPACE2(0x01, 'I'),
ORACLE = LEDGER_NAMESPACE2(0x01, 'R'),
DID = 'I',
ORACLE = 'R',
MPTOKEN_ISSUANCE = '~',
MPTOKEN = 't',
CREDENTIAL = LEDGER_NAMESPACE2(0x01, 'D'),
CREDENTIAL = 'D',
PERMISSIONED_DOMAIN = 'm',
// No longer used or supported. Left here to reserve the space

View File

@@ -87,6 +87,17 @@ InnerObjectFormats::InnerObjectFormats()
{sfEmittedTxnID, soeREQUIRED},
{sfEmitNonce, soeOPTIONAL}});
add(sfHookDefinition.jsonName,
sfHookDefinition.getCode(),
{{sfCreateCode, soeREQUIRED},
{sfHookNamespace, soeREQUIRED},
{sfHookParameters, soeREQUIRED},
{sfHookOn, soeREQUIRED},
{sfHookCanEmit, soeOPTIONAL},
{sfHookApiVersion, soeREQUIRED},
{sfFlags, soeREQUIRED},
{sfFee, soeREQUIRED}});
add(sfHook.jsonName,
sfHook.getCode(),
{{sfHookHash, soeOPTIONAL},
@@ -95,11 +106,8 @@ InnerObjectFormats::InnerObjectFormats()
{sfHookNamespace, soeOPTIONAL},
{sfHookParameters, soeOPTIONAL},
{sfHookOn, soeOPTIONAL},
{sfHookOnIncoming, soeOPTIONAL},
{sfHookOnOutgoing, soeOPTIONAL},
{sfHookCanEmit, soeOPTIONAL},
{sfHookApiVersion, soeOPTIONAL},
{sfHookName, soeOPTIONAL},
{sfFlags, soeOPTIONAL}});
add(sfHookGrant.jsonName,
@@ -254,24 +262,6 @@ InnerObjectFormats::InnerObjectFormats()
{sfIssuer, soeREQUIRED},
{sfCredentialType, soeREQUIRED},
});
add(sfHighReward.jsonName,
sfHighReward.getCode(),
{
{sfRewardLgrFirst, soeREQUIRED},
{sfRewardLgrLast, soeREQUIRED},
{sfRewardTime, soeREQUIRED},
{sfTrustLineRewardAccumulator, soeREQUIRED},
});
add(sfLowReward.jsonName,
sfLowReward.getCode(),
{
{sfRewardLgrFirst, soeREQUIRED},
{sfRewardLgrLast, soeREQUIRED},
{sfRewardTime, soeREQUIRED},
{sfTrustLineRewardAccumulator, soeREQUIRED},
});
}
InnerObjectFormats const&

View File

@@ -111,7 +111,7 @@ issueFromJson(Json::Value const& v)
}
auto const currency = to_currency(curStr.asString());
if (isBadCurrency(currency) || currency == noCurrency())
if (currency == badCurrency() || currency == noCurrency())
{
Throw<Json::error>("issueFromJson currency must be a valid currency");
}

View File

@@ -153,12 +153,4 @@ Rules::operator!=(Rules const& other) const
{
return !(*this == other);
}
bool
isFeatureEnabled(uint256 const& feature)
{
auto const& rules = getCurrentTransactionRules();
return rules && rules->enabled(feature);
}
} // namespace ripple

View File

@@ -103,7 +103,7 @@ currencyFromJson(SField const& name, Json::Value const& v)
}
auto const currency = to_currency(v.asString());
if (isBadCurrency(currency) || currency == noCurrency())
if (currency == badCurrency() || currency == noCurrency())
{
Throw<std::runtime_error>(
"currencyFromJson currency must be a valid currency");

View File

@@ -48,7 +48,6 @@ TxFormats::TxFormats()
{sfFirstLedgerSequence, soeOPTIONAL},
{sfNetworkID, soeOPTIONAL},
{sfHookParameters, soeOPTIONAL},
{sfHookName, soeOPTIONAL},
};
#pragma push_macro("UNWRAP")

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