Compare commits

..

95 Commits

Author SHA1 Message Date
JCW
4001748ee9 Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-29 09:57:31 +01:00
JCW
f1482d332c Fix errors
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 16:49:11 +01:00
JCW
373121ed78 Fix levelisation
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 15:54:56 +01:00
JCW
17c10de2ea Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 15:46:10 +01:00
JCW
6de7802001 Remove unrelated changes
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 15:30:49 +01:00
JCW
56a45506eb Optimise
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:08:06 +01:00
JCW
23029ab2b6 Optimise
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:52 +01:00
JCW
d1fe8ed31d Fix error
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:52 +01:00
JCW
129166cda5 Fix build error
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:52 +01:00
JCW
6376f10df7 Fix unit tests
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:52 +01:00
JCW
acafed7376 Performance test
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:52 +01:00
JCW
4feaa7b279 WIP
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:52 +01:00
JCW
45a4f44dc1 Performance test
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:51 +01:00
JCW
211d90dadd Performance test
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:51 +01:00
JCW
a4498f084e Performance test
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:51 +01:00
JCW
294dae5766 Performance test
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:51 +01:00
JCW
d2f01eb755 Performance test
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:51 +01:00
JCW
a854a78107 Fix test error
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:51 +01:00
JCW
c4047690e2 Fix test cases
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:50 +01:00
JCW
893632d330 Performance test
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:50 +01:00
JCW
f44d53be16 Fix test error
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:50 +01:00
JCW
d33691da84 Log size optimise
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:50 +01:00
JCW
1dc3b256e0 Bugfix
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:50 +01:00
JCW
2c2936fa93 Fix issues
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:50 +01:00
JCW
dcec5a0bbc Revert unrelated changes & performance optimisation
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:20 +01:00
JCW
ce5a6aec7b Revert unneeded changes
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:06:18 +01:00
JCW
79c3a83088 Fix build error
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:03:16 +01:00
JCW
bd91ec7242 Optimise
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:03:14 +01:00
JCW
bb787e3995 Optimisation
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:55 +01:00
JCW
0223443452 Hardcode the logstyle as json
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:54 +01:00
JCW
79e8c6a158 Add additional check
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:54 +01:00
JCW
44aa394e1e Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:54 +01:00
JCW
5e16b3df62 Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:54 +01:00
JCW
2f6d133169 Improve test coverage
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:54 +01:00
JCW
06c212495d Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:54 +01:00
JCW
9543ccf8e1 Set module name in json
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:53 +01:00
JCW
816089eab7 Fix error
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:53 +01:00
JCW
fa0cff3532 Fix build error
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:53 +01:00
JCW
3ec7596170 Fix build error
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:53 +01:00
JCW
28ad89ca20 Fix build error
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:53 +01:00
JCW
e6c5f8338b Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:53 +01:00
JCW
4d0c0ca5c7 Polish code
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:53 +01:00
JCW
4f63747f33 Polish code
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:52 +01:00
JCW
1a2b7e9b94 Fix issues
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:52 +01:00
JCW
c2aae2d846 Optimisation
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:52 +01:00
JCW
458bd8a3bd Revert unrelated changes
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:52 +01:00
JCW
cd8d5d97d1 Fix issues
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:52 +01:00
JCW
bd7b098409 Fix levelisation
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:52 +01:00
JCW
addfae1213 Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:51 +01:00
JCW
89ebb6b495 Fix issues
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:24 +01:00
JCW
67aa3d5ac9 Remove hardcoded logstyle
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:24 +01:00
JCW
3b2edce813 Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:23 +01:00
JCW
1d3d0c6774 Optimise
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:23 +01:00
JCW
f50f76788b Fix issues
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:23 +01:00
JCW
feae1d6e15 Optimisation
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:23 +01:00
JCW
7debf3e9f4 Optimisation
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:23 +01:00
JCW
90f970be46 Improve performance
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:23 +01:00
JCW
5e060a9e7b Fix
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:22 +01:00
JCW
dca000a60f Optimisation
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:22 +01:00
JCW
7500d635bb Fix issues
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:22 +01:00
JCW
3181042f15 Fix issues
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:22 +01:00
JCW
157aa367f2 Fix issues
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:22 +01:00
JCW
48cf042258 Optimisation
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:22 +01:00
JCW
61ff2ba0e7 Fix issues
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:21 +01:00
JCW
e19d770b86 performance optimisation
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 14:02:21 +01:00
JCW
a128571ab5 Fix issues 2025-09-26 14:02:21 +01:00
JCW
76bb517eb8 Fix issues 2025-09-26 14:02:21 +01:00
JCW
dc221de60c Fix issues 2025-09-26 14:02:21 +01:00
JCW
cdf1109558 Performance improvement 2025-09-26 14:02:18 +01:00
JCW
0fe8f3f62d Hardcode the log style as json
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:55 +01:00
JCW
ab9e6563e4 Fix PR comments
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:54 +01:00
Jingchen
d0f0789490 Update include/xrpl/basics/Log.h
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
2025-09-26 13:55:54 +01:00
JCW
d36ef0cd18 Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:54 +01:00
JCW
a90bf169bf Improve coverage
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:54 +01:00
JCW
b3f389d918 Remove unneeded file
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:54 +01:00
JCW
d68f87f968 Fix errors
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:54 +01:00
JCW
34127593e6 Fix errors
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:53 +01:00
JCW
9e09595db0 Fix errors
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:53 +01:00
JCW
856b36d0a5 Fix errors
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:53 +01:00
JCW
9edba67e64 Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:53 +01:00
JCW
0e4f9a7ccf Fix errors
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:51 +01:00
JCW
eda9bf1f1a Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:41 +01:00
JCW
43c6e202af Fix to_string error
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:41 +01:00
JCW
e4db80f61d Fix errors
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:39 +01:00
JCW
af9dde4f75 Fix formatting
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:19 +01:00
JCW
f6d7b90b70 Support structured logs
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:18 +01:00
JCW
1774769226 Support structured logs
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:18 +01:00
JCW
92312801f1 Support structured logs
Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-09-26 13:55:16 +01:00
Jingchen
cfd26f444c fix: Address http header case sensitivity (#5767)
This change makes the regex in `HttpClient.cpp` that matches the content-length http header case insensitive to improve compatibility, as http headers are case insensitive.
2025-09-26 11:40:43 +00:00
tequ
2c3024716b change fixPriceOracleOrder to Supported::yes (#5749) 2025-09-26 12:07:48 +01:00
Bart
a12f5de68d chore: Pin all CI Docker tags (#5813)
To avoid surprises and ensure reproducibility, this change pins all CI Docker image tags to the latest version in the XRPLF/CI repo.
2025-09-25 16:08:07 +00:00
Bronek Kozicki
51c5f2bfc9 Improve ValidatorList invalid UNL manifest logging (#5804)
This change raises logging severity from `INFO` to `WARN` when handling UNL manifest signed with an unexpected / invalid key. It also changes the internal error code for an invalid format of UNL manifest to `invalid` (from `untrusted`).

This is a follow up to problems experienced by an UNL node due to old manifest key configured in `validators.txt`, which would be easier to diagnose with improved logging.

It also replaces a log line with `UNREACHABLE` for an impossible situation when we match UNL manifest key against a configured key which has an invalid type (we cannot configure such a key because of checks when loading configured keys).
2025-09-25 16:14:29 +02:00
Valentin Balaschenko
73ff54143d docs: Add warning about using std::counting_semaphore (#5595)
This adds a comment to avoid using `std::counting_semaphore` until the minimum compiler versions of GCC and Clang have been updated to no longer contain the bug that is present in older compilers.
2025-09-23 13:26:26 +02:00
Bart
08b136528e Revert "Update Conan dependencies: OpenSSL" (#5807)
This change reverts #5617, because it will require extensive testing that will take up more time than we have before the next scheduled release.

Reverting this change does not mean we are abandoning it. We aim to pick it back up once there's a sufficient time window to allow for testing on multiple distros running a mixture of OpenSSL 1.x and 3.x.
2025-09-22 18:27:02 +00:00
Mayukha Vadari
6b8a589447 test: Add STInteger and STParsedJSON tests (#5726)
This change is to improve code coverage (and to simplify #5720 and #5725); there is otherwise no change in functionality. The change adds basic tests for `STInteger` and `STParsedJSON`, so it becomes easier to test smaller changes to the types, as well as removes `STParsedJSONArray`, since it is not used anywhere (including in Clio).
2025-09-22 20:00:31 +02:00
131 changed files with 4641 additions and 30585 deletions

6
.github/CODEOWNERS vendored
View File

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

View File

@@ -138,6 +138,7 @@ test.toplevel > test.csf
test.toplevel > xrpl.json
test.unit_test > xrpl.basics
tests.libxrpl > xrpl.basics
tests.libxrpl > xrpl.net
xrpl.json > xrpl.basics
xrpl.ledger > xrpl.basics
xrpl.ledger > xrpl.protocol

View File

@@ -63,7 +63,7 @@ jobs:
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
max-parallel: 10
runs-on: ${{ matrix.architecture.runner }}
container: ${{ inputs.os == 'linux' && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version) || null }}
container: ${{ inputs.os == 'linux' && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-5dd7158', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version) || null }}
steps:
- name: Check strategy matrix
run: |

View File

@@ -40,7 +40,7 @@ jobs:
upload:
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
runs-on: ubuntu-latest
container: ghcr.io/xrplf/ci/ubuntu-noble:gcc-13
container: ghcr.io/xrplf/ci/ubuntu-noble:gcc-13-sha-5dd7158
steps:
- name: Checkout repository
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0

View File

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

View File

@@ -27,7 +27,7 @@ env:
jobs:
publish:
runs-on: ubuntu-latest
container: ghcr.io/xrplf/ci/tools-rippled-documentation
container: ghcr.io/xrplf/ci/tools-rippled-documentation:sha-d1496b8
permissions:
contents: write
steps:

View File

@@ -56,7 +56,7 @@ jobs:
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
max-parallel: 10
runs-on: ${{ matrix.architecture.runner }}
container: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version) || null }}
container: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-5dd7158', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version) || null }}
steps:
- name: Cleanup workspace

View File

@@ -147,7 +147,6 @@ git sparse-checkout set recipes/snappy
git sparse-checkout add recipes/soci
git fetch origin master
git checkout master
conan export --version 2.4.1 external/wamr # TODO: needs to be added to the conan center index
conan export --version 1.1.10 recipes/snappy/all
conan export --version 4.0.3 recipes/soci/all
rm -rf .git

View File

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

View File

@@ -16,16 +16,13 @@ set(CMAKE_CXX_EXTENSIONS OFF)
target_compile_definitions (common
INTERFACE
$<$<CONFIG:Debug>:DEBUG _DEBUG>
#[===[
NOTE: CMAKE release builds already have NDEBUG defined, so no need to add it
explicitly except for the special case of (profile ON) and (assert OFF).
Presumably this is because we don't want profile builds asserting unless
asserts were specifically requested.
]===]
$<$<AND:$<BOOL:${profile}>,$<NOT:$<BOOL:${assert}>>>:NDEBUG>
# TODO: Remove once we have migrated functions from OpenSSL 1.x to 3.x.
OPENSSL_SUPPRESS_DEPRECATED
)
$<$<AND:$<BOOL:${profile}>,$<NOT:$<BOOL:${assert}>>>:NDEBUG>)
# ^^^^ NOTE: CMAKE release builds already have NDEBUG
# defined, so no need to add it explicitly except for
# this special case of (profile ON) and (assert OFF)
# -- presumably this is because we don't want profile
# builds asserting unless asserts were specifically
# requested
if (MSVC)
# remove existing exception flag since we set it to -EHa

View File

@@ -65,14 +65,8 @@ target_link_libraries(xrpl.imports.main
xrpl.libpb
xxHash::xxhash
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp>
wamr::wamr
)
if (WIN32)
target_link_libraries(xrpl.imports.main INTERFACE ntdll)
endif()
include(add_module)
include(target_link_modules)

View File

@@ -3,14 +3,13 @@
"requires": [
"zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1756234269.497",
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1756234289.683",
"wamr/2.4.1#731b101bc8fa06d84e5c84edb4dc41a5%1756223745.11",
"sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1756234266.869",
"soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1756234262.318",
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1756234314.246",
"rocksdb/10.0.1#85537f46e538974d67da0c3977de48ac%1756234304.347",
"re2/20230301#dfd6e2bf050eb90ddd8729cfb4c844a4%1756234257.976",
"protobuf/3.21.12#d927114e28de9f4691a6bbcdd9a529d1%1756234251.614",
"openssl/3.5.2#0c5a5e15ae569f45dff57adcf1770cf7%1756234259.61",
"openssl/1.1.1w#a8f0792d7c5121b954578a7149d23e03%1756223730.729",
"nudb/2.0.9#c62cfd501e57055a7e0d8ee3d5e5427d%1756234237.107",
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1756234228.999",
"libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1756223727.64",
@@ -54,4 +53,4 @@
]
},
"config_requires": []
}
}

View File

@@ -2,7 +2,6 @@ from conan import ConanFile, __version__ as conan_version
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
import re
class Xrpl(ConanFile):
name = 'xrpl'
@@ -28,10 +27,9 @@ class Xrpl(ConanFile):
'grpc/1.50.1',
'libarchive/3.8.1',
'nudb/2.0.9',
'openssl/3.5.2',
'openssl/1.1.1w',
'soci/4.0.3',
'zlib/1.3.1',
'wamr/2.4.1',
]
test_requires = [
@@ -135,7 +133,6 @@ class Xrpl(ConanFile):
self.folders.generators = 'build/generators'
generators = 'CMakeDeps'
def generate(self):
tc = CMakeToolchain(self)
tc.variables['tests'] = self.options.tests
@@ -193,7 +190,6 @@ class Xrpl(ConanFile):
'protobuf::libprotobuf',
'soci::soci',
'sqlite3::sqlite',
'wamr::wamr',
'xxhash::xxhash',
'zlib::zlib',
]

View File

@@ -1,6 +0,0 @@
patches:
2.4.1:
- patch_description: add metering to iwasm interpreter
patch_file: patches/ripp_metering.patch
patch_type: conan

View File

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

View File

@@ -1,901 +0,0 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b28fa89..7d523a3d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-cmake_minimum_required (VERSION 3.14)
+cmake_minimum_required (VERSION 3.20)
option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)
@@ -170,7 +170,7 @@ if (MINGW)
endif ()
if (WIN32)
- target_link_libraries(vmlib PRIVATE ntdll)
+ target_link_libraries(vmlib PUBLIC ntdll)
endif()
set (WAMR_PUBLIC_HEADERS
diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c
index d2621fb2..6c96a844 100644
--- a/core/iwasm/aot/aot_runtime.c
+++ b/core/iwasm/aot/aot_runtime.c
@@ -5611,7 +5611,7 @@ aot_resolve_import_func(AOTModule *module, AOTImportFunc *import_func)
import_func->func_ptr_linked = wasm_native_resolve_symbol(
import_func->module_name, import_func->func_name,
import_func->func_type, &import_func->signature,
- &import_func->attachment, &import_func->call_conv_raw);
+ &import_func->attachment, NULL, &import_func->call_conv_raw);
#if WASM_ENABLE_MULTI_MODULE != 0
if (!import_func->func_ptr_linked) {
if (!wasm_runtime_is_built_in_module(import_func->module_name)) {
diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c
index 269ec577..34eb7c34 100644
--- a/core/iwasm/common/wasm_c_api.c
+++ b/core/iwasm/common/wasm_c_api.c
@@ -3242,10 +3242,20 @@ wasm_func_copy(const wasm_func_t *func)
cloned->func_idx_rt = func->func_idx_rt;
cloned->inst_comm_rt = func->inst_comm_rt;
+ cloned->gas = func->gas;
RETURN_OBJ(cloned, wasm_func_delete)
}
+uint32_t
+wasm_func_set_gas(wasm_func_t *func, uint32_t gas)
+{
+ if(!func) return 0;
+
+ func->gas = gas;
+ return gas;
+}
+
own wasm_functype_t *
wasm_func_type(const wasm_func_t *func)
{
@@ -4998,11 +5008,11 @@ wasm_instance_new_with_args_ex(wasm_store_t *store, const wasm_module_t *module,
goto failed;
}
+ WASMModuleInstance *wasm_module_inst = NULL;
/* create the c-api func import list */
#if WASM_ENABLE_INTERP != 0
if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) {
- WASMModuleInstance *wasm_module_inst =
- (WASMModuleInstance *)instance->inst_comm_rt;
+ wasm_module_inst = (WASMModuleInstance *)instance->inst_comm_rt;
p_func_imports = &(wasm_module_inst->c_api_func_imports);
import_func_count = MODULE_INTERP(module)->import_function_count;
}
@@ -5052,6 +5062,13 @@ wasm_instance_new_with_args_ex(wasm_store_t *store, const wasm_module_t *module,
}
bh_assert(func_import->func_ptr_linked);
+ // fill gas
+ if(wasm_module_inst) {
+ WASMFunctionInstance *fi = wasm_module_inst->e->functions + func_host->func_idx_rt;
+ if(fi) fi->gas = func_host->gas;
+ }
+
+
func_import++;
}
@@ -5389,3 +5406,8 @@ wasm_instance_get_wasm_func_exec_time(const wasm_instance_t *instance,
return -1.0;
#endif
}
+
+wasm_exec_env_t wasm_instance_exec_env(const wasm_instance_t *instance)
+{
+ return wasm_runtime_get_exec_env_singleton(instance->inst_comm_rt);
+}
diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h
index 49a17a96..19a85980 100644
--- a/core/iwasm/common/wasm_c_api_internal.h
+++ b/core/iwasm/common/wasm_c_api_internal.h
@@ -142,6 +142,10 @@ struct wasm_func_t {
void (*finalizer)(void *);
} cb_env;
} u;
+
+ // gas cost for import func
+ uint32 gas;
+
/*
* an index in both functions runtime instance lists
* of interpreter mode and aot mode
diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c
index 47752950..5f26d886 100644
--- a/core/iwasm/common/wasm_exec_env.c
+++ b/core/iwasm/common/wasm_exec_env.c
@@ -86,7 +86,7 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
#endif
#if WASM_ENABLE_INSTRUCTION_METERING != 0
- exec_env->instructions_to_execute = -1;
+ exec_env->instructions_to_execute = INT64_MAX;
#endif
return exec_env;
diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h
index 5d80312f..b2ecce2e 100644
--- a/core/iwasm/common/wasm_exec_env.h
+++ b/core/iwasm/common/wasm_exec_env.h
@@ -89,7 +89,7 @@ typedef struct WASMExecEnv {
#if WASM_ENABLE_INSTRUCTION_METERING != 0
/* instructions to execute */
- int instructions_to_execute;
+ int64 instructions_to_execute;
#endif
#if WASM_ENABLE_FAST_JIT != 0
diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c
index 060bb2c3..9221c36a 100644
--- a/core/iwasm/common/wasm_native.c
+++ b/core/iwasm/common/wasm_native.c
@@ -180,9 +180,9 @@ native_symbol_cmp(const void *native_symbol1, const void *native_symbol2)
((const NativeSymbol *)native_symbol2)->symbol);
}
-static void *
+static NativeSymbol *
lookup_symbol(NativeSymbol *native_symbols, uint32 n_native_symbols,
- const char *symbol, const char **p_signature, void **p_attachment)
+ const char *symbol)
{
NativeSymbol *native_symbol, key = { 0 };
@@ -190,9 +190,7 @@ lookup_symbol(NativeSymbol *native_symbols, uint32 n_native_symbols,
if ((native_symbol = bsearch(&key, native_symbols, n_native_symbols,
sizeof(NativeSymbol), native_symbol_cmp))) {
- *p_signature = native_symbol->signature;
- *p_attachment = native_symbol->attachment;
- return native_symbol->func_ptr;
+ return native_symbol;
}
return NULL;
@@ -205,25 +203,36 @@ lookup_symbol(NativeSymbol *native_symbols, uint32 n_native_symbols,
void *
wasm_native_resolve_symbol(const char *module_name, const char *field_name,
const WASMFuncType *func_type,
- const char **p_signature, void **p_attachment,
+ const char **p_signature, void **p_attachment, uint32_t *gas,
bool *p_call_conv_raw)
{
NativeSymbolsNode *node, *node_next;
const char *signature = NULL;
void *func_ptr = NULL, *attachment = NULL;
+ NativeSymbol *native_symbol = NULL;
node = g_native_symbols_list;
while (node) {
node_next = node->next;
if (!strcmp(node->module_name, module_name)) {
- if ((func_ptr =
+ if ((native_symbol =
lookup_symbol(node->native_symbols, node->n_native_symbols,
- field_name, &signature, &attachment))
+ field_name))
|| (field_name[0] == '_'
- && (func_ptr = lookup_symbol(
+ && (native_symbol = lookup_symbol(
node->native_symbols, node->n_native_symbols,
- field_name + 1, &signature, &attachment))))
- break;
+ field_name + 1))))
+ {
+ func_ptr = native_symbol->func_ptr;
+ if(func_ptr)
+ {
+ if(gas)
+ *gas = native_symbol->gas;
+ signature = native_symbol->signature;
+ attachment = native_symbol->attachment;
+ break;
+ }
+ }
}
node = node_next;
}
diff --git a/core/iwasm/common/wasm_native.h b/core/iwasm/common/wasm_native.h
index 9a6afee1..0fe4739f 100644
--- a/core/iwasm/common/wasm_native.h
+++ b/core/iwasm/common/wasm_native.h
@@ -52,7 +52,7 @@ wasm_native_lookup_libc_builtin_global(const char *module_name,
void *
wasm_native_resolve_symbol(const char *module_name, const char *field_name,
const WASMFuncType *func_type,
- const char **p_signature, void **p_attachment,
+ const char **p_signature, void **p_attachment, uint32_t *gas,
bool *p_call_conv_raw);
bool
diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c
index 943b46fc..d026777e 100644
--- a/core/iwasm/common/wasm_runtime_common.c
+++ b/core/iwasm/common/wasm_runtime_common.c
@@ -2344,10 +2344,18 @@ wasm_runtime_access_exce_check_guard_page()
#if WASM_ENABLE_INSTRUCTION_METERING != 0
void
wasm_runtime_set_instruction_count_limit(WASMExecEnv *exec_env,
- int instructions_to_execute)
+ int64 instructions_to_execute)
{
+ if(instructions_to_execute == -1)
+ instructions_to_execute = INT64_MAX;
exec_env->instructions_to_execute = instructions_to_execute;
}
+
+int64
+wasm_runtime_get_instruction_count_limit(WASMExecEnv *exec_env)
+{
+ return exec_env->instructions_to_execute;
+}
#endif
WASMFuncType *
@@ -7412,7 +7420,7 @@ wasm_runtime_is_import_func_linked(const char *module_name,
const char *func_name)
{
return wasm_native_resolve_symbol(module_name, func_name, NULL, NULL, NULL,
- NULL);
+ NULL, NULL);
}
bool
@@ -7869,13 +7877,14 @@ wasm_runtime_get_module_name(wasm_module_t module)
bool
wasm_runtime_detect_native_stack_overflow(WASMExecEnv *exec_env)
{
+#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
uint8 *boundary = exec_env->native_stack_boundary;
RECORD_STACK_USAGE(exec_env, (uint8 *)&boundary);
if (boundary == NULL) {
/* the platform doesn't support os_thread_get_stack_boundary */
return true;
}
-#if defined(OS_ENABLE_HW_BOUND_CHECK) && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
+#if defined(OS_ENABLE_HW_BOUND_CHECK)
uint32 page_size = os_getpagesize();
uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
boundary = boundary + page_size * guard_page_count;
@@ -7885,6 +7894,7 @@ wasm_runtime_detect_native_stack_overflow(WASMExecEnv *exec_env)
"native stack overflow");
return false;
}
+#endif
return true;
}
@@ -7907,7 +7917,7 @@ wasm_runtime_detect_native_stack_overflow_size(WASMExecEnv *exec_env,
boundary = boundary - WASM_STACK_GUARD_SIZE + requested_size;
if ((uint8 *)&boundary < boundary) {
wasm_runtime_set_exception(wasm_runtime_get_module_inst(exec_env),
- "native stack overflow");
+ "native s stack overflow");
return false;
}
return true;
diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h
index 324620be..54155a0c 100644
--- a/core/iwasm/common/wasm_runtime_common.h
+++ b/core/iwasm/common/wasm_runtime_common.h
@@ -833,7 +833,10 @@ wasm_runtime_set_native_stack_boundary(WASMExecEnv *exec_env,
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN void
wasm_runtime_set_instruction_count_limit(WASMExecEnv *exec_env,
- int instructions_to_execute);
+ int64 instructions_to_execute);
+WASM_RUNTIME_API_EXTERN int64
+wasm_runtime_get_instruction_count_limit(WASMExecEnv *exec_env);
+
#endif
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
diff --git a/core/iwasm/include/lib_export.h b/core/iwasm/include/lib_export.h
index 0ca668f5..93bcf807 100644
--- a/core/iwasm/include/lib_export.h
+++ b/core/iwasm/include/lib_export.h
@@ -24,6 +24,8 @@ typedef struct NativeSymbol {
/* attachment which can be retrieved in native API by
calling wasm_runtime_get_function_attachment(exec_env) */
void *attachment;
+ // gas cost for import func
+ uint32_t gas;
} NativeSymbol;
/* clang-format off */
diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h
index 241a0eec..1141744c 100644
--- a/core/iwasm/include/wasm_c_api.h
+++ b/core/iwasm/include/wasm_c_api.h
@@ -19,8 +19,10 @@
#if defined(_MSC_BUILD)
#if defined(COMPILING_WASM_RUNTIME_API)
#define WASM_API_EXTERN __declspec(dllexport)
-#else
+#elif defined(_DLL)
#define WASM_API_EXTERN __declspec(dllimport)
+#else
+#define WASM_API_EXTERN
#endif
#else
#define WASM_API_EXTERN
@@ -592,6 +594,8 @@ WASM_API_EXTERN size_t wasm_func_result_arity(const wasm_func_t*);
WASM_API_EXTERN own wasm_trap_t* wasm_func_call(
const wasm_func_t*, const wasm_val_vec_t* args, wasm_val_vec_t* results);
+WASM_API_EXTERN own uint32_t wasm_func_set_gas(wasm_func_t*, uint32_t);
+
// Global Instances
@@ -701,6 +705,11 @@ WASM_API_EXTERN double wasm_instance_sum_wasm_exec_time(const wasm_instance_t*);
// func_name. If the function is not found, return 0.
WASM_API_EXTERN double wasm_instance_get_wasm_func_exec_time(const wasm_instance_t*, const char *);
+struct WASMExecEnv;
+typedef struct WASMExecEnv *wasm_exec_env_t;
+
+WASM_API_EXTERN wasm_exec_env_t wasm_instance_exec_env(const wasm_instance_t*);
+
///////////////////////////////////////////////////////////////////////////////
// Convenience
diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h
index 81efb8f6..f752a970 100644
--- a/core/iwasm/include/wasm_export.h
+++ b/core/iwasm/include/wasm_export.h
@@ -20,8 +20,10 @@
#if defined(_MSC_BUILD)
#if defined(COMPILING_WASM_RUNTIME_API)
#define WASM_RUNTIME_API_EXTERN __declspec(dllexport)
-#else
+#elif defined(_DLL)
#define WASM_RUNTIME_API_EXTERN __declspec(dllimport)
+#else
+#define WASM_RUNTIME_API_EXTERN
#endif
#elif defined(__GNUC__) || defined(__clang__)
#define WASM_RUNTIME_API_EXTERN __attribute__((visibility("default")))
@@ -1874,7 +1876,14 @@ wasm_runtime_set_native_stack_boundary(wasm_exec_env_t exec_env,
*/
WASM_RUNTIME_API_EXTERN void
wasm_runtime_set_instruction_count_limit(wasm_exec_env_t exec_env,
- int instruction_count);
+ int64_t instruction_count);
+
+WASM_RUNTIME_API_EXTERN int64_t
+wasm_runtime_get_instruction_count_limit(wasm_exec_env_t exec_env);
+
+WASM_RUNTIME_API_EXTERN void
+wasm_runtime_set_instruction_schedule(wasm_exec_env_t exec_env,
+ int64_t const *instructions_schedule);
/**
* Dump runtime memory consumption, including:
diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h
index 0dd73958..b7cad5f2 100644
--- a/core/iwasm/interpreter/wasm.h
+++ b/core/iwasm/interpreter/wasm.h
@@ -617,6 +617,9 @@ typedef struct WASMFunctionImport {
WASMModule *import_module;
WASMFunction *import_func_linked;
#endif
+ // gas cost for import func
+ uint32 gas;
+
} WASMFunctionImport;
#if WASM_ENABLE_TAGS != 0
diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c
index edc473f2..55071613 100644
--- a/core/iwasm/interpreter/wasm_interp_classic.c
+++ b/core/iwasm/interpreter/wasm_interp_classic.c
@@ -1547,13 +1547,14 @@ get_global_addr(uint8 *global_data, WASMGlobalInstance *global)
}
#if WASM_ENABLE_INSTRUCTION_METERING != 0
-#define CHECK_INSTRUCTION_LIMIT() \
- if (instructions_left == 0) { \
- wasm_set_exception(module, "instruction limit exceeded"); \
- goto got_exception; \
- } \
- else if (instructions_left > 0) \
- instructions_left--;
+#define CHECK_INSTRUCTION_LIMIT() \
+ do { \
+ --instructions_left; \
+ if (instructions_left < 0) { \
+ wasm_set_exception(module, "instruction limit exceeded"); \
+ goto got_exception; \
+ } \
+ } while (0)
#else
#define CHECK_INSTRUCTION_LIMIT() (void)0
#endif
@@ -1603,10 +1604,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 cache_index, type_index, param_cell_num, cell_num;
#if WASM_ENABLE_INSTRUCTION_METERING != 0
- int instructions_left = -1;
- if (exec_env) {
+ int64 instructions_left = INT64_MAX;
+ if (exec_env)
instructions_left = exec_env->instructions_to_execute;
- }
#endif
#if WASM_ENABLE_EXCE_HANDLING != 0
@@ -6849,6 +6849,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
FREE_FRAME(exec_env, frame);
wasm_exec_env_set_cur_frame(exec_env, prev_frame);
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
+ if(exec_env)
+ exec_env->instructions_to_execute = instructions_left;
+#endif
+
if (!prev_frame->ip) {
/* Called from native. */
return;
@@ -6889,6 +6894,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
}
#endif
SYNC_ALL_TO_FRAME();
+
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
+ if(exec_env)
+ exec_env->instructions_to_execute = instructions_left;
+#endif
+
return;
#if WASM_ENABLE_LABELS_AS_VALUES == 0
diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c
index 36d4538f..4d03603e 100644
--- a/core/iwasm/interpreter/wasm_interp_fast.c
+++ b/core/iwasm/interpreter/wasm_interp_fast.c
@@ -90,14 +90,14 @@ typedef float64 CellType_F64;
} while (0)
#if WASM_ENABLE_INSTRUCTION_METERING != 0
-#define CHECK_INSTRUCTION_LIMIT() \
- if (instructions_left == 0) { \
- wasm_set_exception(module, "instruction limit exceeded"); \
- goto got_exception; \
- } \
- else if (instructions_left > 0) \
- instructions_left--;
-
+#define CHECK_INSTRUCTION_LIMIT() \
+ do { \
+ --instructions_left; \
+ if (instructions_left < 0) { \
+ wasm_set_exception(module, "instruction limit exceeded"); \
+ goto got_exception; \
+ } \
+ } while (0)
#else
#define CHECK_INSTRUCTION_LIMIT() (void)0
#endif
@@ -1438,7 +1438,6 @@ wasm_interp_dump_op_count()
do { \
const void *p_label_addr = *(void **)frame_ip; \
frame_ip += sizeof(void *); \
- CHECK_INSTRUCTION_LIMIT(); \
goto *p_label_addr; \
} while (0)
#else
@@ -1450,7 +1449,6 @@ wasm_interp_dump_op_count()
/* int32 relative offset was emitted in 64-bit target */ \
p_label_addr = label_base + (int32)LOAD_U32_WITH_2U16S(frame_ip); \
frame_ip += sizeof(int32); \
- CHECK_INSTRUCTION_LIMIT(); \
goto *p_label_addr; \
} while (0)
#else
@@ -1461,17 +1459,18 @@ wasm_interp_dump_op_count()
/* uint32 label address was emitted in 32-bit target */ \
p_label_addr = (void *)(uintptr_t)LOAD_U32_WITH_2U16S(frame_ip); \
frame_ip += sizeof(int32); \
- CHECK_INSTRUCTION_LIMIT(); \
goto *p_label_addr; \
} while (0)
#endif
#endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */
-#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
+#define HANDLE_OP_END() CHECK_INSTRUCTION_LIMIT(); FETCH_OPCODE_AND_DISPATCH()
#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
#define HANDLE_OP(opcode) case opcode:
-#define HANDLE_OP_END() continue
+#define HANDLE_OP_END() \
+ CHECK_INSTRUCTION_LIMIT(); \
+ continue
#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
@@ -1540,10 +1539,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint8 opcode = 0, local_type, *global_addr;
#if WASM_ENABLE_INSTRUCTION_METERING != 0
- int instructions_left = -1;
- if (exec_env) {
+ int64 instructions_left = INT64_MAX;
+ if (exec_env)
instructions_left = exec_env->instructions_to_execute;
- }
#endif
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
@@ -4012,7 +4010,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
}
/* constant instructions */
+#ifdef ENABLE_FLOAT_POINT
HANDLE_OP(WASM_OP_F64_CONST)
+#else
+ HANDLE_OP(WASM_OP_F64_CONST)
+ {
+ wasm_set_exception(module, "opcode disabled");
+ goto got_exception;
+ }
+#endif
HANDLE_OP(WASM_OP_I64_CONST)
{
uint8 *orig_ip = frame_ip;
@@ -4025,7 +4031,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
HANDLE_OP_END();
}
+#ifdef ENABLE_FLOAT_POINT
+ HANDLE_OP(WASM_OP_F32_CONST)
+#else
HANDLE_OP(WASM_OP_F32_CONST)
+ {
+ wasm_set_exception(module, "opcode disabled");
+ goto got_exception;
+ }
+#endif
HANDLE_OP(WASM_OP_I32_CONST)
{
uint8 *orig_ip = frame_ip;
@@ -4172,6 +4186,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
HANDLE_OP_END();
}
+#ifdef ENABLE_FLOAT_POINT
+
/* comparison instructions of f32 */
HANDLE_OP(WASM_OP_F32_EQ)
{
@@ -4245,6 +4261,24 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
DEF_OP_CMP(float64, F64, >=);
HANDLE_OP_END();
}
+#else
+ HANDLE_OP(WASM_OP_F32_EQ)
+ HANDLE_OP(WASM_OP_F32_NE)
+ HANDLE_OP(WASM_OP_F32_LT)
+ HANDLE_OP(WASM_OP_F32_GT)
+ HANDLE_OP(WASM_OP_F32_LE)
+ HANDLE_OP(WASM_OP_F32_GE)
+ HANDLE_OP(WASM_OP_F64_EQ)
+ HANDLE_OP(WASM_OP_F64_NE)
+ HANDLE_OP(WASM_OP_F64_LT)
+ HANDLE_OP(WASM_OP_F64_GT)
+ HANDLE_OP(WASM_OP_F64_LE)
+ HANDLE_OP(WASM_OP_F64_GE)
+ {
+ wasm_set_exception(module, "opcode disabled");
+ goto got_exception;
+ }
+#endif
/* numeric instructions of i32 */
HANDLE_OP(WASM_OP_I32_CLZ)
@@ -4573,6 +4607,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
HANDLE_OP_END();
}
+#ifdef ENABLE_FLOAT_POINT
+
/* numeric instructions of f32 */
HANDLE_OP(WASM_OP_F32_ABS)
{
@@ -4784,6 +4820,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
HANDLE_OP_END();
}
+#else
+
+ HANDLE_OP(WASM_OP_F32_ABS)
+ HANDLE_OP(WASM_OP_F32_NEG)
+ HANDLE_OP(WASM_OP_F32_CEIL)
+ HANDLE_OP(WASM_OP_F32_FLOOR)
+ HANDLE_OP(WASM_OP_F32_TRUNC)
+ HANDLE_OP(WASM_OP_F32_NEAREST)
+ HANDLE_OP(WASM_OP_F32_SQRT)
+ HANDLE_OP(WASM_OP_F32_ADD)
+ HANDLE_OP(WASM_OP_F32_SUB)
+ HANDLE_OP(WASM_OP_F32_MUL)
+ HANDLE_OP(WASM_OP_F32_DIV)
+ HANDLE_OP(WASM_OP_F32_MIN)
+ HANDLE_OP(WASM_OP_F32_MAX)
+ HANDLE_OP(WASM_OP_F32_COPYSIGN)
+ HANDLE_OP(WASM_OP_F64_ABS)
+ HANDLE_OP(WASM_OP_F64_NEG)
+ HANDLE_OP(WASM_OP_F64_CEIL)
+ HANDLE_OP(WASM_OP_F64_FLOOR)
+ HANDLE_OP(WASM_OP_F64_TRUNC)
+ HANDLE_OP(WASM_OP_F64_NEAREST)
+ HANDLE_OP(WASM_OP_F64_SQRT)
+ HANDLE_OP(WASM_OP_F64_ADD)
+ HANDLE_OP(WASM_OP_F64_SUB)
+ HANDLE_OP(WASM_OP_F64_MUL)
+ HANDLE_OP(WASM_OP_F64_DIV)
+ HANDLE_OP(WASM_OP_F64_MIN)
+ HANDLE_OP(WASM_OP_F64_MAX)
+ HANDLE_OP(WASM_OP_F64_COPYSIGN)
+ {
+ wasm_set_exception(module, "opcode disabled");
+ goto got_exception;
+ }
+
+#endif //ENABLE_FLOAT_POINT
+
/* conversions of i32 */
HANDLE_OP(WASM_OP_I32_WRAP_I64)
{
@@ -4792,6 +4865,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
HANDLE_OP_END();
}
+
+#ifdef ENABLE_FLOAT_POINT
HANDLE_OP(WASM_OP_I32_TRUNC_S_F32)
{
/* We don't use INT32_MIN/INT32_MAX/UINT32_MIN/UINT32_MAX,
@@ -4821,6 +4896,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
HANDLE_OP_END();
}
+#else
+
+ HANDLE_OP(WASM_OP_I32_TRUNC_S_F32)
+ HANDLE_OP(WASM_OP_I32_TRUNC_U_F32)
+ HANDLE_OP(WASM_OP_I32_TRUNC_S_F64)
+ HANDLE_OP(WASM_OP_I32_TRUNC_U_F64)
+ {
+ wasm_set_exception(module, "opcode disabled");
+ goto got_exception;
+ }
+
+#endif //ENABLE_FLOAT_POINT
+
/* conversions of i64 */
HANDLE_OP(WASM_OP_I64_EXTEND_S_I32)
{
@@ -4834,6 +4922,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
HANDLE_OP_END();
}
+#ifdef ENABLE_FLOAT_POINT
+
HANDLE_OP(WASM_OP_I64_TRUNC_S_F32)
{
DEF_OP_TRUNC_F32(-9223373136366403584.0f,
@@ -4937,6 +5027,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
HANDLE_OP_END();
}
+#else
+ HANDLE_OP(WASM_OP_I64_TRUNC_S_F32)
+ HANDLE_OP(WASM_OP_I64_TRUNC_U_F32)
+ HANDLE_OP(WASM_OP_I64_TRUNC_S_F64)
+ HANDLE_OP(WASM_OP_I64_TRUNC_U_F64)
+ HANDLE_OP(WASM_OP_F32_CONVERT_S_I32)
+ HANDLE_OP(WASM_OP_F32_CONVERT_U_I32)
+ HANDLE_OP(WASM_OP_F32_CONVERT_S_I64)
+ HANDLE_OP(WASM_OP_F32_CONVERT_U_I64)
+ HANDLE_OP(WASM_OP_F32_DEMOTE_F64)
+ HANDLE_OP(WASM_OP_F64_CONVERT_S_I32)
+ HANDLE_OP(WASM_OP_F64_CONVERT_U_I32)
+ HANDLE_OP(WASM_OP_F64_CONVERT_S_I64)
+ HANDLE_OP(WASM_OP_F64_CONVERT_U_I64)
+ HANDLE_OP(WASM_OP_F64_PROMOTE_F32)
+ HANDLE_OP(WASM_OP_I32_REINTERPRET_F32)
+ HANDLE_OP(WASM_OP_F32_REINTERPRET_I32)
+ HANDLE_OP(WASM_OP_I64_REINTERPRET_F64)
+ HANDLE_OP(WASM_OP_F64_REINTERPRET_I64)
+ {
+ wasm_set_exception(module, "opcode disabled");
+ goto got_exception;
+ }
+
+#endif //ENABLE_FLOAT_POINT
+
HANDLE_OP(EXT_OP_COPY_STACK_TOP)
{
addr1 = GET_OFFSET();
@@ -5108,6 +5224,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
{
GET_OPCODE();
switch (opcode) {
+
+#ifdef ENABLE_FLOAT_POINT
case WASM_OP_I32_TRUNC_SAT_S_F32:
DEF_OP_TRUNC_SAT_F32(-2147483904.0f, 2147483648.0f,
true, true);
@@ -5140,6 +5258,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
DEF_OP_TRUNC_SAT_F64(-1.0, 18446744073709551616.0,
false, false);
break;
+
+#endif
+
#if WASM_ENABLE_BULK_MEMORY != 0
case WASM_OP_MEMORY_INIT:
{
@@ -7672,6 +7793,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
{
wasm_interp_call_func_native(module, exec_env, cur_func,
prev_frame);
+ instructions_left -= cur_func->gas;
}
#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0
@@ -7784,6 +7906,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
FREE_FRAME(exec_env, frame);
wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)prev_frame);
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
+ if (exec_env)
+ exec_env->instructions_to_execute = instructions_left;
+#endif
+
if (!prev_frame->ip)
/* Called from native. */
return;
@@ -7812,6 +7939,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
got_exception:
SYNC_ALL_TO_FRAME();
+#if WASM_ENABLE_INSTRUCTION_METERING != 0
+ if (exec_env)
+ exec_env->instructions_to_execute = instructions_left;
+#endif
return;
#if WASM_ENABLE_LABELS_AS_VALUES == 0
diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c
index 771538a1..d6e6a6b8 100644
--- a/core/iwasm/interpreter/wasm_mini_loader.c
+++ b/core/iwasm/interpreter/wasm_mini_loader.c
@@ -805,6 +805,7 @@ load_function_import(const uint8 **p_buf, const uint8 *buf_end,
const char *linked_signature = NULL;
void *linked_attachment = NULL;
bool linked_call_conv_raw = false;
+ uint32_t gas = 0;
read_leb_uint32(p, p_end, declare_type_index);
*p_buf = p;
@@ -816,7 +817,7 @@ load_function_import(const uint8 **p_buf, const uint8 *buf_end,
/* check built-in modules */
linked_func = wasm_native_resolve_symbol(
sub_module_name, function_name, declare_func_type, &linked_signature,
- &linked_attachment, &linked_call_conv_raw);
+ &linked_attachment, &gas, &linked_call_conv_raw);
function->module_name = (char *)sub_module_name;
function->field_name = (char *)function_name;
@@ -825,6 +826,7 @@ load_function_import(const uint8 **p_buf, const uint8 *buf_end,
function->signature = linked_signature;
function->attachment = linked_attachment;
function->call_conv_raw = linked_call_conv_raw;
+ function->gas = gas;
return true;
}
diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c
index b4aa483d..2d74e469 100644
--- a/core/iwasm/interpreter/wasm_runtime.c
+++ b/core/iwasm/interpreter/wasm_runtime.c
@@ -168,7 +168,7 @@ wasm_resolve_import_func(const WASMModule *module, WASMFunctionImport *function)
#endif
function->func_ptr_linked = wasm_native_resolve_symbol(
function->module_name, function->field_name, function->func_type,
- &function->signature, &function->attachment, &function->call_conv_raw);
+ &function->signature, &function->attachment, &function->gas, &function->call_conv_raw);
if (function->func_ptr_linked) {
return true;
@@ -820,6 +820,7 @@ functions_instantiate(const WASMModule *module, WASMModuleInstance *module_inst,
function->param_count =
(uint16)function->u.func_import->func_type->param_count;
function->param_types = function->u.func_import->func_type->types;
+ function->gas = import->u.function.gas;
function->local_cell_num = 0;
function->local_count = 0;
function->local_types = NULL;
diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h
index 16c670f0..5ddac567 100644
--- a/core/iwasm/interpreter/wasm_runtime.h
+++ b/core/iwasm/interpreter/wasm_runtime.h
@@ -237,6 +237,10 @@ struct WASMFunctionInstance {
WASMFunctionImport *func_import;
WASMFunction *func;
} u;
+
+ // gas cost for import func
+ uint32 gas;
+
#if WASM_ENABLE_MULTI_MODULE != 0
WASMModuleInstance *import_module_inst;
WASMFunctionInstance *import_func_inst;
diff --git a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c
index a68c0749..cafb6915 100644
--- a/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c
+++ b/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c
@@ -1038,16 +1038,16 @@ print_f64_wrapper(wasm_exec_env_t exec_env, double f64)
/* clang-format off */
#define REG_NATIVE_FUNC(func_name, signature) \
- { #func_name, func_name##_wrapper, signature, NULL }
+ { #func_name, func_name##_wrapper, signature, NULL, 0 }
/* clang-format on */
static NativeSymbol native_symbols_libc_builtin[] = {
REG_NATIVE_FUNC(printf, "($*)i"),
REG_NATIVE_FUNC(sprintf, "($$*)i"),
REG_NATIVE_FUNC(snprintf, "(*~$*)i"),
- { "vprintf", printf_wrapper, "($*)i", NULL },
- { "vsprintf", sprintf_wrapper, "($$*)i", NULL },
- { "vsnprintf", snprintf_wrapper, "(*~$*)i", NULL },
+ { "vprintf", printf_wrapper, "($*)i", NULL, 0 },
+ { "vsprintf", sprintf_wrapper, "($$*)i", NULL, 0 },
+ { "vsnprintf", snprintf_wrapper, "(*~$*)i", NULL, 0 },
REG_NATIVE_FUNC(puts, "($)i"),
REG_NATIVE_FUNC(putchar, "(i)i"),
REG_NATIVE_FUNC(memcmp, "(**~)i"),
diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c
index f7dfea0b..c01e80a9 100644
--- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c
+++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c
@@ -2269,7 +2269,7 @@ wasi_sched_yield(wasm_exec_env_t exec_env)
/* clang-format off */
#define REG_NATIVE_FUNC(func_name, signature) \
- { #func_name, wasi_##func_name, signature, NULL }
+ { #func_name, wasi_##func_name, signature, NULL, 0 }
/* clang-format on */
static NativeSymbol native_symbols_libc_wasi[] = {
diff --git a/core/shared/platform/include/platform_wasi_types.h b/core/shared/platform/include/platform_wasi_types.h
index ac1a95ea..e23b500e 100644
--- a/core/shared/platform/include/platform_wasi_types.h
+++ b/core/shared/platform/include/platform_wasi_types.h
@@ -36,7 +36,11 @@ extern "C" {
#if WASM_ENABLE_UVWASI != 0 || WASM_ENABLE_LIBC_WASI == 0
#define assert_wasi_layout(expr, message) /* nothing */
#else
-#define assert_wasi_layout(expr, message) _Static_assert(expr, message)
+ #ifndef _MSC_VER
+ #define assert_wasi_layout(expr, message) _Static_assert(expr, message)
+ #else
+ #define assert_wasi_layout(expr, message) static_assert(expr, message)
+ #endif
#endif
assert_wasi_layout(_Alignof(int8_t) == 1, "non-wasi data layout");

View File

@@ -30,6 +30,7 @@
#include <map>
#include <memory>
#include <mutex>
#include <string_view>
#include <utility>
namespace ripple {
@@ -130,27 +131,14 @@ private:
Does nothing if there is no associated system file.
*/
void
write(char const* text);
write(std::string_view text);
/** write to the log file and append an end of line marker.
Does nothing if there is no associated system file.
*/
void
writeln(char const* text);
writeln(std::string_view text);
/** Write to the log file using std::string. */
/** @{ */
void
write(std::string const& str)
{
write(str.c_str());
}
void
writeln(std::string const& str)
{
writeln(str.c_str());
}
/** @} */
private:
@@ -186,6 +174,14 @@ public:
beast::Journal::Sink&
operator[](std::string const& name);
template <typename AttributesFactory>
beast::Journal
journal(std::string const& name, AttributesFactory&& factory)
{
return beast::Journal{
get(name), name, std::forward<AttributesFactory>(factory)};
}
beast::Journal
journal(std::string const& name);
@@ -237,30 +233,34 @@ public:
static LogSeverity
fromString(std::string const& s);
private:
enum {
// Maximum line length for log messages.
// If the message exceeds this length it will be truncated with elipses.
maximumMessageCharacters = 12 * 1024
};
static void
format(
std::string& output,
std::string const& message,
beast::severities::Severity severity,
std::string const& partition);
private:
enum {
// Maximum line length for log messages.
// If the message exceeds this length it will be truncated with elipses.
maximumMessageCharacters = 12 * 1024
};
};
// Wraps a Journal::Stream to skip evaluation of
// expensive argument lists if the stream is not active.
#ifndef JLOG
#define JLOG(x) \
if (!x) \
{ \
} \
else \
x
#define JLOG_JOIN_(a, b) a##b
#define JLOG_JOIN(a, b) JLOG_JOIN_(a, b)
#define JLOG_UNIQUE(base) JLOG_JOIN(base, __LINE__) // line-based unique name
#define JLOG(x) \
if (auto JLOG_UNIQUE(stream) = (x); !JLOG_UNIQUE(stream)) \
{ \
} \
else \
std::move(JLOG_UNIQUE(stream))
#endif
#ifndef CLOG

View File

@@ -360,10 +360,6 @@ abs(Number x) noexcept
Number
power(Number const& f, unsigned n);
// logarithm with base 10
Number
lg(Number const& value);
// Returns f^(1/d)
// Uses NewtonRaphson iterations until the result stops changing
// to find the root of the polynomial g(x) = x^d - f

View File

@@ -22,10 +22,266 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <atomic>
#include <charconv>
#include <cstring>
#include <deque>
#include <mutex>
#include <shared_mutex>
#include <source_location>
#include <sstream>
#include <string>
#include <string_view>
#include <utility>
namespace ripple::log {
template <typename T>
class LogParameter
{
public:
template <typename TArg>
LogParameter(char const* name, TArg&& value)
: name_(name), value_(std::forward<TArg>(value))
{
}
private:
char const* name_;
T value_;
template <typename U>
friend std::ostream&
operator<<(std::ostream& os, LogParameter<U> const&);
};
template <typename T>
class LogField
{
public:
template <typename TArg>
LogField(char const* name, TArg&& value)
: name_(name), value_(std::forward<TArg>(value))
{
}
private:
char const* name_;
T value_;
template <typename U>
friend std::ostream&
operator<<(std::ostream& os, LogField<U> const&);
};
template <typename T>
std::ostream&
operator<<(std::ostream& os, LogField<T> const& param);
template <typename T>
std::ostream&
operator<<(std::ostream& os, LogParameter<T> const& param);
} // namespace ripple::log
namespace beast {
namespace detail {
class SimpleJsonWriter
{
public:
explicit SimpleJsonWriter(std::string* buffer) : buffer_(buffer)
{
}
SimpleJsonWriter() = default;
SimpleJsonWriter(SimpleJsonWriter const& other) = default;
SimpleJsonWriter&
operator=(SimpleJsonWriter const& other) = default;
std::string&
buffer()
{
return *buffer_;
}
void
startObject() const
{
buffer_->push_back('{');
}
void
endObject() const
{
using namespace std::string_view_literals;
if (buffer_->back() == ',')
buffer_->pop_back();
buffer_->append("},"sv);
}
void
writeKey(std::string_view key) const
{
writeString(key);
buffer_->back() = ':';
}
void
startArray() const
{
buffer_->push_back('[');
}
void
endArray() const
{
using namespace std::string_view_literals;
if (buffer_->back() == ',')
buffer_->pop_back();
buffer_->append("],"sv);
}
void
writeString(std::string_view str) const
{
using namespace std::string_view_literals;
buffer_->push_back('"');
escape(str, *buffer_);
buffer_->append("\","sv);
}
std::string_view
writeInt(std::int32_t val) const
{
return pushNumber(val, *buffer_);
}
std::string_view
writeInt(std::int64_t val) const
{
return pushNumber(val, *buffer_);
}
std::string_view
writeUInt(std::uint32_t val) const
{
return pushNumber(val, *buffer_);
}
std::string_view
writeUInt(std::uint64_t val) const
{
return pushNumber(val, *buffer_);
}
std::string_view
writeDouble(double val) const
{
return pushNumber(val, *buffer_);
}
std::string_view
writeBool(bool val) const
{
using namespace std::string_view_literals;
auto str = val ? "true,"sv : "false,"sv;
buffer_->append(str);
return str;
}
void
writeNull() const
{
using namespace std::string_view_literals;
buffer_->append("null,"sv);
}
void
writeRaw(std::string_view str) const
{
buffer_->append(str);
}
void
finish()
{
buffer_->pop_back();
}
private:
template <typename T>
static std::string_view
pushNumber(T val, std::string& str)
{
thread_local char buffer[128];
auto result = std::to_chars(std::begin(buffer), std::end(buffer), val);
auto ptr = result.ptr;
*ptr = ',';
auto len = ptr - std::begin(buffer);
str.append(buffer, len + 1);
return {buffer, static_cast<size_t>(len)};
}
static void
escape(std::string_view str, std::string& buffer)
{
static constexpr char HEX[] = "0123456789ABCDEF";
char const* p = str.data();
char const* end = p + str.size();
char const* chunk = p;
while (p < end)
{
auto c = static_cast<unsigned char>(*p);
// JSON requires escaping for <0x20 and the two specials below.
bool needsEscape = (c < 0x20) || (c == '"') || (c == '\\');
if (!needsEscape)
{
++p;
continue;
}
// Flush the preceding safe run in one go.
if (chunk != p)
buffer.append(chunk, p - chunk);
switch (c)
{
case '"':
buffer.append("\\\"", 2);
break;
case '\\':
buffer.append("\\\\", 2);
break;
case '\b':
buffer.append("\\b", 2);
break;
case '\f':
buffer.append("\\f", 2);
break;
case '\n':
buffer.append("\\n", 2);
break;
case '\r':
buffer.append("\\r", 2);
break;
case '\t':
buffer.append("\\t", 2);
break;
default: {
// Other C0 controls -> \u00XX (JSON compliant)
char buf[6]{
'\\', 'u', '0', '0', HEX[(c >> 4) & 0xF], HEX[c & 0xF]};
buffer.append(buf, 6);
break;
}
}
++p;
chunk = p;
}
// Flush trailing safe run
if (chunk != p)
buffer.append(chunk, p - chunk);
}
std::string* buffer_ = nullptr;
};
} // namespace detail
/** A namespace for easy access to logging severity values. */
namespace severities {
/** Severity level / threshold of a Journal message. */
@@ -42,6 +298,9 @@ enum Severity {
kDisabled,
kNone = kDisabled
};
std::string_view
to_string(Severity severity);
} // namespace severities
/** A generic endpoint for log messages.
@@ -59,18 +318,114 @@ enum Severity {
class Journal
{
public:
template <typename T>
friend std::ostream&
ripple::log::operator<<(
std::ostream& os,
ripple::log::LogField<T> const& param);
template <typename T>
friend std::ostream&
ripple::log::operator<<(
std::ostream& os,
ripple::log::LogParameter<T> const& param);
class Sink;
class JsonLogContext
{
std::string messageBuffer_;
detail::SimpleJsonWriter jsonWriter_;
bool hasMessageParams_ = false;
std::size_t messageOffset_ = 0;
public:
JsonLogContext() : jsonWriter_(&messageBuffer_)
{
messageBuffer_.reserve(4 * 1024);
}
std::string&
messageBuffer()
{
return messageBuffer_;
}
void
startMessageParams()
{
if (!hasMessageParams_)
{
writer().writeKey("Dt");
writer().startObject();
hasMessageParams_ = true;
}
}
void
endMessageParams()
{
if (hasMessageParams_)
{
writer().endObject();
}
}
detail::SimpleJsonWriter&
writer()
{
return jsonWriter_;
}
void
reuseJson();
void
finish();
void
start(
std::source_location location,
severities::Severity severity,
std::string_view moduleName,
std::string_view journalAttributes) noexcept;
};
private:
// Severity level / threshold of a Journal message.
using Severity = severities::Severity;
std::string name_;
std::string attributes_;
static std::string globalLogAttributes_;
static std::shared_mutex globalLogAttributesMutex_;
static bool jsonLogsEnabled_;
static thread_local JsonLogContext currentJsonLogContext_;
// Invariant: m_sink always points to a valid Sink
Sink* m_sink;
Sink* m_sink = nullptr;
void
initMessageContext(
std::source_location location,
severities::Severity severity) const;
static std::string&
formatLog(std::string const& message);
public:
//--------------------------------------------------------------------------
static void
enableStructuredJournal();
static void
disableStructuredJournal();
static bool
isStructuredJournalEnabled();
/** Abstraction for the underlying message destination. */
class Sink
{
@@ -261,11 +616,32 @@ public:
/** Output stream support. */
/** @{ */
ScopedStream
operator<<(std::ostream& manip(std::ostream&)) const;
operator<<(std::ostream& manip(std::ostream&)) const&&
{
return {*this, manip};
}
template <typename T>
ScopedStream
operator<<(T const& t) const;
operator<<(T const& t) const&&
{
return {*this, t};
}
ScopedStream
operator<<(std::ostream& manip(std::ostream&)) const&
{
currentJsonLogContext_.reuseJson();
return {*this, manip};
}
template <typename T>
ScopedStream
operator<<(T const& t) const&
{
currentJsonLogContext_.reuseJson();
return {*this, t};
}
/** @} */
private:
@@ -287,11 +663,73 @@ public:
/** Journal has no default constructor. */
Journal() = delete;
/** Create a journal that writes to the specified sink. */
explicit Journal(Sink& sink) : m_sink(&sink)
Journal(Journal const& other)
: name_(other.name_)
, attributes_(other.attributes_)
, m_sink(other.m_sink)
{
}
template <typename TAttributesFactory>
Journal(Journal const& other, TAttributesFactory&& attributesFactory)
: name_(other.name_), m_sink(other.m_sink)
{
std::string buffer{other.attributes_};
detail::SimpleJsonWriter writer{&buffer};
if (other.attributes_.empty() && jsonLogsEnabled_)
{
writer.startObject();
}
attributesFactory(writer);
attributes_ = std::move(buffer);
}
/** Create a journal that writes to the specified sink. */
explicit Journal(Sink& sink, std::string const& name = {})
: name_(name), m_sink(&sink)
{
}
/** Create a journal that writes to the specified sink. */
template <typename TAttributesFactory>
explicit Journal(
Sink& sink,
std::string const& name,
TAttributesFactory&& attributesFactory)
: name_(name), m_sink(&sink)
{
std::string buffer;
buffer.reserve(128);
detail::SimpleJsonWriter writer{&buffer};
if (jsonLogsEnabled_)
{
writer.startObject();
}
attributesFactory(writer);
attributes_ = std::move(buffer);
}
Journal&
operator=(Journal const& other)
{
if (&other == this)
return *this; // LCOV_EXCL_LINE
m_sink = other.m_sink;
name_ = other.name_;
attributes_ = other.attributes_;
return *this;
}
Journal&
operator=(Journal&& other) noexcept
{
m_sink = other.m_sink;
name_ = std::move(other.name_);
attributes_ = std::move(other.attributes_);
return *this;
}
/** Returns the Sink associated with this Journal. */
Sink&
sink() const
@@ -301,8 +739,11 @@ public:
/** Returns a stream for this sink, with the specified severity level. */
Stream
stream(Severity level) const
stream(
Severity level,
std::source_location location = std::source_location::current()) const
{
initMessageContext(location, level);
return Stream(*m_sink, level);
}
@@ -319,41 +760,69 @@ public:
/** Severity stream access functions. */
/** @{ */
Stream
trace() const
trace(std::source_location location = std::source_location::current()) const
{
initMessageContext(location, severities::kTrace);
return {*m_sink, severities::kTrace};
}
Stream
debug() const
debug(std::source_location location = std::source_location::current()) const
{
initMessageContext(location, severities::kDebug);
return {*m_sink, severities::kDebug};
}
Stream
info() const
info(std::source_location location = std::source_location::current()) const
{
initMessageContext(location, severities::kInfo);
return {*m_sink, severities::kInfo};
}
Stream
warn() const
warn(std::source_location location = std::source_location::current()) const
{
initMessageContext(location, severities::kWarning);
return {*m_sink, severities::kWarning};
}
Stream
error() const
error(std::source_location location = std::source_location::current()) const
{
initMessageContext(location, severities::kError);
return {*m_sink, severities::kError};
}
Stream
fatal() const
fatal(std::source_location location = std::source_location::current()) const
{
initMessageContext(location, severities::kFatal);
return {*m_sink, severities::kFatal};
}
/** @} */
static void
resetGlobalAttributes()
{
std::unique_lock lock(globalLogAttributesMutex_);
globalLogAttributes_.clear();
}
template <typename TAttributesFactory>
static void
addGlobalAttributes(TAttributesFactory&& factory)
{
std::unique_lock lock(globalLogAttributesMutex_);
globalLogAttributes_.reserve(1024);
auto isEmpty = globalLogAttributes_.empty();
detail::SimpleJsonWriter writer{&globalLogAttributes_};
if (isEmpty && jsonLogsEnabled_)
{
writer.startObject();
}
factory(writer);
}
};
#ifndef __INTELLISENSE__
@@ -368,7 +837,7 @@ static_assert(std::is_nothrow_destructible<Journal>::value == true, "");
//------------------------------------------------------------------------------
template <typename T>
Journal::ScopedStream::ScopedStream(Journal::Stream const& stream, T const& t)
Journal::ScopedStream::ScopedStream(Stream const& stream, T const& t)
: ScopedStream(stream.sink(), stream.level())
{
m_ostream << t;
@@ -384,13 +853,6 @@ Journal::ScopedStream::operator<<(T const& t) const
//------------------------------------------------------------------------------
template <typename T>
Journal::ScopedStream
Journal::Stream::operator<<(T const& t) const
{
return ScopedStream(*this, t);
}
namespace detail {
template <class CharT, class Traits = std::char_traits<CharT>>
@@ -460,4 +922,244 @@ using logwstream = basic_logstream<wchar_t>;
} // namespace beast
namespace ripple::log {
namespace detail {
template <typename T>
concept ToCharsFormattable = requires(T val) {
{
to_chars(std::declval<char*>(), std::declval<char*>(), val)
} -> std::convertible_to<std::to_chars_result>;
};
template <typename T>
concept StreamFormattable = requires(T val) {
{
std::declval<std::ostream&>() << val
} -> std::convertible_to<std::ostream&>;
};
template <typename T>
void
setTextValue(
beast::detail::SimpleJsonWriter& writer,
char const* name,
T&& value)
{
using ValueType = std::decay_t<T>;
writer.buffer() += name;
writer.buffer() += ": ";
if constexpr (
std::is_same_v<ValueType, std::string> ||
std::is_same_v<ValueType, std::string_view> ||
std::is_same_v<ValueType, char const*> ||
std::is_same_v<ValueType, char*>)
{
writer.buffer() += value;
}
else
{
std::ostringstream oss;
oss << value;
writer.buffer() += value;
;
}
writer.buffer() += " ";
}
template <typename T>
void
setJsonValue(
beast::detail::SimpleJsonWriter& writer,
char const* name,
T&& value,
std::ostream* outStream)
{
using ValueType = std::decay_t<T>;
writer.writeKey(name);
if constexpr (std::is_same_v<ValueType, bool>)
{
auto sv = writer.writeBool(value);
if (outStream)
{
outStream->write(sv.data(), sv.size());
}
}
else if constexpr (std::is_integral_v<ValueType>)
{
std::string_view sv;
if constexpr (std::is_signed_v<ValueType>)
{
if constexpr (sizeof(ValueType) > 4)
{
sv = writer.writeInt(static_cast<std::int64_t>(value));
}
else
{
sv = writer.writeInt(static_cast<std::int32_t>(value));
}
}
else
{
if constexpr (sizeof(ValueType) > 4)
{
sv = writer.writeUInt(static_cast<std::uint64_t>(value));
}
else
{
sv = writer.writeUInt(static_cast<std::uint32_t>(value));
}
}
if (outStream)
{
outStream->write(sv.data(), sv.size());
}
}
else if constexpr (std::is_floating_point_v<ValueType>)
{
auto sv = writer.writeDouble(value);
if (outStream)
{
outStream->write(sv.data(), sv.size());
}
}
else if constexpr (
std::is_same_v<ValueType, char const*> ||
std::is_same_v<ValueType, char*>)
{
writer.writeString(value);
if (outStream)
{
outStream->write(value, std::strlen(value));
}
}
else if constexpr (
std::is_same_v<ValueType, std::string> ||
std::is_same_v<ValueType, std::string_view>)
{
writer.writeString(value);
if (outStream)
{
outStream->write(value.data(), value.size());
}
}
else
{
if constexpr (ToCharsFormattable<ValueType>)
{
char buffer[1024];
std::to_chars_result result =
to_chars(std::begin(buffer), std::end(buffer), value);
if (result.ec == std::errc{})
{
std::string_view sv{std::begin(buffer), result.ptr};
writer.writeString(sv);
if (outStream)
{
outStream->write(sv.data(), sv.size());
}
return;
}
}
if constexpr (StreamFormattable<ValueType>)
{
std::ostringstream oss;
oss.imbue(std::locale::classic());
oss << value;
auto str = oss.str();
writer.writeString(str);
if (outStream)
{
outStream->write(
str.c_str(), static_cast<std::streamsize>(str.size()));
}
return;
}
static_assert(
ToCharsFormattable<ValueType> || StreamFormattable<ValueType>);
}
}
} // namespace detail
template <typename T>
std::ostream&
operator<<(std::ostream& os, LogParameter<T> const& param)
{
if (!beast::Journal::jsonLogsEnabled_)
{
os << param.value_;
return os;
}
beast::Journal::currentJsonLogContext_.startMessageParams();
detail::setJsonValue(
beast::Journal::currentJsonLogContext_.writer(),
param.name_,
param.value_,
&os);
return os;
}
template <typename T>
std::ostream&
operator<<(std::ostream& os, LogField<T> const& param)
{
if (!beast::Journal::jsonLogsEnabled_)
return os;
beast::Journal::currentJsonLogContext_.startMessageParams();
detail::setJsonValue(
beast::Journal::currentJsonLogContext_.writer(),
param.name_,
param.value_,
nullptr);
return os;
}
template <typename T>
LogParameter<T>
param(char const* name, T&& value)
{
return LogParameter<T>{name, std::forward<T>(value)};
}
template <typename T>
LogField<T>
field(char const* name, T&& value)
{
return LogField<T>{name, std::forward<T>(value)};
}
template <typename... Pair>
[[nodiscard]] auto
attributes(Pair&&... pairs)
{
return [&](beast::detail::SimpleJsonWriter& writer) {
if (beast::Journal::isStructuredJournalEnabled())
{
(detail::setJsonValue(writer, pairs.first, pairs.second, nullptr),
...);
}
else
{
(detail::setTextValue(writer, pairs.first, pairs.second), ...);
}
};
}
template <typename T>
[[nodiscard]] std::pair<char const*, std::decay_t<T>>
attr(char const* name, T&& value)
{
return std::make_pair(name, std::forward<T>(value));
}
} // namespace ripple::log
#endif

View File

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

View File

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

View File

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

View File

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

View File

@@ -231,12 +231,6 @@ page(Keylet const& root, std::uint64_t index = 0) noexcept
Keylet
escrow(AccountID const& src, std::uint32_t seq) noexcept;
inline Keylet
escrow(uint256 const& key) noexcept
{
return {ltESCROW, key};
}
/** A PaymentChannel */
Keylet
payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept;

View File

@@ -74,6 +74,9 @@ public:
Permission&
operator=(Permission const&) = delete;
std::optional<std::string>
getPermissionName(std::uint32_t const value) const;
std::optional<std::uint32_t>
getGranularValue(std::string const& name) const;

View File

@@ -178,13 +178,6 @@ std::size_t constexpr permissionMaxSize = 10;
/** The maximum number of transactions that can be in a batch. */
std::size_t constexpr maxBatchTxCount = 8;
/** The maximum length of a Data field in Escrow object that can be updated by
* Wasm code */
std::size_t constexpr maxWasmDataLength = 4 * 1024;
/** The maximum length of a parameters passed from Wasm code*/
std::size_t constexpr maxWasmParamLength = 1024;
} // namespace ripple
#endif

View File

@@ -72,10 +72,8 @@ class STCurrency;
STYPE(STI_VL, 7) \
STYPE(STI_ACCOUNT, 8) \
STYPE(STI_NUMBER, 9) \
STYPE(STI_INT32, 10) \
STYPE(STI_INT64, 11) \
\
/* 12-13 are reserved */ \
/* 10-13 are reserved */ \
STYPE(STI_OBJECT, 14) \
STYPE(STI_ARRAY, 15) \
\
@@ -358,9 +356,6 @@ using SF_UINT256 = TypedField<STBitString<256>>;
using SF_UINT384 = TypedField<STBitString<384>>;
using SF_UINT512 = TypedField<STBitString<512>>;
using SF_INT32 = TypedField<STInteger<std::int32_t>>;
using SF_INT64 = TypedField<STInteger<std::int64_t>>;
using SF_ACCOUNT = TypedField<STAccount>;
using SF_AMOUNT = TypedField<STAmount>;
using SF_ISSUE = TypedField<STIssue>;

View File

@@ -81,9 +81,6 @@ using STUInt16 = STInteger<std::uint16_t>;
using STUInt32 = STInteger<std::uint32_t>;
using STUInt64 = STInteger<std::uint64_t>;
using STInt32 = STInteger<std::int32_t>;
// using STInt64 = STInteger<std::int64_t>; // Can be added if&when needed
template <typename Integer>
inline STInteger<Integer>::STInteger(Integer v) : value_(v)
{

View File

@@ -231,8 +231,6 @@ public:
getFieldH192(SField const& field) const;
uint256
getFieldH256(SField const& field) const;
std::int32_t
getFieldI32(SField const& field) const;
AccountID
getAccountID(SField const& field) const;
@@ -367,8 +365,6 @@ public:
void
setFieldH256(SField const& field, uint256 const&);
void
setFieldI32(SField const& field, std::int32_t);
void
setFieldVL(SField const& field, Blob const&);
void
setFieldVL(SField const& field, Slice const&);

View File

@@ -54,34 +54,6 @@ public:
Json::Value error;
};
/** Holds the serialized result of parsing an input JSON array.
This does validation and checking on the provided JSON.
*/
class STParsedJSONArray
{
public:
/** Parses and creates an STParsedJSON array.
The result of the parsing is stored in array and error.
Exceptions:
Does not throw.
@param name The name of the JSON field, used in diagnostics.
@param json The JSON-RPC to parse.
*/
STParsedJSONArray(std::string const& name, Json::Value const& json);
STParsedJSONArray() = delete;
STParsedJSONArray(STParsedJSONArray const&) = delete;
STParsedJSONArray&
operator=(STParsedJSONArray const&) = delete;
~STParsedJSONArray() = default;
/** The STArray if the parse was successful. */
std::optional<STArray> array;
/** On failure, an appropriate set of error values. */
Json::Value error;
};
} // namespace ripple
#endif

View File

@@ -141,8 +141,6 @@ enum TEMcodes : TERUnderlyingType {
temARRAY_TOO_LARGE,
temBAD_TRANSFER_FEE,
temINVALID_INNER_BATCH,
temBAD_WASM,
};
//------------------------------------------------------------------------------
@@ -187,8 +185,6 @@ enum TEFcodes : TERUnderlyingType {
tefNO_TICKET,
tefNFTOKEN_IS_NOT_TRANSFERABLE,
tefINVALID_LEDGER_FIX_TYPE,
tefNO_WASM,
tefWASM_FIELD_NOT_INCLUDED,
};
//------------------------------------------------------------------------------
@@ -366,7 +362,6 @@ enum TECcodes : TERUnderlyingType {
tecPSEUDO_ACCOUNT = 196,
tecPRECISION_LOSS = 197,
tecNO_DELEGATE_PERMISSION = 198,
tecWASM_REJECTED = 199,
};
//------------------------------------------------------------------------------

View File

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

View File

@@ -32,12 +32,11 @@
// If you add an amendment here, then do not forget to increment `numFeatures`
// in include/xrpl/protocol/Feature.h.
XRPL_FEATURE(SmartEscrow, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (IncludeKeyletFields, Supported::no, VoteBehavior::DefaultNo)
XRPL_FEATURE(DynamicMPT, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (TokenEscrowV1, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (DelegateV1_1, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (PriceOracleOrder, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (PriceOracleOrder, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (MPTDeliveredAmount, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (AMMClawbackRounding, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(TokenEscrow, Supported::yes, VoteBehavior::DefaultNo)
@@ -48,6 +47,7 @@ XRPL_FEATURE(Batch, Supported::yes, VoteBehavior::DefaultNo
XRPL_FEATURE(SingleAssetVault, Supported::no, VoteBehavior::DefaultNo)
XRPL_FEATURE(PermissionDelegation, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo)
// Check flags in Credential transactions
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (FrozenLPTokenTransfer, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(DeepFreeze, Supported::yes, VoteBehavior::DefaultNo)

View File

@@ -350,8 +350,6 @@ LEDGER_ENTRY(ltESCROW, 0x0075, Escrow, escrow, ({
{sfCondition, soeOPTIONAL},
{sfCancelAfter, soeOPTIONAL},
{sfFinishAfter, soeOPTIONAL},
{sfFinishFunction, soeOPTIONAL},
{sfData, soeOPTIONAL},
{sfSourceTag, soeOPTIONAL},
{sfDestinationTag, soeOPTIONAL},
{sfOwnerNode, soeREQUIRED},

View File

@@ -115,11 +115,6 @@ TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50)
TYPED_SFIELD(sfOracleDocumentID, UINT32, 51)
TYPED_SFIELD(sfPermissionValue, UINT32, 52)
TYPED_SFIELD(sfMutableFlags, UINT32, 53)
TYPED_SFIELD(sfExtensionComputeLimit, UINT32, 54)
TYPED_SFIELD(sfExtensionSizeLimit, UINT32, 55)
TYPED_SFIELD(sfGasPrice, UINT32, 56)
TYPED_SFIELD(sfComputationAllowance, UINT32, 57)
TYPED_SFIELD(sfGasUsed, UINT32, 58)
// 64-bit integers (common)
TYPED_SFIELD(sfIndexNext, UINT64, 1)
@@ -213,9 +208,6 @@ TYPED_SFIELD(sfAssetsMaximum, NUMBER, 3)
TYPED_SFIELD(sfAssetsTotal, NUMBER, 4)
TYPED_SFIELD(sfLossUnrealized, NUMBER, 5)
// 32-bit signed (common)
TYPED_SFIELD(sfWasmReturnCode, INT32, 1)
// currency amount (common)
TYPED_SFIELD(sfAmount, AMOUNT, 1)
TYPED_SFIELD(sfBalance, AMOUNT, 2)
@@ -244,7 +236,7 @@ TYPED_SFIELD(sfBaseFeeDrops, AMOUNT, 22)
TYPED_SFIELD(sfReserveBaseDrops, AMOUNT, 23)
TYPED_SFIELD(sfReserveIncrementDrops, AMOUNT, 24)
// currency amount (more)
// currency amount (AMM)
TYPED_SFIELD(sfLPTokenOut, AMOUNT, 25)
TYPED_SFIELD(sfLPTokenIn, AMOUNT, 26)
TYPED_SFIELD(sfEPrice, AMOUNT, 27)
@@ -252,7 +244,6 @@ TYPED_SFIELD(sfPrice, AMOUNT, 28)
TYPED_SFIELD(sfSignatureReward, AMOUNT, 29)
TYPED_SFIELD(sfMinAccountCreateAmount, AMOUNT, 30)
TYPED_SFIELD(sfLPTokenBalance, AMOUNT, 31)
TYPED_SFIELD(sfFinishFunction, VL, 32)
// variable length (common)
TYPED_SFIELD(sfPublicKey, VL, 1)

View File

@@ -69,13 +69,11 @@ TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate,
noPriv,
({
{sfDestination, soeREQUIRED},
{sfDestinationTag, soeOPTIONAL},
{sfAmount, soeREQUIRED, soeMPTSupported},
{sfCondition, soeOPTIONAL},
{sfCancelAfter, soeOPTIONAL},
{sfFinishAfter, soeOPTIONAL},
{sfFinishFunction, soeOPTIONAL},
{sfData, soeOPTIONAL},
{sfDestinationTag, soeOPTIONAL},
}))
/** This transaction type completes an existing escrow. */
@@ -89,7 +87,6 @@ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish,
{sfFulfillment, soeOPTIONAL},
{sfCondition, soeOPTIONAL},
{sfCredentialIDs, soeOPTIONAL},
{sfComputationAllowance, soeOPTIONAL},
}))

View File

@@ -47,7 +47,6 @@ protected:
Port const& port_;
Handler& handler_;
endpoint_type remote_address_;
beast::WrappedSink sink_;
beast::Journal const j_;
boost::asio::executor_work_guard<boost::asio::executor> work_;
@@ -84,13 +83,13 @@ BasePeer<Handler, Impl>::BasePeer(
: port_(port)
, handler_(handler)
, remote_address_(remote_address)
, sink_(
journal.sink(),
[] {
static std::atomic<unsigned> id{0};
return "##" + std::to_string(++id) + " ";
}())
, j_(sink_)
, j_(journal,
log::attributes(log::attr(
"PeerID",
[] {
static std::atomic<unsigned> id{0};
return "##" + std::to_string(++id) + " ";
}())))
, work_(boost::asio::make_work_guard(executor))
, strand_(boost::asio::make_strand(executor))
{

View File

@@ -113,14 +113,14 @@ Logs::File::close()
}
void
Logs::File::write(char const* text)
Logs::File::write(std::string_view text)
{
if (m_stream != nullptr)
(*m_stream) << text;
}
void
Logs::File::writeln(char const* text)
Logs::File::writeln(std::string_view text)
{
if (m_stream != nullptr)
{
@@ -196,11 +196,15 @@ Logs::write(
bool console)
{
std::string s;
format(s, text, level, partition);
std::string_view result = text;
if (!beast::Journal::isStructuredJournalEnabled())
{
format(s, text, level, partition);
result = text;
}
std::lock_guard lock(mutex_);
file_.writeln(s);
if (!silent_)
std::cerr << s << '\n';
file_.writeln(result);
// VFALCO TODO Fix console output
// if (console)
// out_.write_console(s);

View File

@@ -623,48 +623,6 @@ power(Number const& f, unsigned n)
return r;
}
// Continued fraction approximation of ln(x)
static Number
ln(Number const& x, unsigned iterations = 50)
{
if (x <= 0)
throw std::runtime_error("Not positive value");
Number const z = (x - 1) / (x + 1);
Number const zz = z * z;
Number denom = Number(1, -10);
// Construct the fraction from the bottom up
for (int i = iterations; i > 0; --i)
{
Number k(2 * i - 1);
denom = k - (i * i * zz / denom);
}
auto const r = 2 * z / denom;
return r;
}
Number
lg(Number const& x)
{
static Number const ln10 = ln(Number(10));
if (x <= Number(10))
{
auto const r = ln(x) / ln10;
return r;
}
// ln(x) = ln(normX * 10^norm) = ln(normX) + norm * ln(10)
int diffExp = 15 + x.exponent();
Number const normalX = x / Number(1, diffExp); // (1 <= normalX < 10)
auto const lnX = ln(normalX) + diffExp * ln10;
auto const r = lnX / ln10;
return r;
}
// Returns f^(1/d)
// Uses NewtonRaphson iterations until the result stops changing
// to find the non-negative root of the polynomial g(x) = x^d - f

View File

@@ -19,12 +19,102 @@
#include <xrpl/beast/utility/Journal.h>
#include <chrono>
#include <ios>
#include <ostream>
#include <ranges>
#include <string>
#include <thread>
namespace beast {
namespace {
// Fast timestamp to ISO string conversion
// Returns string like "2024-01-15T10:30:45.123Z"
std::string_view
fastTimestampToString(std::int64_t milliseconds_since_epoch)
{
thread_local char buffer[64]; // "2024-01-15T10:30:45.123Z"
// Precomputed lookup table for 2-digit numbers 00-99
static constexpr char digits[200] = {
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6',
'0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3',
'1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0',
'2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7',
'2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
'3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1',
'4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8',
'4', '9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5',
'5', '6', '5', '7', '5', '8', '5', '9', '6', '0', '6', '1', '6', '2',
'6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
'7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6',
'7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3',
'8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0',
'9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7',
'9', '8', '9', '9'};
constexpr std::int64_t UNIX_EPOCH_DAYS =
719468; // Days from year 0 to 1970-01-01
std::int64_t seconds = milliseconds_since_epoch / 1000;
int ms = milliseconds_since_epoch % 1000;
std::int64_t days = seconds / 86400 + UNIX_EPOCH_DAYS;
int sec_of_day = seconds % 86400;
// Calculate year, month, day from days using Gregorian calendar algorithm
int era = (days >= 0 ? days : days - 146096) / 146097;
int doe = days - era * 146097;
int yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
int year = yoe + era * 400;
int doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
int mp = (5 * doy + 2) / 153;
int day = doy - (153 * mp + 2) / 5 + 1;
int month = mp + (mp < 10 ? 3 : -9);
year += (month <= 2);
// Calculate hour, minute, second
int hour = sec_of_day / 3600;
int min = (sec_of_day % 3600) / 60;
int sec = sec_of_day % 60;
// Format: "2024-01-15T10:30:45.123Z"
buffer[0] = '0' + year / 1000;
buffer[1] = '0' + (year / 100) % 10;
buffer[2] = '0' + (year / 10) % 10;
buffer[3] = '0' + year % 10;
buffer[4] = '-';
buffer[5] = digits[month * 2];
buffer[6] = digits[month * 2 + 1];
buffer[7] = '-';
buffer[8] = digits[day * 2];
buffer[9] = digits[day * 2 + 1];
buffer[10] = 'T';
buffer[11] = digits[hour * 2];
buffer[12] = digits[hour * 2 + 1];
buffer[13] = ':';
buffer[14] = digits[min * 2];
buffer[15] = digits[min * 2 + 1];
buffer[16] = ':';
buffer[17] = digits[sec * 2];
buffer[18] = digits[sec * 2 + 1];
buffer[19] = '.';
buffer[20] = '0' + ms / 100;
buffer[21] = '0' + (ms / 10) % 10;
buffer[22] = '0' + ms % 10;
buffer[23] = 'Z';
return {buffer, 24};
}
} // anonymous namespace
std::string Journal::globalLogAttributes_;
std::shared_mutex Journal::globalLogAttributesMutex_;
bool Journal::jsonLogsEnabled_ = false;
thread_local Journal::JsonLogContext Journal::currentJsonLogContext_{};
//------------------------------------------------------------------------------
// A Sink that does nothing.
@@ -87,6 +177,186 @@ Journal::getNullSink()
//------------------------------------------------------------------------------
std::string_view
severities::to_string(Severity severity)
{
using namespace std::string_view_literals;
switch (severity)
{
case kDisabled:
return "disabled"sv;
case kTrace:
return "trace"sv;
case kDebug:
return "debug"sv;
case kInfo:
return "info"sv;
case kWarning:
return "warning"sv;
case kError:
return "error"sv;
case kFatal:
return "fatal"sv;
default:
UNREACHABLE("Unexpected severity value!");
}
return ""sv;
}
void
Journal::JsonLogContext::start(
std::source_location location,
severities::Severity severity,
std::string_view moduleName,
std::string_view journalAttributes) noexcept
{
struct ThreadIdStringInitializer
{
std::string value;
ThreadIdStringInitializer()
{
std::stringstream threadIdStream;
threadIdStream << std::this_thread::get_id();
value = threadIdStream.str();
}
};
thread_local ThreadIdStringInitializer const threadId;
messageOffset_ = 0;
messageBuffer_.clear();
jsonWriter_ = detail::SimpleJsonWriter{&messageBuffer_};
if (!jsonLogsEnabled_)
{
messageBuffer_ = journalAttributes;
return;
}
writer().startObject();
if (!journalAttributes.empty())
{
writer().writeKey("Jnl");
writer().writeRaw(journalAttributes);
writer().endObject();
}
{
std::shared_lock lock(globalLogAttributesMutex_);
if (!globalLogAttributes_.empty())
{
writer().writeKey("Glb");
writer().writeRaw(globalLogAttributes_);
writer().endObject();
}
}
writer().writeKey("Mtd");
writer().startObject();
writer().writeKey("Mdl");
writer().writeString(moduleName);
writer().writeKey("Fl");
constexpr size_t FILE_NAME_KEEP_CHARS = 20;
std::string_view fileName = location.file_name();
std::string_view trimmedFileName = (fileName.size() > FILE_NAME_KEEP_CHARS)
? fileName.substr(fileName.size() - FILE_NAME_KEEP_CHARS)
: fileName;
writer().writeString(trimmedFileName);
writer().writeKey("Ln");
writer().writeUInt(location.line());
writer().writeKey("ThId");
writer().writeString(threadId.value);
auto severityStr = to_string(severity);
writer().writeKey("Lv");
writer().writeString(severityStr);
auto nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
writer().writeKey("Tm");
writer().writeString(fastTimestampToString(nowMs));
writer().endObject();
hasMessageParams_ = false;
}
void
Journal::JsonLogContext::reuseJson()
{
messageOffset_ = messageBuffer_.size();
}
void
Journal::JsonLogContext::finish()
{
if (messageOffset_ != 0)
{
messageBuffer_.erase(messageOffset_);
}
else
{
messageBuffer_.clear();
}
jsonWriter_ = detail::SimpleJsonWriter{&messageBuffer_};
}
void
Journal::initMessageContext(
std::source_location location,
severities::Severity severity) const
{
currentJsonLogContext_.start(location, severity, name_, attributes_);
}
std::string&
Journal::formatLog(std::string const& message)
{
if (!jsonLogsEnabled_)
{
currentJsonLogContext_.writer().buffer() += message;
return currentJsonLogContext_.messageBuffer();
}
auto& writer = currentJsonLogContext_.writer();
currentJsonLogContext_.endMessageParams();
writer.writeKey("Msg");
writer.writeString(message);
writer.endObject();
writer.finish();
return currentJsonLogContext_.messageBuffer();
}
void
Journal::enableStructuredJournal()
{
jsonLogsEnabled_ = true;
}
void
Journal::disableStructuredJournal()
{
jsonLogsEnabled_ = false;
resetGlobalAttributes();
}
bool
Journal::isStructuredJournalEnabled()
{
return jsonLogsEnabled_;
}
Journal::Sink::Sink(Severity thresh, bool console)
: thresh_(thresh), m_console(console)
{
@@ -143,13 +413,14 @@ Journal::ScopedStream::ScopedStream(
Journal::ScopedStream::~ScopedStream()
{
std::string const& s(m_ostream.str());
std::string s = m_ostream.str();
if (!s.empty())
{
if (s == "\n")
m_sink.write(m_level, "");
else
m_sink.write(m_level, s);
s = "";
m_sink.write(m_level, formatLog(s));
currentJsonLogContext_.finish();
}
}
@@ -159,12 +430,4 @@ Journal::ScopedStream::operator<<(std::ostream& manip(std::ostream&)) const
return m_ostream << manip;
}
//------------------------------------------------------------------------------
Journal::ScopedStream
Journal::Stream::operator<<(std::ostream& manip(std::ostream&)) const
{
return ScopedStream(*this, manip);
}
} // namespace beast

View File

@@ -116,8 +116,6 @@ ApplyStateTable::apply(
TER ter,
std::optional<STAmount> const& deliver,
std::optional<uint256 const> const& parentBatchId,
std::optional<std::uint32_t> const& gasUsed,
std::optional<std::int32_t> const& wasmReturnCode,
bool isDryRun,
beast::Journal j)
{
@@ -128,16 +126,11 @@ ApplyStateTable::apply(
std::optional<TxMeta> metadata;
if (!to.open() || isDryRun)
{
TxMeta meta(tx.getTransactionID(), to.seq());
TxMeta meta(tx.getTransactionID(), to.seq(), parentBatchId);
if (deliver)
meta.setDeliveredAmount(*deliver);
if (parentBatchId)
meta.setParentBatchId(*parentBatchId);
if (gasUsed)
meta.setGasUsed(*gasUsed);
if (wasmReturnCode)
meta.setWasmReturnCode(*wasmReturnCode);
Mods newMod;
for (auto& item : items_)
{

View File

@@ -35,16 +35,7 @@ ApplyViewImpl::apply(
bool isDryRun,
beast::Journal j)
{
return items_.apply(
to,
tx,
ter,
deliver_,
parentBatchId,
gasUsed_,
wasmReturnCode_,
isDryRun,
j);
return items_.apply(to, tx, ter, deliver_, parentBatchId, isDryRun, j);
}
std::size_t

View File

@@ -383,7 +383,7 @@ public:
static boost::regex reStatus{
"\\`HTTP/1\\S+ (\\d{3}) .*\\'"}; // HTTP/1.1 200 OK
static boost::regex reSize{
"\\`.*\\r\\nContent-Length:\\s+([0-9]+).*\\'"};
"\\`.*\\r\\nContent-Length:\\s+([0-9]+).*\\'", boost::regex::icase};
static boost::regex reBody{"\\`.*\\r\\n\\r\\n(.*)\\'"};
boost::smatch smMatch;

View File

@@ -58,6 +58,13 @@ setSTNumberSwitchover(bool v)
*getStaticSTNumberSwitchover() = v;
}
/* The range for the mantissa when normalized */
static std::int64_t constexpr minMantissa = 1000000000000000ull;
static std::int64_t constexpr maxMantissa = 9999999999999999ull;
/* The range for the exponent when normalized */
static int constexpr minExponent = -96;
static int constexpr maxExponent = 80;
IOUAmount
IOUAmount::minPositiveAmount()
{
@@ -305,8 +312,7 @@ mulRatio(
{
if (!result)
{
return IOUAmount(
-IOUAmount::minMantissa, IOUAmount::minExponent);
return IOUAmount(-minMantissa, minExponent);
}
// This subtraction cannot underflow because `result` is not zero
return IOUAmount(result.mantissa() - 1, result.exponent());

View File

@@ -101,6 +101,22 @@ Permission::getInstance()
return instance;
}
std::optional<std::string>
Permission::getPermissionName(std::uint32_t const value) const
{
auto const permissionValue = static_cast<GranularPermissionType>(value);
if (auto const granular = getGranularName(permissionValue))
return *granular;
// not a granular permission, check if it maps to a transaction type
auto const txType = permissionToTxType(value);
if (auto const* item = TxFormats::getInstance().findByType(txType);
item != nullptr)
return item->getName();
return std::nullopt;
}
std::optional<std::uint32_t>
Permission::getGranularValue(std::string const& name) const
{

View File

@@ -62,8 +62,10 @@ STUInt8::getText() const
if (transResultInfo(TER::fromInt(value_), token, human))
return human;
// LCOV_EXCL_START
JLOG(debugLog().error())
<< "Unknown result code in metadata: " << value_;
// LCOV_EXCL_STOP
}
return std::to_string(value_);
@@ -80,8 +82,10 @@ STUInt8::getJson(JsonOptions) const
if (transResultInfo(TER::fromInt(value_), token, human))
return token;
// LCOV_EXCL_START
JLOG(debugLog().error())
<< "Unknown result code in metadata: " << value_;
// LCOV_EXCL_STOP
}
return value_;
@@ -171,6 +175,13 @@ template <>
std::string
STUInt32::getText() const
{
if (getFName() == sfPermissionValue)
{
auto const permissionName =
Permission::getInstance().getPermissionName(value_);
if (permissionName)
return *permissionName;
}
return std::to_string(value_);
}
@@ -180,23 +191,10 @@ STUInt32::getJson(JsonOptions) const
{
if (getFName() == sfPermissionValue)
{
auto const permissionValue =
static_cast<GranularPermissionType>(value_);
auto const granular =
Permission::getInstance().getGranularName(permissionValue);
if (granular)
{
return *granular;
}
else
{
auto const txType =
Permission::getInstance().permissionToTxType(value_);
auto item = TxFormats::getInstance().findByType(txType);
if (item != nullptr)
return item->getName();
}
auto const permissionName =
Permission::getInstance().getPermissionName(value_);
if (permissionName)
return *permissionName;
}
return value_;
@@ -251,33 +249,4 @@ STUInt64::getJson(JsonOptions) const
return convertToString(value_, 16); // Convert to base 16
}
//------------------------------------------------------------------------------
template <>
STInteger<std::int32_t>::STInteger(SerialIter& sit, SField const& name)
: STInteger(name, sit.get32())
{
}
template <>
SerializedTypeID
STInt32::getSType() const
{
return STI_INT32;
}
template <>
std::string
STInt32::getText() const
{
return std::to_string(value_);
}
template <>
Json::Value
STInt32::getJson(JsonOptions) const
{
return value_;
}
} // namespace ripple

View File

@@ -647,12 +647,6 @@ STObject::getFieldH256(SField const& field) const
return getFieldByValue<STUInt256>(field);
}
std::int32_t
STObject::getFieldI32(SField const& field) const
{
return getFieldByValue<STInt32>(field);
}
AccountID
STObject::getAccountID(SField const& field) const
{
@@ -767,12 +761,6 @@ STObject::setFieldH256(SField const& field, uint256 const& v)
setFieldUsingSetValue<STUInt256>(field, v);
}
void
STObject::setFieldI32(SField const& field, std::int32_t v)
{
setFieldUsingSetValue<STInt32>(field, v);
}
void
STObject::setFieldV256(SField const& field, STVector256 const& v)
{

View File

@@ -83,7 +83,8 @@ constexpr std::
return static_cast<U1>(value);
}
static std::string
// LCOV_EXCL_START
static inline std::string
make_name(std::string const& object, std::string const& field)
{
if (field.empty())
@@ -92,7 +93,7 @@ make_name(std::string const& object, std::string const& field)
return object + "." + field;
}
static Json::Value
static inline Json::Value
not_an_object(std::string const& object, std::string const& field)
{
return RPC::make_error(
@@ -100,20 +101,20 @@ not_an_object(std::string const& object, std::string const& field)
"Field '" + make_name(object, field) + "' is not a JSON object.");
}
static Json::Value
static inline Json::Value
not_an_object(std::string const& object)
{
return not_an_object(object, "");
}
static Json::Value
static inline Json::Value
not_an_array(std::string const& object)
{
return RPC::make_error(
rpcINVALID_PARAMS, "Field '" + object + "' is not a JSON array.");
}
static Json::Value
static inline Json::Value
unknown_field(std::string const& object, std::string const& field)
{
return RPC::make_error(
@@ -121,7 +122,7 @@ unknown_field(std::string const& object, std::string const& field)
"Field '" + make_name(object, field) + "' is unknown.");
}
static Json::Value
static inline Json::Value
out_of_range(std::string const& object, std::string const& field)
{
return RPC::make_error(
@@ -129,7 +130,7 @@ out_of_range(std::string const& object, std::string const& field)
"Field '" + make_name(object, field) + "' is out of range.");
}
static Json::Value
static inline Json::Value
bad_type(std::string const& object, std::string const& field)
{
return RPC::make_error(
@@ -137,7 +138,7 @@ bad_type(std::string const& object, std::string const& field)
"Field '" + make_name(object, field) + "' has bad type.");
}
static Json::Value
static inline Json::Value
invalid_data(std::string const& object, std::string const& field)
{
return RPC::make_error(
@@ -145,13 +146,13 @@ invalid_data(std::string const& object, std::string const& field)
"Field '" + make_name(object, field) + "' has invalid data.");
}
static Json::Value
static inline Json::Value
invalid_data(std::string const& object)
{
return invalid_data(object, "");
}
static Json::Value
static inline Json::Value
array_expected(std::string const& object, std::string const& field)
{
return RPC::make_error(
@@ -159,7 +160,7 @@ array_expected(std::string const& object, std::string const& field)
"Field '" + make_name(object, field) + "' must be a JSON array.");
}
static Json::Value
static inline Json::Value
string_expected(std::string const& object, std::string const& field)
{
return RPC::make_error(
@@ -167,7 +168,7 @@ string_expected(std::string const& object, std::string const& field)
"Field '" + make_name(object, field) + "' must be a string.");
}
static Json::Value
static inline Json::Value
too_deep(std::string const& object)
{
return RPC::make_error(
@@ -175,7 +176,7 @@ too_deep(std::string const& object)
"Field '" + object + "' exceeds nesting depth limit.");
}
static Json::Value
static inline Json::Value
singleton_expected(std::string const& object, unsigned int index)
{
return RPC::make_error(
@@ -184,7 +185,7 @@ singleton_expected(std::string const& object, unsigned int index)
"]' must be an object with a single key/object value.");
}
static Json::Value
static inline Json::Value
template_mismatch(SField const& sField)
{
return RPC::make_error(
@@ -193,7 +194,7 @@ template_mismatch(SField const& sField)
"' contents did not meet requirements for that type.");
}
static Json::Value
static inline Json::Value
non_object_in_array(std::string const& item, Json::UInt index)
{
return RPC::make_error(
@@ -201,6 +202,7 @@ non_object_in_array(std::string const& item, Json::UInt index)
"Item '" + item + "' at index " + std::to_string(index) +
" is not an object. Arrays may only contain objects.");
}
// LCOV_EXCL_STOP
template <class STResult, class Integer>
static std::optional<detail::STVar>
@@ -385,10 +387,13 @@ parseLeaf(
auto const& field = SField::getField(fieldName);
// checked in parseObject
if (field == sfInvalid)
{
// LCOV_EXCL_START
error = unknown_field(json_name, fieldName);
return ret;
// LCOV_EXCL_STOP
}
switch (field.fieldType)
@@ -558,30 +563,6 @@ parseLeaf(
break;
}
case STI_UINT160: {
if (!value.isString())
{
error = bad_type(json_name, fieldName);
return ret;
}
uint160 num;
if (auto const s = value.asString(); !num.parseHex(s))
{
if (!s.empty())
{
error = invalid_data(json_name, fieldName);
return ret;
}
num.zero();
}
ret = detail::make_stvar<STUInt160>(field, num);
break;
}
case STI_UINT192: {
if (!value.isString())
{
@@ -606,6 +587,30 @@ parseLeaf(
break;
}
case STI_UINT160: {
if (!value.isString())
{
error = bad_type(json_name, fieldName);
return ret;
}
uint160 num;
if (auto const s = value.asString(); !num.parseHex(s))
{
if (!s.empty())
{
error = invalid_data(json_name, fieldName);
return ret;
}
num.zero();
}
ret = detail::make_stvar<STUInt160>(field, num);
break;
}
case STI_UINT256: {
if (!value.isString())
{
@@ -630,46 +635,6 @@ parseLeaf(
break;
}
case STI_INT32:
try
{
if (value.isString())
{
ret = detail::make_stvar<STInt32>(
field,
beast::lexicalCastThrow<std::int32_t>(
value.asString()));
}
else if (value.isInt())
{
ret = detail::make_stvar<STInt32>(field, value.asInt());
}
else if (value.isUInt())
{
if (value.asUInt() >
static_cast<std::uint32_t>(
std::numeric_limits<std::int32_t>::max()))
{
error = out_of_range(json_name, fieldName);
return ret;
}
ret = detail::make_stvar<STInt32>(
field, safe_cast<std::int32_t>(value.asInt()));
}
else
{
error = bad_type(json_name, fieldName);
return ret;
}
}
catch (std::exception const&)
{
error = invalid_data(json_name, fieldName);
return ret;
}
break;
case STI_VL:
if (!value.isString())
{
@@ -800,6 +765,12 @@ parseLeaf(
AccountID uAccount, uIssuer;
Currency uCurrency;
if (!account && !currency && !issuer)
{
error = invalid_data(element_name);
return ret;
}
if (account)
{
// human account id
@@ -1149,7 +1120,8 @@ parseArray(
Json::Value const objectFields(json[i][objectName]);
std::stringstream ss;
ss << json_name << "." << "[" << i << "]." << objectName;
ss << json_name << "."
<< "[" << i << "]." << objectName;
auto ret = parseObject(
ss.str(), objectFields, nameField, depth + 1, error);
@@ -1192,24 +1164,4 @@ STParsedJSONObject::STParsedJSONObject(
object = parseObject(name, json, sfGeneric, 0, error);
}
//------------------------------------------------------------------------------
STParsedJSONArray::STParsedJSONArray(
std::string const& name,
Json::Value const& json)
{
using namespace STParsedJSONDetail;
auto arr = parseArray(name, json, sfGeneric, 0, error);
if (!arr)
array.reset();
else
{
auto p = dynamic_cast<STArray*>(&arr->get());
if (p == nullptr)
array.reset();
else
array = std::move(*p);
}
}
} // namespace ripple

View File

@@ -208,9 +208,6 @@ STVar::constructST(SerializedTypeID id, int depth, Args&&... args)
case STI_UINT256:
construct<STUInt256>(std::forward<Args>(args)...);
return;
case STI_INT32:
construct<STInt32>(std::forward<Args>(args)...);
return;
case STI_VECTOR256:
construct<STVector256>(std::forward<Args>(args)...);
return;

View File

@@ -83,18 +83,6 @@ Serializer::addInteger(std::uint64_t i)
{
return add64(i);
}
template <>
int
Serializer::addInteger(std::int32_t i)
{
return add32(i);
}
template <>
int
Serializer::addInteger(std::int64_t i)
{
return add64(i);
}
int
Serializer::addRaw(Blob const& vector)

View File

@@ -128,7 +128,6 @@ transResults()
MAKE_ERROR(tecPSEUDO_ACCOUNT, "This operation is not allowed against a pseudo-account."),
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
MAKE_ERROR(tecNO_DELEGATE_PERMISSION, "Delegated account lacks permission to perform this transaction."),
MAKE_ERROR(tecWASM_REJECTED, "The custom WASM code that was run rejected your transaction."),
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
@@ -152,8 +151,6 @@ transResults()
MAKE_ERROR(tefNO_TICKET, "Ticket is not in ledger."),
MAKE_ERROR(tefNFTOKEN_IS_NOT_TRANSFERABLE, "The specified NFToken is not transferable."),
MAKE_ERROR(tefINVALID_LEDGER_FIX_TYPE, "The LedgerFixType field has an invalid value."),
MAKE_ERROR(tefNO_WASM, "There is no WASM code to run, but a WASM-specific field was included."),
MAKE_ERROR(tefWASM_FIELD_NOT_INCLUDED, "WASM code requires a field to be included that was not included."),
MAKE_ERROR(telLOCAL_ERROR, "Local failure."),
MAKE_ERROR(telBAD_DOMAIN, "Domain too long."),
@@ -223,7 +220,6 @@ transResults()
MAKE_ERROR(temARRAY_TOO_LARGE, "Malformed: Array is too large."),
MAKE_ERROR(temBAD_TRANSFER_FEE, "Malformed: Transfer fee is outside valid range."),
MAKE_ERROR(temINVALID_INNER_BATCH, "Malformed: Invalid inner batch transaction."),
MAKE_ERROR(temBAD_WASM, "Malformed: Provided WASM code is invalid."),
MAKE_ERROR(terRETRY, "Retry transaction."),
MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."),

View File

@@ -56,12 +56,9 @@ TxMeta::TxMeta(
if (obj.isFieldPresent(sfDeliveredAmount))
setDeliveredAmount(obj.getFieldAmount(sfDeliveredAmount));
if (obj.isFieldPresent(sfParentBatchID))
setParentBatchId(obj.getFieldH256(sfParentBatchID));
if (obj.isFieldPresent(sfGasUsed))
setGasUsed(obj.getFieldU32(sfGasUsed));
if (obj.isFieldPresent(sfWasmReturnCode))
setWasmReturnCode(obj.getFieldI32(sfWasmReturnCode));
}
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj)
@@ -85,12 +82,6 @@ TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj)
if (obj.isFieldPresent(sfParentBatchID))
setParentBatchId(obj.getFieldH256(sfParentBatchID));
if (obj.isFieldPresent(sfGasUsed))
setGasUsed(obj.getFieldU32(sfGasUsed));
if (obj.isFieldPresent(sfWasmReturnCode))
setWasmReturnCode(obj.getFieldI32(sfWasmReturnCode));
}
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, Blob const& vec)
@@ -106,11 +97,15 @@ TxMeta::TxMeta(
{
}
TxMeta::TxMeta(uint256 const& transactionID, std::uint32_t ledger)
TxMeta::TxMeta(
uint256 const& transactionID,
std::uint32_t ledger,
std::optional<uint256> parentBatchId)
: mTransactionID(transactionID)
, mLedger(ledger)
, mIndex(static_cast<std::uint32_t>(-1))
, mResult(255)
, mParentBatchId(parentBatchId)
, mNodes(sfAffectedNodes)
{
mNodes.reserve(32);
@@ -258,12 +253,9 @@ TxMeta::getAsObject() const
metaData.emplace_back(mNodes);
if (hasDeliveredAmount())
metaData.setFieldAmount(sfDeliveredAmount, getDeliveredAmount());
if (hasParentBatchId())
metaData.setFieldH256(sfParentBatchID, getParentBatchId());
if (hasGasUsed())
metaData.setFieldU32(sfGasUsed, getGasUsed());
if (hasWasmReturnCode())
metaData.setFieldI32(sfWasmReturnCode, getWasmReturnCode());
return metaData;
}

View File

@@ -17,11 +17,9 @@
*/
//==============================================================================
#include <test/app/wasm_fixtures/fixtures.h>
#include <test/jtx.h>
#include <xrpld/app/tx/applySteps.h>
#include <xrpld/app/wasm/WasmVM.h>
#include <xrpl/ledger/Dir.h>
#include <xrpl/protocol/Feature.h>
@@ -255,6 +253,14 @@ struct Escrow_test : public beast::unit_test::suite
BEAST_EXPECT(sle);
BEAST_EXPECT((*sle)[sfSourceTag] == 1);
BEAST_EXPECT((*sle)[sfDestinationTag] == 2);
if (features[fixIncludeKeyletFields])
{
BEAST_EXPECT((*sle)[sfSequence] == seq);
}
else
{
BEAST_EXPECT(!sle->isFieldPresent(sfSequence));
}
}
void
@@ -296,7 +302,7 @@ struct Escrow_test : public beast::unit_test::suite
{
testcase("Implied Finish Time (without fix1571)");
Env env(*this, features - fix1571);
Env env(*this, testable_amendments() - fix1571);
auto const baseFee = env.current()->fees().base;
env.fund(XRP(5000), "alice", "bob", "carol");
env.close();
@@ -1553,7 +1559,7 @@ struct Escrow_test : public beast::unit_test::suite
Account const alice{"alice"};
Account const bob{"bob"};
Account const carol{"carol"};
Account const dillon{"dillon"};
Account const dillon{"dillon "};
Account const zelda{"zelda"};
char const credType[] = "abcde";
@@ -1695,785 +1701,21 @@ struct Escrow_test : public beast::unit_test::suite
}
}
void
testCreateFinishFunctionPreflight(FeatureBitset features)
{
testcase("Test preflight checks involving FinishFunction");
using namespace jtx;
using namespace std::chrono;
Account const alice{"alice"};
Account const carol{"carol"};
// Tests whether the ledger index is >= 5
// getLedgerSqn() >= 5}
static auto wasmHex = ledgerSqnWasmHex;
{
// featureSmartEscrow disabled
Env env(*this, features - featureSmartEscrow);
env.fund(XRP(5000), alice, carol);
XRPAmount const txnFees = env.current()->fees().base + 1000;
auto escrowCreate = escrow::create(alice, carol, XRP(100));
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::cancel_time(env.now() + 100s),
fee(txnFees),
ter(temDISABLED));
env.close();
}
{
// FinishFunction > max length
Env env(
*this,
envconfig([](std::unique_ptr<Config> cfg) {
cfg->FEES.extension_size_limit = 10; // 10 bytes
return cfg;
}),
features);
XRPAmount const txnFees = env.current()->fees().base + 1000;
// create escrow
env.fund(XRP(5000), alice, carol);
auto escrowCreate = escrow::create(alice, carol, XRP(200));
// 11-byte string
std::string longWasmHex = "00112233445566778899AA";
env(escrowCreate,
escrow::finish_function(longWasmHex),
escrow::cancel_time(env.now() + 100s),
fee(txnFees),
ter(temMALFORMED));
env.close();
}
Env env(
*this,
envconfig([](std::unique_ptr<Config> cfg) {
cfg->START_UP = Config::FRESH;
return cfg;
}),
features);
XRPAmount const txnFees =
env.current()->fees().base * 10 + wasmHex.size() / 2 * 5;
// create escrow
env.fund(XRP(5000), alice, carol);
auto escrowCreate = escrow::create(alice, carol, XRP(300));
// Success situations
{
// FinishFunction + CancelAfter
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::cancel_time(env.now() + 20s),
fee(txnFees));
env.close();
}
{
// FinishFunction + Condition + CancelAfter
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::cancel_time(env.now() + 30s),
escrow::condition(escrow::cb1),
fee(txnFees));
env.close();
}
{
// FinishFunction + FinishAfter + CancelAfter
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::cancel_time(env.now() + 40s),
escrow::finish_time(env.now() + 2s),
fee(txnFees));
env.close();
}
{
// FinishFunction + FinishAfter + Condition + CancelAfter
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::cancel_time(env.now() + 50s),
escrow::condition(escrow::cb1),
escrow::finish_time(env.now() + 2s),
fee(txnFees));
env.close();
}
// Failure situations (i.e. all other combinations)
{
// only FinishFunction
env(escrowCreate,
escrow::finish_function(wasmHex),
fee(txnFees),
ter(temBAD_EXPIRATION));
env.close();
}
{
// FinishFunction + FinishAfter
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::finish_time(env.now() + 2s),
fee(txnFees),
ter(temBAD_EXPIRATION));
env.close();
}
{
// FinishFunction + Condition
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::condition(escrow::cb1),
fee(txnFees),
ter(temBAD_EXPIRATION));
env.close();
}
{
// FinishFunction + FinishAfter + Condition
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::condition(escrow::cb1),
escrow::finish_time(env.now() + 2s),
fee(txnFees),
ter(temBAD_EXPIRATION));
env.close();
}
{
// FinishFunction 0 length
env(escrowCreate,
escrow::finish_function(""),
escrow::cancel_time(env.now() + 60s),
fee(txnFees),
ter(temMALFORMED));
env.close();
}
{
// Not enough fees
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::cancel_time(env.now() + 70s),
fee(txnFees - 1),
ter(telINSUF_FEE_P));
env.close();
}
{
// FinishFunction nonexistent host function
// pub fn finish() -> bool {
// unsafe { host_lib::bad() >= 5 }
// }
auto const badWasmHex =
"0061736d010000000105016000017f02100108686f73745f6c696203626164"
"00000302010005030100100611027f00418080c0000b7f00418080c0000b07"
"2e04066d656d6f727902000666696e69736800010a5f5f646174615f656e64"
"03000b5f5f686561705f6261736503010a09010700100041044a0b004d0970"
"726f64756365727302086c616e6775616765010452757374000c70726f6365"
"737365642d6279010572757374631d312e38352e3120283465623136313235"
"3020323032352d30332d31352900490f7461726765745f6665617475726573"
"042b0f6d757461626c652d676c6f62616c732b087369676e2d6578742b0f72"
"65666572656e63652d74797065732b0a6d756c746976616c7565";
env(escrowCreate,
escrow::finish_function(badWasmHex),
escrow::cancel_time(env.now() + 100s),
fee(txnFees),
ter(temBAD_WASM));
env.close();
}
}
void
testFinishWasmFailures(FeatureBitset features)
{
testcase("EscrowFinish Smart Escrow failures");
using namespace jtx;
using namespace std::chrono;
Account const alice{"alice"};
Account const carol{"carol"};
// Tests whether the ledger index is >= 5
// getLedgerSqn() >= 5}
static auto const& wasmHex = ledgerSqnWasmHex;
{
// featureSmartEscrow disabled
Env env(*this, features - featureSmartEscrow);
env.fund(XRP(5000), alice, carol);
XRPAmount const txnFees =
env.current()->fees().base * 10 + wasmHex.size() / 2 * 5;
env(escrow::finish(carol, alice, 1),
fee(txnFees),
escrow::comp_allowance(4),
ter(temDISABLED));
env.close();
}
{
// ComputationAllowance > max compute limit
Env env(
*this,
envconfig([](std::unique_ptr<Config> cfg) {
cfg->FEES.extension_compute_limit = 1'000; // in gas
return cfg;
}),
features);
env.fund(XRP(5000), alice, carol);
// Run past the flag ledger so that a Fee change vote occurs and
// updates FeeSettings. (It also activates all supported
// amendments.)
for (auto i = env.current()->seq(); i <= 257; ++i)
env.close();
auto const allowance = 1'001;
env(escrow::finish(carol, alice, 1),
fee(env.current()->fees().base + allowance),
escrow::comp_allowance(allowance),
ter(temBAD_LIMIT));
}
Env env(*this, features);
// Run past the flag ledger so that a Fee change vote occurs and
// updates FeeSettings. (It also activates all supported
// amendments.)
for (auto i = env.current()->seq(); i <= 257; ++i)
env.close();
XRPAmount const txnFees =
env.current()->fees().base * 10 + wasmHex.size() / 2 * 5;
env.fund(XRP(5000), alice, carol);
// create escrow
auto const seq = env.seq(alice);
env(escrow::create(alice, carol, XRP(400)),
escrow::finish_function(wasmHex),
escrow::cancel_time(env.now() + 100s),
fee(txnFees));
env.close();
{
// no ComputationAllowance field
env(escrow::finish(carol, alice, seq),
ter(tefWASM_FIELD_NOT_INCLUDED));
}
{
// ComputationAllowance value of 0
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(0),
ter(temBAD_LIMIT));
}
{
// not enough fees
// This function takes 4 gas
// In testing, 1 gas costs 1 drop
auto const finishFee = env.current()->fees().base + 3;
env(escrow::finish(carol, alice, seq),
fee(finishFee),
escrow::comp_allowance(4),
ter(telINSUF_FEE_P));
}
{
// not enough gas
// This function takes 4 gas
// In testing, 1 gas costs 1 drop
auto const finishFee = env.current()->fees().base + 4;
env(escrow::finish(carol, alice, seq),
fee(finishFee),
escrow::comp_allowance(2),
ter(tecFAILED_PROCESSING));
}
{
// ComputationAllowance field included w/no FinishFunction on
// escrow
auto const seq2 = env.seq(alice);
env(escrow::create(alice, carol, XRP(500)),
escrow::finish_time(env.now() + 10s),
escrow::cancel_time(env.now() + 100s));
env.close();
auto const allowance = 100;
env(escrow::finish(carol, alice, seq2),
fee(env.current()->fees().base +
(allowance * env.current()->fees().gasPrice) /
MICRO_DROPS_PER_DROP +
1),
escrow::comp_allowance(allowance),
ter(tefNO_WASM));
}
}
void
testFinishFunction(FeatureBitset features)
{
testcase("Example escrow function");
using namespace jtx;
using namespace std::chrono;
Account const alice{"alice"};
Account const carol{"carol"};
// Tests whether the ledger index is >= 5
// getLedgerSqn() >= 5}
auto const& wasmHex = ledgerSqnWasmHex;
std::uint32_t const allowance = 66;
auto escrowCreate = escrow::create(alice, carol, XRP(600));
auto [createFee, finishFee] = [&]() {
Env env(*this, features);
auto createFee =
env.current()->fees().base * 10 + wasmHex.size() / 2 * 5;
auto finishFee = env.current()->fees().base +
(allowance * env.current()->fees().gasPrice) /
MICRO_DROPS_PER_DROP +
1;
return std::make_pair(createFee, finishFee);
}();
{
// basic FinishFunction situation
Env env(*this, features);
// create escrow
env.fund(XRP(5000), alice, carol);
auto const seq = env.seq(alice);
BEAST_EXPECT(env.ownerCount(alice) == 0);
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::cancel_time(env.now() + 100s),
fee(createFee));
env.close();
if (BEAST_EXPECT(env.ownerCount(alice) == 2))
{
env.require(balance(alice, XRP(4000) - createFee));
env.require(balance(carol, XRP(5000)));
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee),
ter(tecWASM_REJECTED));
env(escrow::finish(alice, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee),
ter(tecWASM_REJECTED));
env(escrow::finish(alice, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee),
ter(tecWASM_REJECTED));
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee),
ter(tecWASM_REJECTED));
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee),
ter(tecWASM_REJECTED));
env.close();
{
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECTS(
env.meta()->getFieldU32(sfGasUsed) == allowance,
std::to_string(env.meta()->getFieldU32(sfGasUsed)));
}
env(escrow::finish(alice, alice, seq),
fee(finishFee),
escrow::comp_allowance(allowance),
ter(tesSUCCESS));
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECTS(
txMeta->getFieldU32(sfGasUsed) == allowance,
std::to_string(txMeta->getFieldU32(sfGasUsed)));
if (BEAST_EXPECT(txMeta->isFieldPresent(sfWasmReturnCode)))
BEAST_EXPECTS(
txMeta->getFieldI32(sfWasmReturnCode) == 5,
std::to_string(txMeta->getFieldI32(sfWasmReturnCode)));
BEAST_EXPECT(env.ownerCount(alice) == 0);
}
}
{
// FinishFunction + Condition
Env env(*this, features);
env.fund(XRP(5000), alice, carol);
BEAST_EXPECT(env.ownerCount(alice) == 0);
auto const seq = env.seq(alice);
// create escrow
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::condition(escrow::cb1),
escrow::cancel_time(env.now() + 100s),
fee(createFee));
env.close();
auto const conditionFinishFee = finishFee +
env.current()->fees().base * (32 + (escrow::fb1.size() / 16));
if (BEAST_EXPECT(env.ownerCount(alice) == 2))
{
env.require(balance(alice, XRP(4000) - createFee));
env.require(balance(carol, XRP(5000)));
// no fulfillment provided, function fails
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee),
ter(tecCRYPTOCONDITION_ERROR));
// fulfillment provided, function fails
env(escrow::finish(carol, alice, seq),
escrow::condition(escrow::cb1),
escrow::fulfillment(escrow::fb1),
escrow::comp_allowance(allowance),
fee(conditionFinishFee),
ter(tecWASM_REJECTED));
if (BEAST_EXPECT(env.meta()->isFieldPresent(sfGasUsed)))
BEAST_EXPECTS(
env.meta()->getFieldU32(sfGasUsed) == allowance,
std::to_string(env.meta()->getFieldU32(sfGasUsed)));
env.close();
// no fulfillment provided, function succeeds
env(escrow::finish(alice, alice, seq),
escrow::comp_allowance(allowance),
fee(conditionFinishFee),
ter(tecCRYPTOCONDITION_ERROR));
// wrong fulfillment provided, function succeeds
env(escrow::finish(alice, alice, seq),
escrow::condition(escrow::cb1),
escrow::fulfillment(escrow::fb2),
escrow::comp_allowance(allowance),
fee(conditionFinishFee),
ter(tecCRYPTOCONDITION_ERROR));
// fulfillment provided, function succeeds, tx succeeds
env(escrow::finish(alice, alice, seq),
escrow::condition(escrow::cb1),
escrow::fulfillment(escrow::fb1),
escrow::comp_allowance(allowance),
fee(conditionFinishFee),
ter(tesSUCCESS));
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECT(txMeta->getFieldU32(sfGasUsed) == allowance);
if (BEAST_EXPECT(txMeta->isFieldPresent(sfWasmReturnCode)))
BEAST_EXPECTS(
txMeta->getFieldI32(sfWasmReturnCode) == 6,
std::to_string(txMeta->getFieldI32(sfWasmReturnCode)));
env.close();
BEAST_EXPECT(env.ownerCount(alice) == 0);
}
}
{
// FinishFunction + FinishAfter
Env env(*this, features);
// create escrow
env.fund(XRP(5000), alice, carol);
auto const seq = env.seq(alice);
BEAST_EXPECT(env.ownerCount(alice) == 0);
auto const ts = env.now() + 97s;
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::finish_time(ts),
escrow::cancel_time(env.now() + 1000s),
fee(createFee));
env.close();
if (BEAST_EXPECT(env.ownerCount(alice) == 2))
{
env.require(balance(alice, XRP(4000) - createFee));
env.require(balance(carol, XRP(5000)));
// finish time hasn't passed, function fails
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee + 1),
ter(tecNO_PERMISSION));
env.close();
// finish time hasn't passed, function succeeds
for (; env.now() < ts; env.close())
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee + 2),
ter(tecNO_PERMISSION));
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee + 1),
ter(tesSUCCESS));
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECT(txMeta->getFieldU32(sfGasUsed) == allowance);
if (BEAST_EXPECT(txMeta->isFieldPresent(sfWasmReturnCode)))
BEAST_EXPECTS(
txMeta->getFieldI32(sfWasmReturnCode) == 13,
std::to_string(txMeta->getFieldI32(sfWasmReturnCode)));
BEAST_EXPECT(env.ownerCount(alice) == 0);
}
}
{
// FinishFunction + FinishAfter #2
Env env(*this, features);
// create escrow
env.fund(XRP(5000), alice, carol);
auto const seq = env.seq(alice);
BEAST_EXPECT(env.ownerCount(alice) == 0);
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::finish_time(env.now() + 2s),
escrow::cancel_time(env.now() + 100s),
fee(createFee));
// Don't close the ledger here
if (BEAST_EXPECT(env.ownerCount(alice) == 2))
{
env.require(balance(alice, XRP(4000) - createFee));
env.require(balance(carol, XRP(5000)));
// finish time hasn't passed, function fails
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee),
ter(tecNO_PERMISSION));
env.close();
// finish time has passed, function fails
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee),
ter(tecWASM_REJECTED));
if (BEAST_EXPECT(env.meta()->isFieldPresent(sfGasUsed)))
BEAST_EXPECTS(
env.meta()->getFieldU32(sfGasUsed) == allowance,
std::to_string(env.meta()->getFieldU32(sfGasUsed)));
env.close();
// finish time has passed, function succeeds, tx succeeds
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee),
ter(tesSUCCESS));
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECT(txMeta->getFieldU32(sfGasUsed) == allowance);
if (BEAST_EXPECT(txMeta->isFieldPresent(sfWasmReturnCode)))
BEAST_EXPECTS(
txMeta->getFieldI32(sfWasmReturnCode) == 6,
std::to_string(txMeta->getFieldI32(sfWasmReturnCode)));
env.close();
BEAST_EXPECT(env.ownerCount(alice) == 0);
}
}
}
void
testAllHostFunctions(FeatureBitset features)
{
testcase("Test all host functions");
using namespace jtx;
using namespace std::chrono;
// TODO: create wasm module for all host functions
static auto wasmHex = allHostFunctionsWasmHex;
Account const alice{"alice"};
Account const carol{"carol"};
{
Env env(*this, features);
// create escrow
env.fund(XRP(5000), alice, carol);
auto const seq = env.seq(alice);
BEAST_EXPECT(env.ownerCount(alice) == 0);
auto escrowCreate = escrow::create(alice, carol, XRP(700));
XRPAmount txnFees =
env.current()->fees().base * 10 + wasmHex.size() / 2 * 5;
env(escrowCreate,
escrow::finish_function(wasmHex),
escrow::finish_time(env.now() + 11s),
escrow::cancel_time(env.now() + 100s),
escrow::data("1000000000"), // 1000 XRP in drops
fee(txnFees));
env.close();
if (BEAST_EXPECT(
env.ownerCount(alice) == (1 + wasmHex.size() / 2 / 500)))
{
env.require(balance(alice, XRP(4000) - txnFees));
env.require(balance(carol, XRP(5000)));
auto const allowance = 1'000'000;
XRPAmount const finishFee = env.current()->fees().base +
(allowance * env.current()->fees().gasPrice) /
MICRO_DROPS_PER_DROP +
1;
// FinishAfter time hasn't passed
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee),
ter(tecNO_PERMISSION));
env.close();
env.close();
env.close();
// reduce the destination balance
env(pay(carol, alice, XRP(4500)));
env.close();
env.close();
env(escrow::finish(alice, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee),
ter(tesSUCCESS));
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta && txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECTS(
txMeta->getFieldU32(sfGasUsed) == 38'571,
std::to_string(txMeta->getFieldU32(sfGasUsed)));
if (BEAST_EXPECT(txMeta->isFieldPresent(sfWasmReturnCode)))
BEAST_EXPECT(txMeta->getFieldI32(sfWasmReturnCode) == 1);
env.close();
BEAST_EXPECT(env.ownerCount(alice) == 0);
}
}
}
void
testKeyletHostFunctions(FeatureBitset features)
{
testcase("Test all keylet host functions");
using namespace jtx;
using namespace std::chrono;
// TODO: create wasm module for all host functions
static auto wasmHex = allKeyletsWasmHex;
Account const alice{"alice"};
Account const carol{"carol"};
{
Env env{*this};
env.fund(XRP(10000), alice, carol);
BEAST_EXPECT(env.seq(alice) == 4);
BEAST_EXPECT(env.ownerCount(alice) == 0);
// base objects that need to be created first
auto const tokenId =
token::getNextID(env, alice, 0, tfTransferable);
env(token::mint(alice, 0u), txflags(tfTransferable));
env(trust(alice, carol["USD"](1'000'000)));
env.close();
BEAST_EXPECT(env.seq(alice) == 6);
BEAST_EXPECT(env.ownerCount(alice) == 2);
// set up a bunch of objects to check their keylets
AMM amm(env, carol, XRP(10), carol["USD"](1000));
env(check::create(alice, carol, XRP(100)));
env(credentials::create(alice, alice, "termsandconditions"));
env(delegate::set(alice, carol, {"TrustSet"}));
env(deposit::auth(alice, carol));
env(did::set(alice), did::data("alice_did"));
env(escrow::create(alice, carol, XRP(800)),
escrow::finish_time(env.now() + 100s));
MPTTester mptTester{env, alice, {.fund = false}};
mptTester.create();
mptTester.authorize({.account = carol});
env(token::createOffer(carol, tokenId, XRP(100)),
token::owner(alice));
env(offer(alice, carol["GBP"](0.1), XRP(100)));
env(create(alice, carol, XRP(1000), 100s, alice.pk()));
pdomain::Credentials credentials{{alice, "first credential"}};
env(pdomain::setTx(alice, credentials));
env(signers(alice, 1, {{carol, 1}}));
env(ticket::create(alice, 1));
Vault vault{env};
auto [tx, _keylet] =
vault.create({.owner = alice, .asset = xrpIssue()});
env(tx);
env.close();
BEAST_EXPECTS(
env.ownerCount(alice) == 16,
std::to_string(env.ownerCount(alice)));
if (BEAST_EXPECTS(
env.seq(alice) == 20, std::to_string(env.seq(alice))))
{
auto const seq = env.seq(alice);
XRPAmount txnFees =
env.current()->fees().base * 10 + wasmHex.size() / 2 * 5;
env(escrow::create(alice, carol, XRP(900)),
escrow::finish_function(wasmHex),
escrow::finish_time(env.now() + 2s),
escrow::cancel_time(env.now() + 100s),
fee(txnFees));
env.close();
env.close();
env.close();
auto const allowance = 137'596;
auto const finishFee = env.current()->fees().base +
(allowance * env.current()->fees().gasPrice) /
MICRO_DROPS_PER_DROP +
1;
env(escrow::finish(carol, alice, seq),
escrow::comp_allowance(allowance),
fee(finishFee));
env.close();
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta && txMeta->isFieldPresent(sfGasUsed)))
{
auto const gasUsed = txMeta->getFieldU32(sfGasUsed);
BEAST_EXPECTS(
gasUsed == allowance, std::to_string(gasUsed));
}
BEAST_EXPECTS(
env.ownerCount(alice) == 16,
std::to_string(env.ownerCount(alice)));
}
}
}
void
testWithFeats(FeatureBitset features)
{
// testEnablement(features);
// testTiming(features);
// testTags(features);
// testDisallowXRP(features);
// test1571(features);
// testFails(features);
// testLockup(features);
// testEscrowConditions(features);
// testMetaAndOwnership(features);
// testConsequences(features);
// testEscrowWithTickets(features);
// testCredentials(features);
testCreateFinishFunctionPreflight(features);
testFinishWasmFailures(features);
testFinishFunction(features);
// TODO: Update module with new host functions
testAllHostFunctions(features);
testKeyletHostFunctions(features);
testEnablement(features);
testTiming(features);
testTags(features);
testDisallowXRP(features);
test1571(features);
testFails(features);
testLockup(features);
testEscrowConditions(features);
testMetaAndOwnership(features);
testConsequences(features);
testEscrowWithTickets(features);
testCredentials(features);
}
public:
@@ -2483,8 +1725,9 @@ public:
using namespace test::jtx;
FeatureBitset const all{testable_amendments()};
testWithFeats(all);
// testWithFeats(all - featureTokenEscrow);
};
testWithFeats(all - featureTokenEscrow);
testTags(all - fixIncludeKeyletFields);
}
};
BEAST_DEFINE_TESTSUITE(Escrow, app, ripple);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -768,6 +768,24 @@ private:
expectUntrusted(lists.at(7));
expectTrusted(lists.at(2));
// try empty or mangled manifest
checkResult(
trustedKeys->applyLists(
"", version, {{blob7, sig7, {}}, {blob6, sig6, {}}}, siteUri),
publisherPublic,
ListDisposition::invalid,
ListDisposition::invalid);
checkResult(
trustedKeys->applyLists(
base64_encode("not a manifest"),
version,
{{blob7, sig7, {}}, {blob6, sig6, {}}},
siteUri),
publisherPublic,
ListDisposition::invalid,
ListDisposition::invalid);
// do not use list from untrusted publisher
auto const untrustedManifest = base64_encode(makeManifestString(
randomMasterKey(),

View File

@@ -1,730 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2025 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifdef _DEBUG
// #define DEBUG_OUTPUT 1
#endif
#include <test/app/TestHostFunctions.h>
#include <xrpld/app/wasm/HostFuncWrapper.h>
#include <xrpld/app/wasm/WamrVM.h>
namespace ripple {
namespace test {
bool
testGetDataIncrement();
using Add_proto = int32_t(int32_t, int32_t);
static wasm_trap_t*
Add(void* env, wasm_val_vec_t const* params, wasm_val_vec_t* results)
{
int32_t Val1 = params->data[0].of.i32;
int32_t Val2 = params->data[1].of.i32;
// printf("Host function \"Add\": %d + %d\n", Val1, Val2);
results->data[0] = WASM_I32_VAL(Val1 + Val2);
return nullptr;
}
struct Wasm_test : public beast::unit_test::suite
{
void
testGetDataHelperFunctions()
{
testcase("getData helper functions");
BEAST_EXPECT(testGetDataIncrement());
}
void
testWasmLib()
{
testcase("wasmtime lib test");
// clang-format off
/* The WASM module buffer. */
Bytes const wasm = {/* WASM header */
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00,
/* Type section */
0x01, 0x07, 0x01,
/* function type {i32, i32} -> {i32} */
0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F,
/* Import section */
0x02, 0x13, 0x01,
/* module name: "extern" */
0x06, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6E,
/* extern name: "func-add" */
0x08, 0x66, 0x75, 0x6E, 0x63, 0x2D, 0x61, 0x64, 0x64,
/* import desc: func 0 */
0x00, 0x00,
/* Function section */
0x03, 0x02, 0x01, 0x00,
/* Export section */
0x07, 0x0A, 0x01,
/* export name: "addTwo" */
0x06, 0x61, 0x64, 0x64, 0x54, 0x77, 0x6F,
/* export desc: func 0 */
0x00, 0x01,
/* Code section */
0x0A, 0x0A, 0x01,
/* code body */
0x08, 0x00, 0x20, 0x00, 0x20, 0x01, 0x10, 0x00, 0x0B};
// clang-format on
auto& vm = WasmEngine::instance();
std::vector<WasmImportFunc> imports;
WasmImpFunc<Add_proto>(
imports, "func-add", reinterpret_cast<void*>(&Add));
auto re = vm.run(wasm, "addTwo", wasmParams(1234, 5678), imports);
// if (res) printf("invokeAdd get the result: %d\n", res.value());
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 6'912, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 2, std::to_string(re->cost));
}
}
void
testBadWasm()
{
testcase("bad wasm test");
using namespace test::jtx;
Env env{*this};
HostFunctions hfs;
{
auto wasmHex = "00000000";
auto wasmStr = boost::algorithm::unhex(std::string(wasmHex));
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
std::string funcName("mock_escrow");
auto re = runEscrowWasm(wasm, funcName, {}, &hfs, 15, env.journal);
BEAST_EXPECT(!re);
}
{
auto wasmHex = "00112233445566778899AA";
auto wasmStr = boost::algorithm::unhex(std::string(wasmHex));
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
std::string funcName("mock_escrow");
auto const re =
preflightEscrowWasm(wasm, funcName, {}, &hfs, env.journal);
BEAST_EXPECT(!isTesSuccess(re));
}
{
// FinishFunction wrong function name
// pub fn bad() -> bool {
// unsafe { host_lib::getLedgerSqn() >= 5 }
// }
auto const badWasmHex =
"0061736d010000000105016000017f02190108686f73745f6c69620c6765"
"744c656467657253716e00000302010005030100100611027f00418080c0"
"000b7f00418080c0000b072b04066d656d6f727902000362616400010a5f"
"5f646174615f656e6403000b5f5f686561705f6261736503010a09010700"
"100041044a0b004d0970726f64756365727302086c616e67756167650104"
"52757374000c70726f6365737365642d6279010572757374631d312e3835"
"2e31202834656231363132353020323032352d30332d31352900490f7461"
"726765745f6665617475726573042b0f6d757461626c652d676c6f62616c"
"732b087369676e2d6578742b0f7265666572656e63652d74797065732b0a"
"6d756c746976616c7565";
auto wasmStr = boost::algorithm::unhex(std::string(badWasmHex));
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
auto const re = preflightEscrowWasm(
wasm, ESCROW_FUNCTION_NAME, {}, &hfs, env.journal);
BEAST_EXPECT(!isTesSuccess(re));
}
}
void
testWasmLedgerSqn()
{
testcase("Wasm get ledger sequence");
auto wasmStr = boost::algorithm::unhex(ledgerSqnWasmHex);
Bytes wasm(wasmStr.begin(), wasmStr.end());
using namespace test::jtx;
Env env{*this};
TestLedgerDataProvider hf(&env);
std::vector<WasmImportFunc> imports;
WASM_IMPORT_FUNC2(imports, getLedgerSqn, "get_ledger_sqn", &hf, 33);
auto& engine = WasmEngine::instance();
auto re = engine.run(
wasm,
ESCROW_FUNCTION_NAME,
{},
imports,
&hf,
1'000'000,
env.journal);
// code takes 11 gas + 1 getLedgerSqn call
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 0, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 39, std::to_string(re->cost));
}
env.close();
env.close();
// empty module - run the same instance
re = engine.run(
{}, ESCROW_FUNCTION_NAME, {}, imports, &hf, 1'000'000, env.journal);
// code takes 22 gas + 2 getLedgerSqn calls
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 5, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 78, std::to_string(re->cost));
}
}
void
testWasmFib()
{
testcase("Wasm fibo");
auto const ws = boost::algorithm::unhex(fibWasmHex);
Bytes const wasm(ws.begin(), ws.end());
auto& engine = WasmEngine::instance();
auto const re = engine.run(wasm, "fib", wasmParams(10));
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 55, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 755, std::to_string(re->cost));
}
}
void
testWasmSha()
{
testcase("Wasm sha");
auto const ws = boost::algorithm::unhex(sha512PureWasmHex);
Bytes const wasm(ws.begin(), ws.end());
auto& engine = WasmEngine::instance();
auto const re =
engine.run(wasm, "sha512_process", wasmParams(sha512PureWasmHex));
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 34'432, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 157'452, std::to_string(re->cost));
}
}
void
testWasmB58()
{
testcase("Wasm base58");
auto const ws = boost::algorithm::unhex(b58WasmHex);
Bytes const wasm(ws.begin(), ws.end());
auto& engine = WasmEngine::instance();
Bytes outb;
outb.resize(1024);
auto const minsz = std::min(
static_cast<std::uint32_t>(512),
static_cast<std::uint32_t>(b58WasmHex.size()));
auto const s = std::string_view(b58WasmHex.c_str(), minsz);
auto const re = engine.run(wasm, "b58enco", wasmParams(outb, s));
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 700, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 3'066'129, std::to_string(re->cost));
}
}
void
testWasmSP1Verifier()
{
testcase("Wasm sp1 zkproof verifier");
auto const ws = boost::algorithm::unhex(sp1WasmHex);
Bytes const wasm(ws.begin(), ws.end());
auto& engine = WasmEngine::instance();
auto const re = engine.run(wasm, "sp1_groth16_verifier");
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
BEAST_EXPECTS(
re->cost == 4'191'711'969ll, std::to_string(re->cost));
}
}
void
testWasmBG16Verifier()
{
testcase("Wasm BG16 zkproof verifier");
auto const ws = boost::algorithm::unhex(zkProofWasmHex);
Bytes const wasm(ws.begin(), ws.end());
auto& engine = WasmEngine::instance();
auto const re = engine.run(wasm, "bellman_groth16_test");
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 332'205'984, std::to_string(re->cost));
}
}
void
testHFCost()
{
testcase("wasm test host functions cost");
using namespace test::jtx;
Env env(*this);
{
std::string const wasmHex = allHostFunctionsWasmHex;
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
auto& engine = WasmEngine::instance();
TestHostFunctions hfs(env, 0);
std::vector<WasmImportFunc> imp = createWasmImport(&hfs);
for (auto& i : imp)
i.gas = 0;
auto re = engine.run(
wasm,
ESCROW_FUNCTION_NAME,
{},
imp,
&hfs,
1'000'000,
env.journal);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 847, std::to_string(re->cost));
}
env.close();
}
env.close();
env.close();
env.close();
env.close();
env.close();
{
std::string const wasmHex = allHostFunctionsWasmHex;
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
auto& engine = WasmEngine::instance();
TestHostFunctions hfs(env, 0);
std::vector<WasmImportFunc> const imp = createWasmImport(&hfs);
auto re = engine.run(
wasm,
ESCROW_FUNCTION_NAME,
{},
imp,
&hfs,
1'000'000,
env.journal);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 40'107, std::to_string(re->cost));
}
env.close();
}
}
void
testEscrowWasmDN()
{
testcase("escrow wasm devnet test");
std::string const wasmStr =
boost::algorithm::unhex(allHostFunctionsWasmHex);
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
using namespace test::jtx;
Env env{*this};
{
TestHostFunctions nfs(env, 0);
auto re =
runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100'000);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 40'107, std::to_string(re->cost));
}
}
{ // fail because trying to access nonexistent field
struct BadTestHostFunctions : public TestHostFunctions
{
explicit BadTestHostFunctions(Env& env) : TestHostFunctions(env)
{
}
Expected<Bytes, HostFunctionError>
getTxField(SField const& fname) override
{
return Unexpected(HostFunctionError::FIELD_NOT_FOUND);
}
};
BadTestHostFunctions nfs(env);
auto re =
runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100'000);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == -201, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 4'806, std::to_string(re->cost));
}
}
{ // fail because trying to allocate more than MAX_PAGES memory
struct BadTestHostFunctions : public TestHostFunctions
{
explicit BadTestHostFunctions(Env& env) : TestHostFunctions(env)
{
}
Expected<Bytes, HostFunctionError>
getTxField(SField const& fname) override
{
return Bytes((MAX_PAGES + 1) * 64 * 1024, 1);
}
};
BadTestHostFunctions nfs(env);
auto re =
runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100'000);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == -201, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 4'806, std::to_string(re->cost));
}
}
{ // fail because recursion too deep
auto const wasmStr = boost::algorithm::unhex(deepRecursionHex);
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
TestHostFunctionsSink nfs(env);
std::string funcName("recursive");
auto re = runEscrowWasm(wasm, funcName, {}, &nfs, 1'000'000'000);
BEAST_EXPECT(!re && re.error());
// std::cout << "bad case (deep recursion) result " << re.error()
// << std::endl;
auto const& sink = nfs.getSink();
auto countSubstr = [](std::string const& str,
std::string const& substr) {
std::size_t pos = 0;
int occurrences = 0;
while ((pos = str.find(substr, pos)) != std::string::npos)
{
occurrences++;
pos += substr.length();
}
return occurrences;
};
auto const s = sink.messages().str();
BEAST_EXPECT(
countSubstr(s, "WAMR Error: failure to call func") == 1);
BEAST_EXPECT(
countSubstr(s, "Exception: wasm operand stack overflow") > 0);
}
{
auto wasmStr = boost::algorithm::unhex(ledgerSqnWasmHex);
Bytes wasm(wasmStr.begin(), wasmStr.end());
TestLedgerDataProvider ledgerDataProvider(&env);
std::vector<WasmImportFunc> imports;
WASM_IMPORT_FUNC2(
imports, getLedgerSqn, "get_ledger_sqn2", &ledgerDataProvider);
auto& engine = WasmEngine::instance();
auto re = engine.run(
wasm,
ESCROW_FUNCTION_NAME,
{},
imports,
nullptr,
1'000'000,
env.journal);
// expected import not provided
BEAST_EXPECT(!re);
}
}
void
testFloat()
{
testcase("float point");
std::string const funcName("finish");
using namespace test::jtx;
Env env(*this);
{
std::string const wasmHex = floatTestsWasmHex;
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
TestHostFunctions hf(env, 0);
auto re = runEscrowWasm(wasm, funcName, {}, &hf, 100'000);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 96'942, std::to_string(re->cost));
}
env.close();
}
{
std::string const wasmHex = float0Hex;
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
TestHostFunctions hf(env, 0);
auto re = runEscrowWasm(wasm, funcName, {}, &hf, 100'000);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 1, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 2'053, std::to_string(re->cost));
}
env.close();
}
}
void
perfTest()
{
testcase("Perf test host functions");
using namespace jtx;
using namespace std::chrono;
// std::string const funcName("test");
auto const& wasmHex = hfPerfTest;
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
// std::string const credType = "abcde";
// std::string const credType2 = "fghijk";
// std::string const credType3 = "0123456";
// char const uri[] = "uri";
Account const alan{"alan"};
Account const bob{"bob"};
Account const issuer{"issuer"};
{
Env env(*this);
// Env env(*this, envconfig(), {}, nullptr,
// beast::severities::kTrace);
env.fund(XRP(5000), alan, bob, issuer);
env.close();
// // create escrow
// auto const seq = env.seq(alan);
// auto const k = keylet::escrow(alan, seq);
// // auto const allowance = 3'600;
// auto escrowCreate = escrow::create(alan, bob, XRP(1000));
// XRPAmount txnFees = env.current()->fees().base + 1000;
// env(escrowCreate,
// escrow::finish_function(wasmHex),
// escrow::finish_time(env.now() + 11s),
// escrow::cancel_time(env.now() + 100s),
// escrow::data("1000000000"), // 1000 XRP in drops
// memodata("memo1234567"),
// memodata("2memo1234567"),
// fee(txnFees));
// // create depositPreauth
// auto const k = keylet::depositPreauth(
// bob,
// {{issuer.id(), makeSlice(credType)},
// {issuer.id(), makeSlice(credType2)},
// {issuer.id(), makeSlice(credType3)}});
// env(deposit::authCredentials(
// bob,
// {{issuer, credType},
// {issuer, credType2},
// {issuer, credType3}}));
// create nft
[[maybe_unused]] uint256 const nft0{
token::getNextID(env, alan, 0u)};
env(token::mint(alan, 0u));
auto const k = keylet::nftoffer(alan, 0);
[[maybe_unused]] uint256 const nft1{
token::getNextID(env, alan, 0u)};
env(token::mint(alan, 0u),
token::uri(
"https://github.com/XRPLF/XRPL-Standards/discussions/"
"279?id=github.com/XRPLF/XRPL-Standards/discussions/"
"279&ut=github.com/XRPLF/XRPL-Standards/discussions/"
"279&sid=github.com/XRPLF/XRPL-Standards/discussions/"
"279&aot=github.com/XRPLF/XRPL-Standards/disc"));
[[maybe_unused]] uint256 const nft2{
token::getNextID(env, alan, 0u)};
env(token::mint(alan, 0u));
env.close();
PerfHostFunctions nfs(env, k, env.tx());
auto re = runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result);
std::cout << "Res: " << re->result << " cost: " << re->cost
<< std::endl;
}
// env(escrow::finish(alan, alan, seq),
// escrow::comp_allowance(allowance),
// fee(txnFees),
// ter(tesSUCCESS));
env.close();
}
}
void
testCodecovWasm()
{
testcase("Codecov wasm test");
using namespace test::jtx;
Env env{*this};
auto const wasmStr = boost::algorithm::unhex(codecovTestsWasmHex);
Bytes const wasm(wasmStr.begin(), wasmStr.end());
TestHostFunctions hfs(env, 0);
auto const allowance = 153'296;
auto re = runEscrowWasm(
wasm, ESCROW_FUNCTION_NAME, {}, &hfs, allowance, env.journal);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result);
BEAST_EXPECTS(re->cost == allowance, std::to_string(re->cost));
}
}
void
testDisabledFloat()
{
testcase("disabled float");
using namespace test::jtx;
Env env{*this};
auto const wasmStr = boost::algorithm::unhex(disabledFloatHex);
Bytes wasm(wasmStr.begin(), wasmStr.end());
std::string const funcName("finish");
TestHostFunctions hfs(env, 0);
{
// f32 set constant, opcode disabled exception
auto const re =
runEscrowWasm(wasm, funcName, {}, &hfs, 1'000'000, env.journal);
if (BEAST_EXPECT(!re.has_value()))
{
BEAST_EXPECT(re.error() == tecFAILED_PROCESSING);
}
}
{
// f32 add, can't create module exception
wasm[0x117] = 0x92;
auto const re =
runEscrowWasm(wasm, funcName, {}, &hfs, 1'000'000, env.journal);
if (BEAST_EXPECT(!re.has_value()))
{
BEAST_EXPECT(re.error() == tecFAILED_PROCESSING);
}
}
}
void
run() override
{
using namespace test::jtx;
testGetDataHelperFunctions();
testWasmLib();
testBadWasm();
testWasmLedgerSqn();
testWasmFib();
testWasmSha();
testWasmB58();
// runing too long
// testWasmSP1Verifier();
testWasmBG16Verifier();
testHFCost();
testEscrowWasmDN();
testFloat();
testCodecovWasm();
testDisabledFloat();
// perfTest();
}
};
BEAST_DEFINE_TESTSUITE(Wasm, app, ripple);
} // namespace test
} // namespace ripple

View File

@@ -1,3 +0,0 @@
**/target
**/debug
*.wasm

View File

@@ -1,15 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "all_host_functions"
version = "0.1.0"
dependencies = [
"xrpl-std",
]
[[package]]
name = "xrpl-std"
version = "0.5.1-devnet5"
source = "git+https://github.com/ripple/craft.git?branch=last-hfs2#ec4a3fb2ea45a7f27b7190976d37d3596e2ec29e"

View File

@@ -1,21 +0,0 @@
[package]
name = "all_host_functions"
version = "0.1.0"
edition = "2024"
# This empty workspace definition keeps this project independent of the parent workspace
[workspace]
[lib]
crate-type = ["cdylib"]
[dependencies]
xrpl-std = { git = "https://github.com/ripple/craft.git", branch = "last-hfs2", package = "xrpl-std" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
opt-level = "z"
lto = true

View File

@@ -1,772 +0,0 @@
#![cfg_attr(target_arch = "wasm32", no_std)]
#[cfg(not(target_arch = "wasm32"))]
extern crate std;
//
// Host Functions Test
// Tests 26 host functions (across 7 categories)
//
// With craft you can run this test with:
// craft test --project host_functions_test --test-case host_functions_test
//
// Amount Format Update:
// - XRP amounts now return as 8-byte serialized rippled objects
// - IOU and MPT amounts return in variable-length serialized format
// - Format details: https://xrpl.org/docs/references/protocol/binary-format#amount-fields
//
// Error Code Ranges:
// -100 to -199: Ledger Header Functions (3 functions)
// -200 to -299: Transaction Data Functions (5 functions)
// -300 to -399: Current Ledger Object Functions (4 functions)
// -400 to -499: Any Ledger Object Functions (5 functions)
// -500 to -599: Keylet Generation Functions (4 functions)
// -600 to -699: Utility Functions (4 functions)
// -700 to -799: Data Update Functions (1 function)
//
use xrpl_std::core::current_tx::escrow_finish::EscrowFinish;
use xrpl_std::core::current_tx::traits::TransactionCommonFields;
use xrpl_std::host;
use xrpl_std::host::trace::{trace, trace_account_buf, trace_data, trace_num, DataRepr};
use xrpl_std::sfield;
#[unsafe(no_mangle)]
pub extern "C" fn finish() -> i32 {
let _ = trace("=== HOST FUNCTIONS TEST ===");
let _ = trace("Testing 26 host functions");
// Category 1: Ledger Header Data Functions (3 functions)
// Error range: -100 to -199
match test_ledger_header_functions() {
0 => (),
err => return err,
}
// Category 2: Transaction Data Functions (5 functions)
// Error range: -200 to -299
match test_transaction_data_functions() {
0 => (),
err => return err,
}
// Category 3: Current Ledger Object Functions (4 functions)
// Error range: -300 to -399
match test_current_ledger_object_functions() {
0 => (),
err => return err,
}
// Category 4: Any Ledger Object Functions (5 functions)
// Error range: -400 to -499
match test_any_ledger_object_functions() {
0 => (),
err => return err,
}
// Category 5: Keylet Generation Functions (4 functions)
// Error range: -500 to -599
match test_keylet_generation_functions() {
0 => (),
err => return err,
}
// Category 6: Utility Functions (4 functions)
// Error range: -600 to -699
match test_utility_functions() {
0 => (),
err => return err,
}
// Category 7: Data Update Functions (1 function)
// Error range: -700 to -799
match test_data_update_functions() {
0 => (),
err => return err,
}
let _ = trace("SUCCESS: All host function tests passed!");
1 // Success return code for WASM finish function
}
/// Test Category 1: Ledger Header Data Functions (3 functions)
/// - get_ledger_sqn() - Get ledger sequence number
/// - get_parent_ledger_time() - Get parent ledger timestamp
/// - get_parent_ledger_hash() - Get parent ledger hash
fn test_ledger_header_functions() -> i32 {
let _ = trace("--- Category 1: Ledger Header Functions ---");
// Test 1.1: get_ledger_sqn() - should return current ledger sequence number
let sqn_result = unsafe { host::get_ledger_sqn() };
if sqn_result <= 0 {
let _ = trace_num("ERROR: get_ledger_sqn failed:", sqn_result as i64);
return -101; // Ledger sequence number test failed
}
let _ = trace_num("Ledger sequence number:", sqn_result as i64);
// Test 1.2: get_parent_ledger_time() - should return parent ledger timestamp
let time_result = unsafe { host::get_parent_ledger_time() };
if time_result <= 0 {
let _ = trace_num("ERROR: get_parent_ledger_time failed:", time_result as i64);
return -102; // Parent ledger time test failed
}
let _ = trace_num("Parent ledger time:", time_result as i64);
// Test 1.3: get_parent_ledger_hash() - should return parent ledger hash (32 bytes)
let mut hash_buffer = [0u8; 32];
let hash_result =
unsafe { host::get_parent_ledger_hash(hash_buffer.as_mut_ptr(), hash_buffer.len()) };
if hash_result != 32 {
let _ = trace_num(
"ERROR: get_parent_ledger_hash wrong length:",
hash_result as i64,
);
return -103; // Parent ledger hash test failed - should be exactly 32 bytes
}
let _ = trace_data("Parent ledger hash:", &hash_buffer, DataRepr::AsHex);
let _ = trace("SUCCESS: Ledger header functions");
0
}
/// Test Category 2: Transaction Data Functions (5 functions)
/// Tests all functions for accessing current transaction data
fn test_transaction_data_functions() -> i32 {
let _ = trace("--- Category 2: Transaction Data Functions ---");
// Test 2.1: get_tx_field() - Basic transaction field access
// Test with Account field (required, 20 bytes)
let mut account_buffer = [0u8; 20];
let account_len = unsafe {
host::get_tx_field(
sfield::Account,
account_buffer.as_mut_ptr(),
account_buffer.len(),
)
};
if account_len != 20 {
let _ = trace_num(
"ERROR: get_tx_field(Account) wrong length:",
account_len as i64,
);
return -201; // Basic transaction field test failed
}
let _ = trace_account_buf("Transaction Account:", &account_buffer);
// Test with Fee field (XRP amount - 8 bytes in new serialized format)
// New format: XRP amounts are always 8 bytes (positive: value | cPositive flag, negative: just value)
let mut fee_buffer = [0u8; 8];
let fee_len =
unsafe { host::get_tx_field(sfield::Fee, fee_buffer.as_mut_ptr(), fee_buffer.len()) };
if fee_len != 8 {
let _ = trace_num(
"ERROR: get_tx_field(Fee) wrong length (expected 8 bytes for XRP):",
fee_len as i64,
);
return -202; // Fee field test failed - XRP amounts should be exactly 8 bytes
}
let _ = trace_num("Transaction Fee length:", fee_len as i64);
let _ = trace_data(
"Transaction Fee (serialized XRP amount):",
&fee_buffer,
DataRepr::AsHex,
);
// Test with Sequence field (required, 4 bytes uint32)
let mut seq_buffer = [0u8; 4];
let seq_len =
unsafe { host::get_tx_field(sfield::Sequence, seq_buffer.as_mut_ptr(), seq_buffer.len()) };
if seq_len != 4 {
let _ = trace_num(
"ERROR: get_tx_field(Sequence) wrong length:",
seq_len as i64,
);
return -203; // Sequence field test failed
}
let _ = trace_data("Transaction Sequence:", &seq_buffer, DataRepr::AsHex);
// NOTE: get_tx_field2() through get_tx_field6() have been deprecated.
// Use get_tx_field() with appropriate parameters for all transaction field access.
// Test 2.2: get_tx_nested_field() - Nested field access with locator
let locator = [0x01, 0x00]; // Simple locator for first element
let mut nested_buffer = [0u8; 32];
let nested_result = unsafe {
host::get_tx_nested_field(
locator.as_ptr(),
locator.len(),
nested_buffer.as_mut_ptr(),
nested_buffer.len(),
)
};
if nested_result < 0 {
let _ = trace_num(
"INFO: get_tx_nested_field not applicable:",
nested_result as i64,
);
// Expected - locator may not match transaction structure
} else {
let _ = trace_num("Nested field length:", nested_result as i64);
let _ = trace_data(
"Nested field:",
&nested_buffer[..nested_result as usize],
DataRepr::AsHex,
);
}
// Test 2.3: get_tx_array_len() - Get array length
let signers_len = unsafe { host::get_tx_array_len(sfield::Signers) };
let _ = trace_num("Signers array length:", signers_len as i64);
let memos_len = unsafe { host::get_tx_array_len(sfield::Memos) };
let _ = trace_num("Memos array length:", memos_len as i64);
// Test 2.4: get_tx_nested_array_len() - Get nested array length with locator
let nested_array_len =
unsafe { host::get_tx_nested_array_len(locator.as_ptr(), locator.len()) };
if nested_array_len < 0 {
let _ = trace_num(
"INFO: get_tx_nested_array_len not applicable:",
nested_array_len as i64,
);
} else {
let _ = trace_num("Nested array length:", nested_array_len as i64);
}
let _ = trace("SUCCESS: Transaction data functions");
0
}
/// Test Category 3: Current Ledger Object Functions (4 functions)
/// Tests functions that access the current ledger object being processed
fn test_current_ledger_object_functions() -> i32 {
let _ = trace("--- Category 3: Current Ledger Object Functions ---");
// Test 3.1: get_current_ledger_obj_field() - Access field from current ledger object
// Test with Balance field (XRP amount - 8 bytes in new serialized format)
let mut balance_buffer = [0u8; 8];
let balance_result = unsafe {
host::get_current_ledger_obj_field(
sfield::Balance,
balance_buffer.as_mut_ptr(),
balance_buffer.len(),
)
};
if balance_result <= 0 {
let _ = trace_num(
"INFO: get_current_ledger_obj_field(Balance) failed (may be expected):",
balance_result as i64,
);
// This might fail if current ledger object doesn't have balance field
} else if balance_result == 8 {
let _ = trace_num(
"Current object balance length (XRP amount):",
balance_result as i64,
);
let _ = trace_data(
"Current object balance (serialized XRP amount):",
&balance_buffer,
DataRepr::AsHex,
);
} else {
let _ = trace_num(
"Current object balance length (non-XRP amount):",
balance_result as i64,
);
let _ = trace_data(
"Current object balance:",
&balance_buffer[..balance_result as usize],
DataRepr::AsHex,
);
}
// Test with Account field
let mut current_account_buffer = [0u8; 20];
let current_account_result = unsafe {
host::get_current_ledger_obj_field(
sfield::Account,
current_account_buffer.as_mut_ptr(),
current_account_buffer.len(),
)
};
if current_account_result <= 0 {
let _ = trace_num(
"INFO: get_current_ledger_obj_field(Account) failed:",
current_account_result as i64,
);
} else {
let _ = trace_account_buf("Current ledger object account:", &current_account_buffer);
}
// Test 3.2: get_current_ledger_obj_nested_field() - Nested field access
let locator = [0x01, 0x00]; // Simple locator
let mut current_nested_buffer = [0u8; 32];
let current_nested_result = unsafe {
host::get_current_ledger_obj_nested_field(
locator.as_ptr(),
locator.len(),
current_nested_buffer.as_mut_ptr(),
current_nested_buffer.len(),
)
};
if current_nested_result < 0 {
let _ = trace_num(
"INFO: get_current_ledger_obj_nested_field not applicable:",
current_nested_result as i64,
);
} else {
let _ = trace_num("Current nested field length:", current_nested_result as i64);
let _ = trace_data(
"Current nested field:",
&current_nested_buffer[..current_nested_result as usize],
DataRepr::AsHex,
);
}
// Test 3.3: get_current_ledger_obj_array_len() - Array length in current object
let current_array_len = unsafe { host::get_current_ledger_obj_array_len(sfield::Signers) };
let _ = trace_num(
"Current object Signers array length:",
current_array_len as i64,
);
// Test 3.4: get_current_ledger_obj_nested_array_len() - Nested array length
let current_nested_array_len =
unsafe { host::get_current_ledger_obj_nested_array_len(locator.as_ptr(), locator.len()) };
if current_nested_array_len < 0 {
let _ = trace_num(
"INFO: get_current_ledger_obj_nested_array_len not applicable:",
current_nested_array_len as i64,
);
} else {
let _ = trace_num(
"Current nested array length:",
current_nested_array_len as i64,
);
}
let _ = trace("SUCCESS: Current ledger object functions");
0
}
/// Test Category 4: Any Ledger Object Functions (5 functions)
/// Tests functions that work with cached ledger objects
fn test_any_ledger_object_functions() -> i32 {
let _ = trace("--- Category 4: Any Ledger Object Functions ---");
// First we need to cache a ledger object to test the other functions
// Get the account from transaction and generate its keylet
let escrow_finish = EscrowFinish;
let account_id = escrow_finish.get_account().unwrap();
// Test 4.1: cache_ledger_obj() - Cache a ledger object
let mut keylet_buffer = [0u8; 32];
let keylet_result = unsafe {
host::account_keylet(
account_id.0.as_ptr(),
account_id.0.len(),
keylet_buffer.as_mut_ptr(),
keylet_buffer.len(),
)
};
if keylet_result != 32 {
let _ = trace_num(
"ERROR: account_keylet failed for caching test:",
keylet_result as i64,
);
return -401; // Keylet generation failed for caching test
}
let cache_result =
unsafe { host::cache_ledger_obj(keylet_buffer.as_ptr(), keylet_result as usize, 0) };
if cache_result <= 0 {
let _ = trace_num(
"INFO: cache_ledger_obj failed (expected with test fixtures):",
cache_result as i64,
);
// Test fixtures may not contain the account object - this is expected
// We'll test the interface but expect failures
// Test 4.2-4.5 with invalid slot (should fail gracefully)
let mut test_buffer = [0u8; 32];
// Test get_ledger_obj_field with invalid slot
let field_result = unsafe {
host::get_ledger_obj_field(
1,
sfield::Balance,
test_buffer.as_mut_ptr(),
test_buffer.len(),
)
};
if field_result < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_field failed as expected (no cached object):",
field_result as i64,
);
}
// Test get_ledger_obj_nested_field with invalid slot
let locator = [0x01, 0x00];
let nested_result = unsafe {
host::get_ledger_obj_nested_field(
1,
locator.as_ptr(),
locator.len(),
test_buffer.as_mut_ptr(),
test_buffer.len(),
)
};
if nested_result < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_nested_field failed as expected:",
nested_result as i64,
);
}
// Test get_ledger_obj_array_len with invalid slot
let array_result = unsafe { host::get_ledger_obj_array_len(1, sfield::Signers) };
if array_result < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_array_len failed as expected:",
array_result as i64,
);
}
// Test get_ledger_obj_nested_array_len with invalid slot
let nested_array_result =
unsafe { host::get_ledger_obj_nested_array_len(1, locator.as_ptr(), locator.len()) };
if nested_array_result < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_nested_array_len failed as expected:",
nested_array_result as i64,
);
}
let _ = trace("SUCCESS: Any ledger object functions (interface tested)");
return 0;
}
// If we successfully cached an object, test the access functions
let slot = cache_result;
let _ = trace_num("Successfully cached object in slot:", slot as i64);
// Test 4.2: get_ledger_obj_field() - Access field from cached object
let mut cached_balance_buffer = [0u8; 8];
let cached_balance_result = unsafe {
host::get_ledger_obj_field(
slot,
sfield::Balance,
cached_balance_buffer.as_mut_ptr(),
cached_balance_buffer.len(),
)
};
if cached_balance_result <= 0 {
let _ = trace_num(
"INFO: get_ledger_obj_field(Balance) failed:",
cached_balance_result as i64,
);
} else if cached_balance_result == 8 {
let _ = trace_num(
"Cached object balance length (XRP amount):",
cached_balance_result as i64,
);
let _ = trace_data(
"Cached object balance (serialized XRP amount):",
&cached_balance_buffer,
DataRepr::AsHex,
);
} else {
let _ = trace_num(
"Cached object balance length (non-XRP amount):",
cached_balance_result as i64,
);
let _ = trace_data(
"Cached object balance:",
&cached_balance_buffer[..cached_balance_result as usize],
DataRepr::AsHex,
);
}
// Test 4.3: get_ledger_obj_nested_field() - Nested field from cached object
let locator = [0x01, 0x00];
let mut cached_nested_buffer = [0u8; 32];
let cached_nested_result = unsafe {
host::get_ledger_obj_nested_field(
slot,
locator.as_ptr(),
locator.len(),
cached_nested_buffer.as_mut_ptr(),
cached_nested_buffer.len(),
)
};
if cached_nested_result < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_nested_field not applicable:",
cached_nested_result as i64,
);
} else {
let _ = trace_num("Cached nested field length:", cached_nested_result as i64);
let _ = trace_data(
"Cached nested field:",
&cached_nested_buffer[..cached_nested_result as usize],
DataRepr::AsHex,
);
}
// Test 4.4: get_ledger_obj_array_len() - Array length from cached object
let cached_array_len = unsafe { host::get_ledger_obj_array_len(slot, sfield::Signers) };
let _ = trace_num(
"Cached object Signers array length:",
cached_array_len as i64,
);
// Test 4.5: get_ledger_obj_nested_array_len() - Nested array length from cached object
let cached_nested_array_len =
unsafe { host::get_ledger_obj_nested_array_len(slot, locator.as_ptr(), locator.len()) };
if cached_nested_array_len < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_nested_array_len not applicable:",
cached_nested_array_len as i64,
);
} else {
let _ = trace_num(
"Cached nested array length:",
cached_nested_array_len as i64,
);
}
let _ = trace("SUCCESS: Any ledger object functions");
0
}
/// Test Category 5: Keylet Generation Functions (4 functions)
/// Tests keylet generation functions for different ledger entry types
fn test_keylet_generation_functions() -> i32 {
let _ = trace("--- Category 5: Keylet Generation Functions ---");
let escrow_finish = EscrowFinish;
let account_id = escrow_finish.get_account().unwrap();
// Test 5.1: account_keylet() - Generate keylet for account
let mut account_keylet_buffer = [0u8; 32];
let account_keylet_result = unsafe {
host::account_keylet(
account_id.0.as_ptr(),
account_id.0.len(),
account_keylet_buffer.as_mut_ptr(),
account_keylet_buffer.len(),
)
};
if account_keylet_result != 32 {
let _ = trace_num(
"ERROR: account_keylet failed:",
account_keylet_result as i64,
);
return -501; // Account keylet generation failed
}
let _ = trace_data("Account keylet:", &account_keylet_buffer, DataRepr::AsHex);
// Test 5.2: credential_keylet() - Generate keylet for credential
let mut credential_keylet_buffer = [0u8; 32];
let credential_keylet_result = unsafe {
host::credential_keylet(
account_id.0.as_ptr(), // Subject
account_id.0.len(),
account_id.0.as_ptr(), // Issuer - same account for test
account_id.0.len(),
b"TestType".as_ptr(), // Credential type
9usize, // Length of "TestType"
credential_keylet_buffer.as_mut_ptr(),
credential_keylet_buffer.len(),
)
};
if credential_keylet_result <= 0 {
let _ = trace_num(
"INFO: credential_keylet failed (expected - interface issue):",
credential_keylet_result as i64,
);
// This is expected to fail due to unusual parameter types
} else {
let _ = trace_data(
"Credential keylet:",
&credential_keylet_buffer[..credential_keylet_result as usize],
DataRepr::AsHex,
);
}
// Test 5.3: escrow_keylet() - Generate keylet for escrow
let mut escrow_keylet_buffer = [0u8; 32];
let escrow_keylet_result = unsafe {
host::escrow_keylet(
account_id.0.as_ptr(),
account_id.0.len(),
1000, // Sequence number
escrow_keylet_buffer.as_mut_ptr(),
escrow_keylet_buffer.len(),
)
};
if escrow_keylet_result != 32 {
let _ = trace_num("ERROR: escrow_keylet failed:", escrow_keylet_result as i64);
return -503; // Escrow keylet generation failed
}
let _ = trace_data("Escrow keylet:", &escrow_keylet_buffer, DataRepr::AsHex);
// Test 5.4: oracle_keylet() - Generate keylet for oracle
let mut oracle_keylet_buffer = [0u8; 32];
let oracle_keylet_result = unsafe {
host::oracle_keylet(
account_id.0.as_ptr(),
account_id.0.len(),
42, // Document ID
oracle_keylet_buffer.as_mut_ptr(),
oracle_keylet_buffer.len(),
)
};
if oracle_keylet_result != 32 {
let _ = trace_num("ERROR: oracle_keylet failed:", oracle_keylet_result as i64);
return -504; // Oracle keylet generation failed
}
let _ = trace_data("Oracle keylet:", &oracle_keylet_buffer, DataRepr::AsHex);
let _ = trace("SUCCESS: Keylet generation functions");
0
}
/// Test Category 6: Utility Functions (4 functions)
/// Tests utility functions for hashing, NFT access, and tracing
fn test_utility_functions() -> i32 {
let _ = trace("--- Category 6: Utility Functions ---");
// Test 6.1: compute_sha512_half() - SHA512 hash computation (first 32 bytes)
let test_data = b"Hello, XRPL WASM world!";
let mut hash_output = [0u8; 32];
let hash_result = unsafe {
host::compute_sha512_half(
test_data.as_ptr(),
test_data.len(),
hash_output.as_mut_ptr(),
hash_output.len(),
)
};
if hash_result != 32 {
let _ = trace_num("ERROR: compute_sha512_half failed:", hash_result as i64);
return -601; // SHA512 half computation failed
}
let _ = trace_data("Input data:", test_data, DataRepr::AsHex);
let _ = trace_data("SHA512 half hash:", &hash_output, DataRepr::AsHex);
// Test 6.2: get_nft() - NFT data retrieval
let escrow_finish = EscrowFinish;
let account_id = escrow_finish.get_account().unwrap();
let nft_id = [0u8; 32]; // Dummy NFT ID for testing
let mut nft_buffer = [0u8; 256];
let nft_result = unsafe {
host::get_nft(
account_id.0.as_ptr(),
account_id.0.len(),
nft_id.as_ptr(),
nft_id.len(),
nft_buffer.as_mut_ptr(),
nft_buffer.len(),
)
};
if nft_result <= 0 {
let _ = trace_num(
"INFO: get_nft failed (expected - no such NFT):",
nft_result as i64,
);
// This is expected - test account likely doesn't own the dummy NFT
} else {
let _ = trace_num("NFT data length:", nft_result as i64);
let _ = trace_data(
"NFT data:",
&nft_buffer[..nft_result as usize],
DataRepr::AsHex,
);
}
// Test 6.3: trace() - Debug logging with data
let trace_message = b"Test trace message";
let trace_data_payload = b"payload";
let trace_result = unsafe {
host::trace(
trace_message.as_ptr(),
trace_message.len(),
trace_data_payload.as_ptr(),
trace_data_payload.len(),
1, // as_hex = true
)
};
if trace_result < 0 {
let _ = trace_num("ERROR: trace() failed:", trace_result as i64);
return -603; // Trace function failed
}
let _ = trace_num("Trace function bytes written:", trace_result as i64);
// Test 6.4: trace_num() - Debug logging with number
let test_number = 42i64;
let trace_num_result = trace_num("Test number trace", test_number);
use xrpl_std::host::Result;
match trace_num_result {
Result::Ok(_) => {
let _ = trace_num("Trace_num function succeeded", 0);
}
Result::Err(_) => {
let _ = trace_num("ERROR: trace_num() failed:", -604);
return -604; // Trace number function failed
}
}
let _ = trace("SUCCESS: Utility functions");
0
}
/// Test Category 7: Data Update Functions (1 function)
/// Tests the function for modifying the current ledger entry
fn test_data_update_functions() -> i32 {
let _ = trace("--- Category 7: Data Update Functions ---");
// Test 7.1: update_data() - Update current ledger entry data
let update_payload = b"Updated ledger entry data from WASM test";
let update_result = unsafe { host::update_data(update_payload.as_ptr(), update_payload.len()) };
if update_result != 0 {
let _ = trace_num("ERROR: update_data failed:", update_result as i64);
return -701; // Data update failed
}
let _ = trace_data(
"Successfully updated ledger entry with:",
update_payload,
DataRepr::AsHex,
);
let _ = trace("SUCCESS: Data update functions");
0
}

View File

@@ -1,15 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "all_keylets"
version = "0.0.1"
dependencies = [
"xrpl-std",
]
[[package]]
name = "xrpl-std"
version = "0.5.1-devnet5"
source = "git+https://github.com/ripple/craft.git?branch=lastdevnet#c3a92273195a211ac9b41d641b0d20f60f982bb2"

View File

@@ -1,21 +0,0 @@
[package]
edition = "2024"
name = "all_keylets"
version = "0.0.1"
# This empty workspace definition keeps this project independent of the parent workspace
[workspace]
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true
opt-level = 's'
panic = "abort"
[dependencies]
xrpl-std = { git = "https://github.com/ripple/craft.git", branch = "lastdevnet", package = "xrpl-std" }
[profile.dev]
panic = "abort"

View File

@@ -1,179 +0,0 @@
#![cfg_attr(target_arch = "wasm32", no_std)]
#[cfg(not(target_arch = "wasm32"))]
extern crate std;
use crate::host::{Error, Result, Result::Err, Result::Ok};
use xrpl_std::core::ledger_objects::current_escrow::CurrentEscrow;
use xrpl_std::core::ledger_objects::current_escrow::get_current_escrow;
use xrpl_std::core::ledger_objects::ledger_object;
use xrpl_std::core::ledger_objects::traits::CurrentEscrowFields;
use xrpl_std::core::types::amount::asset::{Asset, IouAsset, XrpAsset};
use xrpl_std::core::types::amount::currency_code::CurrencyCode;
use xrpl_std::core::types::amount::mpt_id::MptId;
use xrpl_std::core::types::keylets;
use xrpl_std::host;
use xrpl_std::host::trace::{DataRepr, trace, trace_account, trace_data, trace_num};
use xrpl_std::sfield;
#[unsafe(no_mangle)]
pub fn object_exists(
keylet_result: Result<keylets::KeyletBytes>,
keylet_type: &str,
field: i32,
) -> Result<bool> {
match keylet_result {
Ok(keylet) => {
let _ = trace_data(keylet_type, &keylet, DataRepr::AsHex);
let slot = unsafe { host::cache_ledger_obj(keylet.as_ptr(), keylet.len(), 0) };
if slot <= 0 {
let _ = trace_num("Error: ", slot.into());
return Err(Error::from_code(slot));
}
if field == 0 {
let new_field = sfield::PreviousTxnID;
let _ = trace_num("Getting field: ", new_field.into());
match ledger_object::get_hash_256_field(slot, new_field) {
Ok(data) => {
let _ = trace_data("Field data: ", &data.0, DataRepr::AsHex);
}
Err(result_code) => {
let _ = trace_num("Error getting field: ", result_code.into());
return Err(result_code);
}
}
} else {
let _ = trace_num("Getting field: ", field.into());
match ledger_object::get_account_id_field(slot, field) {
Ok(data) => {
let _ = trace_data("Field data: ", &data.0, DataRepr::AsHex);
}
Err(result_code) => {
let _ = trace_num("Error getting field: ", result_code.into());
return Err(result_code);
}
}
}
Ok(true)
}
Err(error) => {
let _ = trace_num("Error getting keylet: ", error.into());
Err(error)
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn finish() -> i32 {
let _ = trace("$$$$$ STARTING WASM EXECUTION $$$$$");
let escrow: CurrentEscrow = get_current_escrow();
let account = escrow.get_account().unwrap_or_panic();
let _ = trace_account("Account:", &account);
let destination = escrow.get_destination().unwrap_or_panic();
let _ = trace_account("Destination:", &destination);
let mut seq = 5;
macro_rules! check_object_exists {
($keylet:expr, $type:expr, $field:expr) => {
match object_exists($keylet, $type, $field) {
Ok(_exists) => {
// false isn't returned
let _ = trace(concat!(
$type,
" object exists, proceeding with escrow finish."
));
}
Err(error) => {
let _ = trace_num("Current seq value:", seq.try_into().unwrap());
return error.code();
}
}
};
}
let account_keylet = keylets::account_keylet(&account);
check_object_exists!(account_keylet, "Account", sfield::Account);
let currency_code: &[u8; 3] = b"USD";
let currency: CurrencyCode = CurrencyCode::from(*currency_code);
let line_keylet = keylets::line_keylet(&account, &destination, &currency);
check_object_exists!(line_keylet, "Trustline", sfield::Generic);
seq += 1;
let asset1 = Asset::XRP(XrpAsset {});
let asset2 = Asset::IOU(IouAsset::new(destination, currency));
check_object_exists!(
keylets::amm_keylet(&asset1, &asset2),
"AMM",
sfield::Account
);
let check_keylet = keylets::check_keylet(&account, seq);
check_object_exists!(check_keylet, "Check", sfield::Account);
seq += 1;
let cred_type: &[u8] = b"termsandconditions";
let credential_keylet = keylets::credential_keylet(&account, &account, cred_type);
check_object_exists!(credential_keylet, "Credential", sfield::Subject);
seq += 1;
let delegate_keylet = keylets::delegate_keylet(&account, &destination);
check_object_exists!(delegate_keylet, "Delegate", sfield::Account);
seq += 1;
let deposit_preauth_keylet = keylets::deposit_preauth_keylet(&account, &destination);
check_object_exists!(deposit_preauth_keylet, "DepositPreauth", sfield::Account);
seq += 1;
let did_keylet = keylets::did_keylet(&account);
check_object_exists!(did_keylet, "DID", sfield::Account);
seq += 1;
let escrow_keylet = keylets::escrow_keylet(&account, seq);
check_object_exists!(escrow_keylet, "Escrow", sfield::Account);
seq += 1;
let mpt_issuance_keylet = keylets::mpt_issuance_keylet(&account, seq);
let mpt_id = MptId::new(seq.try_into().unwrap(), account);
check_object_exists!(mpt_issuance_keylet, "MPTIssuance", sfield::Issuer);
seq += 1;
let mptoken_keylet = keylets::mptoken_keylet(&mpt_id, &destination);
check_object_exists!(mptoken_keylet, "MPToken", sfield::Account);
let nft_offer_keylet = keylets::nft_offer_keylet(&destination, 6);
check_object_exists!(nft_offer_keylet, "NFTokenOffer", sfield::Owner);
let offer_keylet = keylets::offer_keylet(&account, seq);
check_object_exists!(offer_keylet, "Offer", sfield::Account);
seq += 1;
let paychan_keylet = keylets::paychan_keylet(&account, &destination, seq);
check_object_exists!(paychan_keylet, "PayChannel", sfield::Account);
seq += 1;
let pd_keylet = keylets::permissioned_domain_keylet(&account, seq);
check_object_exists!(pd_keylet, "PermissionedDomain", sfield::Owner);
seq += 1;
let signers_keylet = keylets::signers_keylet(&account);
check_object_exists!(signers_keylet, "SignerList", sfield::Generic);
seq += 1;
seq += 1; // ticket sequence number is one greater
let ticket_keylet = keylets::ticket_keylet(&account, seq);
check_object_exists!(ticket_keylet, "Ticket", sfield::Account);
seq += 1;
let vault_keylet = keylets::vault_keylet(&account, seq);
check_object_exists!(vault_keylet, "Vault", sfield::Account);
// seq += 1;
1 // All keylets exist, finish the escrow.
}

View File

@@ -1,73 +0,0 @@
#include <stdint.h>
static char const b58digits_ordered[] =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
uint8_t e_data[32 * 1024];
void*
allocate(int sz)
{
static int idx = 0;
if (idx >= 32)
return 0;
if (sz > 1024)
return 0;
return &e_data[idx++ << 10];
}
void
deallocate(void* p)
{
}
extern int32_t
b58enco(char* b58, int32_t b58sz, void const* data, int32_t binsz)
{
uint8_t const* bin = data;
int32_t carry;
int32_t i, j, high, zcount = 0;
int32_t size;
while (zcount < binsz && !bin[zcount])
++zcount;
size = (binsz - zcount) * 138 / 100 + 1;
uint8_t* buf = allocate(size);
if (!buf)
return 0;
// memset(buf, 0, size);
for (i = 0; i < size; ++i)
buf[i] = 0;
for (i = zcount, high = size - 1; i < binsz; ++i, high = j)
{
for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
{
carry += 256 * buf[j];
buf[j] = carry % 58;
carry /= 58;
if (!j)
break;
}
}
for (j = 0; j < size && !buf[j]; ++j)
;
if (b58sz <= zcount + size - j)
return 0;
if (zcount)
{
// memset(b58, '1', zcount);
for (i = 0; i < zcount; ++i)
b58[i] = '1';
}
for (i = zcount; j < size; ++i, ++j)
b58[i] = b58digits_ordered[buf[j]];
b58[i] = '\0';
return i + 1;
}

View File

@@ -1,15 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "codecov_tests"
version = "0.0.1"
dependencies = [
"xrpl-std",
]
[[package]]
name = "xrpl-std"
version = "0.5.1-devnet5"
source = "git+https://github.com/ripple/craft.git?branch=lastdevnet#6b20669b20561b9d0f09678f44ccbddb84ef9f47"

View File

@@ -1,18 +0,0 @@
[package]
edition = "2024"
name = "codecov_tests"
version = "0.0.1"
# This empty workspace definition keeps this project independent of the parent workspace
[workspace]
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true
opt-level = 's'
panic = "abort"
[dependencies]
xrpl-std = { git = "https://github.com/ripple/craft.git", branch = "lastdevnet", package = "xrpl-std" }

View File

@@ -1,47 +0,0 @@
//TODO add docs after discussing the interface
//Note that Craft currently does not honor the rounding modes
#[allow(unused)]
pub const FLOAT_ROUNDING_MODES_TO_NEAREST: i32 = 0;
#[allow(unused)]
pub const FLOAT_ROUNDING_MODES_TOWARDS_ZERO: i32 = 1;
#[allow(unused)]
pub const FLOAT_ROUNDING_MODES_DOWNWARD: i32 = 2;
#[allow(unused)]
pub const FLOAT_ROUNDING_MODES_UPWARD: i32 = 3;
// pub enum RippledRoundingModes{
// ToNearest = 0,
// TowardsZero = 1,
// DOWNWARD = 2,
// UPWARD = 3
// }
#[allow(unused)]
#[link(wasm_import_module = "host_lib")]
unsafe extern "C" {
pub fn get_parent_ledger_hash(out_buff_ptr: i32, out_buff_len: i32) -> i32;
pub fn cache_ledger_obj(keylet_ptr: i32, keylet_len: i32, cache_num: i32) -> i32;
pub fn get_tx_nested_array_len(locator_ptr: i32, locator_len: i32) -> i32;
pub fn account_keylet(
account_ptr: i32,
account_len: i32,
out_buff_ptr: *mut u8,
out_buff_len: usize,
) -> i32;
pub fn line_keylet(
account1_ptr: *const u8,
account1_len: usize,
account2_ptr: *const u8,
account2_len: usize,
currency_ptr: i32,
currency_len: i32,
out_buff_ptr: *mut u8,
out_buff_len: usize,
) -> i32;
pub fn trace_num(msg_read_ptr: i32, msg_read_len: i32, number: i64) -> i32;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,134 +0,0 @@
import os
import sys
import subprocess
import re
OPT = "-Oz"
def update_fixture(project_name, wasm):
fixture_name = (
re.sub(r"_([a-z])", lambda m: m.group(1).upper(), project_name) + "WasmHex"
)
print(f"Updating fixture: {fixture_name}")
cpp_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "fixtures.cpp"))
h_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "fixtures.h"))
with open(cpp_path, "r", encoding="utf8") as f:
cpp_content = f.read()
pattern = rf'extern std::string const {fixture_name} =[ \n]+"[^;]*;'
if re.search(pattern, cpp_content, flags=re.MULTILINE):
updated_cpp_content = re.sub(
pattern,
f'extern std::string const {fixture_name} = "{wasm}";',
cpp_content,
flags=re.MULTILINE,
)
else:
with open(h_path, "r", encoding="utf8") as f:
h_content = f.read()
updated_h_content = (
h_content.rstrip() + f"\n\n extern std::string const {fixture_name};\n"
)
with open(h_path, "w", encoding="utf8") as f:
f.write(updated_h_content)
updated_cpp_content = (
cpp_content.rstrip()
+ f'\n\nextern std::string const {fixture_name} = "{wasm}";\n'
)
with open(cpp_path, "w", encoding="utf8") as f:
f.write(updated_cpp_content)
def process_rust(project_name):
project_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), project_name)
)
wasm_location = f"target/wasm32-unknown-unknown/release/{project_name}.wasm"
build_cmd = (
f"(cd {project_path} "
f"&& cargo build --target wasm32-unknown-unknown --release "
f"&& wasm-opt {wasm_location} {OPT} -o {wasm_location}"
")"
)
try:
result = subprocess.run(
build_cmd, shell=True, check=True, capture_output=True, text=True
)
print(f"stdout: {result.stdout}")
if result.stderr:
print(f"stderr: {result.stderr}")
print(f"WASM file for {project_name} has been built and optimized.")
except subprocess.CalledProcessError as e:
print(f"exec error: {e}")
sys.exit(1)
src_path = os.path.abspath(
os.path.join(
os.path.dirname(__file__),
f"{project_name}/target/wasm32-unknown-unknown/release/{project_name}.wasm",
)
)
with open(src_path, "rb") as f:
data = f.read()
wasm = data.hex()
update_fixture(project_name, wasm)
def process_c(project_name):
project_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), f"{project_name}.c")
)
wasm_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), f"{project_name}.wasm")
)
build_cmd = (
f"$CC --sysroot=$SYSROOT "
f"-O3 -ffast-math --target=wasm32 -fno-exceptions -fno-threadsafe-statics -fvisibility=default -Wl,--export-all -Wl,--no-entry -Wl,--allow-undefined -DNDEBUG --no-standard-libraries -fno-builtin-memset "
f"-o {wasm_path} {project_path}"
f"&& wasm-opt {wasm_path} {OPT} -o {wasm_path}"
)
try:
result = subprocess.run(
build_cmd, shell=True, check=True, capture_output=True, text=True
)
print(f"stdout: {result.stdout}")
if result.stderr:
print(f"stderr: {result.stderr}")
print(
f"WASM file for {project_name} has been built with WASI support using clang."
)
except subprocess.CalledProcessError as e:
print(f"exec error: {e}")
sys.exit(1)
with open(wasm_path, "rb") as f:
data = f.read()
wasm = data.hex()
update_fixture(project_name, wasm)
if __name__ == "__main__":
if len(sys.argv) > 2:
print("Usage: python copyFixtures.py [<project_name>]")
sys.exit(1)
if len(sys.argv) == 2:
if os.path.isdir(os.path.join(os.path.dirname(__file__), sys.argv[1])):
process_rust(sys.argv[1])
else:
process_c(sys.argv[1])
print("Fixture has been processed.")
else:
dirs = [
d
for d in os.listdir(os.path.dirname(__file__))
if os.path.isdir(os.path.join(os.path.dirname(__file__), d))
]
c_files = [f for f in os.listdir(os.path.dirname(__file__)) if f.endswith(".c")]
for d in dirs:
process_rust(d)
for c in c_files:
process_c(c[:-2])
print("All fixtures have been processed.")

View File

@@ -1,34 +0,0 @@
(module
(type (;0;) (func))
(type (;1;) (func (result i32)))
(func (;0;) (type 0))
(func (;1;) (type 1) (result i32)
f32.const -2048
f32.const 2050
f32.sub
drop
i32.const 1)
(memory (;0;) 2)
(global (;0;) i32 (i32.const 1024))
(global (;1;) i32 (i32.const 1024))
(global (;2;) i32 (i32.const 2048))
(global (;3;) i32 (i32.const 2048))
(global (;4;) i32 (i32.const 67584))
(global (;5;) i32 (i32.const 1024))
(global (;6;) i32 (i32.const 67584))
(global (;7;) i32 (i32.const 131072))
(global (;8;) i32 (i32.const 0))
(global (;9;) i32 (i32.const 1))
(export "memory" (memory 0))
(export "__wasm_call_ctors" (func 0))
(export "finish" (func 1))
(export "buf" (global 0))
(export "__dso_handle" (global 1))
(export "__data_end" (global 2))
(export "__stack_low" (global 3))
(export "__stack_high" (global 4))
(export "__global_base" (global 5))
(export "__heap_base" (global 6))
(export "__heap_end" (global 7))
(export "__memory_base" (global 8))
(export "__table_base" (global 9)))

View File

@@ -1,12 +0,0 @@
// typedef long long mint;
typedef int mint;
mint
fib(mint n)
{
if (!n)
return 0;
if (n <= 2)
return 1;
return fib(n - 1) + fib(n - 2);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "float_tests"
version = "0.0.1"
dependencies = [
"xrpl-std",
]
[[package]]
name = "xrpl-std"
version = "0.0.1"
source = "git+https://github.com/ripple/craft.git?branch=main#94fb247e0c21b9e7fecb91ce71ef7f74ef4a7931"

View File

@@ -1,21 +0,0 @@
[package]
name = "float_tests"
version = "0.0.1"
edition = "2024"
# This empty workspace definition keeps this project independent of the parent workspace
[workspace]
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true
opt-level = 's'
panic = "abort"
[dependencies]
xrpl-std = { git = "https://github.com/ripple/craft.git", branch = "main", package = "xrpl-std" }
[profile.dev]
panic = "abort"

View File

@@ -1,460 +0,0 @@
#![allow(unused_imports)]
#![allow(unused_variables)]
#![cfg_attr(target_arch = "wasm32", no_std)]
#[cfg(not(target_arch = "wasm32"))]
extern crate std;
use xrpl_std::core::locator::Locator;
use xrpl_std::decode_hex_32;
use xrpl_std::host::trace::DataRepr::AsHex;
use xrpl_std::host::trace::{trace, trace_data, trace_float, trace_num, DataRepr};
use xrpl_std::host::{
cache_ledger_obj, float_add, float_compare, float_divide, float_from_int, float_from_uint,
float_log, float_multiply, float_pow, float_root, float_set, float_subtract,
get_ledger_obj_array_len, get_ledger_obj_field, get_ledger_obj_nested_field,
trace_opaque_float, FLOAT_NEGATIVE_ONE, FLOAT_ONE, FLOAT_ROUNDING_MODES_TO_NEAREST,
};
use xrpl_std::sfield;
use xrpl_std::sfield::{
Account, AccountTxnID, Balance, Domain, EmailHash, Flags, LedgerEntryType, MessageKey,
OwnerCount, PreviousTxnID, PreviousTxnLgrSeq, RegularKey, Sequence, TicketCount, TransferRate,
};
fn test_float_from_wasm() {
let _ = trace("\n$$$ test_float_from_wasm $$$");
let mut f: [u8; 8] = [0u8; 8];
if 8 == unsafe { float_from_int(12300, f.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
let _ = trace_float(" float from i64 12300:", &f);
let _ = trace_data(" float from i64 12300 as HEX:", &f, AsHex);
} else {
let _ = trace(" float from i64 12300: failed");
}
let u64_value: u64 = 12300;
if 8 == unsafe {
float_from_uint(
&u64_value as *const u64 as *const u8,
8,
f.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
} {
let _ = trace_float(" float from u64 12300:", &f);
} else {
let _ = trace(" float from u64 12300: failed");
}
if 8 == unsafe { float_set(2, 123, f.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
let _ = trace_float(" float from exp 2, mantissa 123:", &f);
} else {
let _ = trace(" float from exp 2, mantissa 3: failed");
}
let _ = trace_float(" float from const 1:", &FLOAT_ONE);
let _ = trace_float(" float from const -1:", &FLOAT_NEGATIVE_ONE);
}
fn test_float_compare() {
let _ = trace("\n$$$ test_float_compare $$$");
let mut f1: [u8; 8] = [0u8; 8];
if 8 != unsafe { float_from_int(1, f1.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
let _ = trace(" float from 1: failed");
} else {
let _ = trace_float(" float from 1:", &f1);
}
if 0 == unsafe { float_compare(f1.as_ptr(), 8, FLOAT_ONE.as_ptr(), 8) } {
let _ = trace(" float from 1 == FLOAT_ONE");
} else {
let _ = trace(" float from 1 != FLOAT_ONE");
}
if 1 == unsafe { float_compare(f1.as_ptr(), 8, FLOAT_NEGATIVE_ONE.as_ptr(), 8) } {
let _ = trace(" float from 1 > FLOAT_NEGATIVE_ONE");
} else {
let _ = trace(" float from 1 !> FLOAT_NEGATIVE_ONE");
}
if 2 == unsafe { float_compare(FLOAT_NEGATIVE_ONE.as_ptr(), 8, f1.as_ptr(), 8) } {
let _ = trace(" FLOAT_NEGATIVE_ONE < float from 1");
} else {
let _ = trace(" FLOAT_NEGATIVE_ONE !< float from 1");
}
}
fn test_float_add_subtract() {
let _ = trace("\n$$$ test_float_add_subtract $$$");
let mut f_compute: [u8; 8] = FLOAT_ONE;
for i in 0..9 {
unsafe {
float_add(
f_compute.as_ptr(),
8,
FLOAT_ONE.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
// let _ = trace_float(" float:", &f_compute);
}
let mut f10: [u8; 8] = [0u8; 8];
if 8 != unsafe { float_from_int(10, f10.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
// let _ = trace(" float from 10: failed");
}
if 0 == unsafe { float_compare(f10.as_ptr(), 8, f_compute.as_ptr(), 8) } {
let _ = trace(" repeated add: good");
} else {
let _ = trace(" repeated add: bad");
}
for i in 0..11 {
unsafe {
float_subtract(
f_compute.as_ptr(),
8,
FLOAT_ONE.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
}
if 0 == unsafe { float_compare(f_compute.as_ptr(), 8, FLOAT_NEGATIVE_ONE.as_ptr(), 8) } {
let _ = trace(" repeated subtract: good");
} else {
let _ = trace(" repeated subtract: bad");
}
}
fn test_float_multiply_divide() {
let _ = trace("\n$$$ test_float_multiply_divide $$$");
let mut f10: [u8; 8] = [0u8; 8];
unsafe { float_from_int(10, f10.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
let mut f_compute: [u8; 8] = FLOAT_ONE;
for i in 0..6 {
unsafe {
float_multiply(
f_compute.as_ptr(),
8,
f10.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
// let _ = trace_float(" float:", &f_compute);
}
let mut f1000000: [u8; 8] = [0u8; 8];
unsafe {
float_from_int(
1000000,
f1000000.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
if 0 == unsafe { float_compare(f1000000.as_ptr(), 8, f_compute.as_ptr(), 8) } {
let _ = trace(" repeated multiply: good");
} else {
let _ = trace(" repeated multiply: bad");
}
for i in 0..7 {
unsafe {
float_divide(
f_compute.as_ptr(),
8,
f10.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
}
let mut f01: [u8; 8] = [0u8; 8];
unsafe { float_set(-1, 1, f01.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
if 0 == unsafe { float_compare(f_compute.as_ptr(), 8, f01.as_ptr(), 8) } {
let _ = trace(" repeated divide: good");
} else {
let _ = trace(" repeated divide: bad");
}
}
fn test_float_pow() {
let _ = trace("\n$$$ test_float_pow $$$");
let mut f_compute: [u8; 8] = [0u8; 8];
unsafe {
float_pow(
FLOAT_ONE.as_ptr(),
8,
3,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float cube of 1:", &f_compute);
unsafe {
float_pow(
FLOAT_NEGATIVE_ONE.as_ptr(),
8,
6,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float 6th power of -1:", &f_compute);
let mut f9: [u8; 8] = [0u8; 8];
unsafe { float_from_int(9, f9.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
unsafe {
float_pow(
f9.as_ptr(),
8,
2,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float square of 9:", &f_compute);
unsafe {
float_pow(
f9.as_ptr(),
8,
0,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float 0th power of 9:", &f_compute);
let mut f0: [u8; 8] = [0u8; 8];
unsafe { float_from_int(0, f0.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
unsafe {
float_pow(
f0.as_ptr(),
8,
2,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float square of 0:", &f_compute);
let r = unsafe {
float_pow(
f0.as_ptr(),
8,
0,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_num(
" float 0th power of 0 (expecting INVALID_PARAMS error):",
r as i64,
);
}
fn test_float_root() {
let _ = trace("\n$$$ test_float_root $$$");
let mut f9: [u8; 8] = [0u8; 8];
unsafe { float_from_int(9, f9.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
let mut f_compute: [u8; 8] = [0u8; 8];
unsafe {
float_root(
f9.as_ptr(),
8,
2,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float sqrt of 9:", &f_compute);
unsafe {
float_root(
f9.as_ptr(),
8,
3,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float cbrt of 9:", &f_compute);
let mut f1000000: [u8; 8] = [0u8; 8];
unsafe {
float_from_int(
1000000,
f1000000.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
unsafe {
float_root(
f1000000.as_ptr(),
8,
3,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float cbrt of 1000000:", &f_compute);
unsafe {
float_root(
f1000000.as_ptr(),
8,
6,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float 6th root of 1000000:", &f_compute);
}
fn test_float_log() {
let _ = trace("\n$$$ test_float_log $$$");
let mut f1000000: [u8; 8] = [0u8; 8];
unsafe {
float_from_int(
1000000,
f1000000.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let mut f_compute: [u8; 8] = [0u8; 8];
unsafe {
float_log(
f1000000.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" log_10 of 1000000:", &f_compute);
}
fn test_float_negate() {
let _ = trace("\n$$$ test_float_negate $$$");
let mut f_compute: [u8; 8] = [0u8; 8];
unsafe {
float_multiply(
FLOAT_ONE.as_ptr(),
8,
FLOAT_NEGATIVE_ONE.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
// let _ = trace_float(" float:", &f_compute);
if 0 == unsafe { float_compare(FLOAT_NEGATIVE_ONE.as_ptr(), 8, f_compute.as_ptr(), 8) } {
let _ = trace(" negate const 1: good");
} else {
let _ = trace(" negate const 1: bad");
}
unsafe {
float_multiply(
FLOAT_NEGATIVE_ONE.as_ptr(),
8,
FLOAT_NEGATIVE_ONE.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
// let _ = trace_float(" float:", &f_compute);
if 0 == unsafe { float_compare(FLOAT_ONE.as_ptr(), 8, f_compute.as_ptr(), 8) } {
let _ = trace(" negate const -1: good");
} else {
let _ = trace(" negate const -1: bad");
}
}
fn test_float_invert() {
let _ = trace("\n$$$ test_float_invert $$$");
let mut f_compute: [u8; 8] = [0u8; 8];
let mut f10: [u8; 8] = [0u8; 8];
unsafe { float_from_int(10, f10.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
unsafe {
float_divide(
FLOAT_ONE.as_ptr(),
8,
f10.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" invert a float from 10:", &f_compute);
unsafe {
float_divide(
FLOAT_ONE.as_ptr(),
8,
f_compute.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" invert again:", &f_compute);
// if f10's value is 7, then invert twice won't match the original value
if 0 == unsafe { float_compare(f10.as_ptr(), 8, f_compute.as_ptr(), 8) } {
let _ = trace(" invert twice: good");
} else {
let _ = trace(" invert twice: bad");
}
}
#[unsafe(no_mangle)]
pub extern "C" fn finish() -> i32 {
test_float_from_wasm();
test_float_compare();
test_float_add_subtract();
test_float_multiply_divide();
test_float_pow();
test_float_root();
test_float_log();
test_float_negate();
test_float_invert();
1
}

View File

@@ -1,27 +0,0 @@
#include <stdint.h>
int32_t
get_ledger_sqn();
// int32_t trace(uint8_t const*, int32_t, uint8_t const*, int32_t, int32_t);
// int32_t trace_num(uint8_t const*, int32_t, int64_t);
// uint8_t buf[1024];
// char const test_res[] = "sqn: ";
// char const test_name[] = "TEST get_ledger_sqn";
int
finish()
{
// trace((uint8_t const *)test_name, sizeof(test_name) - 1, 0, 0, 0);
// memset(buf, 0, sizeof(buf));
// for(int i = 0; i < sizeof(buf); ++i) buf[i] = 0;
int x = get_ledger_sqn();
// if (x >= 0)
// x = *((int32_t*)buf);
// trace_num((uint8_t const *)test`_res, sizeof(test_res) - 1, x);
return x < 0 ? x : (x >= 5 ? x : 0);
}

View File

@@ -1,145 +0,0 @@
#include <stdint.h>
#include <stdlib.h>
static uint64_t const K512[] = {
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f,
0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019,
0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242,
0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275,
0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f,
0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc,
0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6,
0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001,
0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99,
0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc,
0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915,
0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207,
0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba,
0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
0x5fcb6fab3ad6faec, 0x6c44198c4a475817};
#define ROTATE(x, y) (((x) >> (y)) | ((x) << (64 - (y))))
#define Sigma0(x) (ROTATE((x), 28) ^ ROTATE((x), 34) ^ ROTATE((x), 39))
#define Sigma1(x) (ROTATE((x), 14) ^ ROTATE((x), 18) ^ ROTATE((x), 41))
#define sigma0(x) (ROTATE((x), 1) ^ ROTATE((x), 8) ^ ((x) >> 7))
#define sigma1(x) (ROTATE((x), 19) ^ ROTATE((x), 61) ^ ((x) >> 6))
#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z)))
#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
static inline uint64_t
B2U64(uint8_t val, uint8_t sh)
{
return ((uint64_t)val) << sh;
}
void*
allocate(int sz)
{
return malloc(sz);
}
void
deallocate(void* p)
{
free(p);
}
uint8_t e_data[32 * 1024];
uint8_t*
sha512_process(uint8_t const* data, int32_t length)
{
static uint64_t state[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint64_t a, b, c, d, e, f, g, h, s0, s1, T1, T2;
uint64_t X[16];
uint64_t blocks = length / 128;
while (blocks--)
{
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
f = state[5];
g = state[6];
h = state[7];
unsigned i;
for (i = 0; i < 16; i++)
{
X[i] = B2U64(data[0], 56) | B2U64(data[1], 48) |
B2U64(data[2], 40) | B2U64(data[3], 32) | B2U64(data[4], 24) |
B2U64(data[5], 16) | B2U64(data[6], 8) | B2U64(data[7], 0);
data += 8;
T1 = h;
T1 += Sigma1(e);
T1 += Ch(e, f, g);
T1 += K512[i];
T1 += X[i];
T2 = Sigma0(a);
T2 += Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
for (i = 16; i < 80; i++)
{
s0 = X[(i + 1) & 0x0f];
s0 = sigma0(s0);
s1 = X[(i + 14) & 0x0f];
s1 = sigma1(s1);
T1 = X[i & 0xf] += s0 + s1 + X[(i + 9) & 0xf];
T1 += h + Sigma1(e) + Ch(e, f, g) + K512[i];
T2 = Sigma0(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
state[5] += f;
state[6] += g;
state[7] += h;
}
return (uint8_t*)(state);
}
// int main ()
//{
// return 0;
// }

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +0,0 @@
[package]
edition = "2021"
name = "sp1"
version = "0.0.1"
[lib]
crate-type = ["cdylib"]
[dependencies]
sp1-verifier = "4.1.3"
[profile.release]
opt-level = 3 # "z" for size or "3" for speed
lto = true # Link Time Optimization
codegen-units = 1 # Single unit = better optimization
panic = "abort" # Smaller binary, faster execution

View File

@@ -1,37 +0,0 @@
use sp1_verifier::Groth16Verifier;
#[no_mangle]
pub fn sp1_groth16_verifier() -> bool {
let groth16_vk = *sp1_verifier::GROTH16_VK_BYTES;
let proof: Vec<u8> = vec![
17, 182, 160, 157, 31, 189, 116, 200, 17, 224, 230, 34, 195, 108, 230, 185, 62, 91, 181,
212, 80, 111, 197, 89, 247, 206, 99, 206, 147, 13, 216, 101, 252, 192, 149, 2, 40, 4, 249,
44, 97, 227, 127, 36, 244, 18, 27, 75, 248, 3, 45, 11, 103, 45, 183, 204, 61, 217, 19, 208,
66, 73, 202, 108, 136, 162, 221, 184, 6, 189, 49, 196, 104, 128, 151, 21, 104, 109, 145,
150, 243, 51, 27, 243, 203, 75, 176, 59, 193, 51, 177, 64, 83, 13, 133, 140, 248, 242, 13,
24, 12, 103, 126, 112, 244, 181, 129, 246, 52, 110, 134, 57, 149, 23, 163, 43, 202, 7, 164,
233, 179, 160, 16, 5, 22, 45, 129, 76, 183, 76, 150, 139, 27, 224, 191, 59, 47, 105, 71,
47, 8, 176, 157, 159, 234, 253, 239, 131, 138, 120, 101, 4, 98, 236, 106, 235, 98, 76, 93,
220, 174, 153, 58, 216, 28, 141, 129, 191, 188, 40, 184, 225, 22, 61, 75, 139, 159, 162,
117, 83, 214, 239, 1, 246, 236, 255, 64, 228, 116, 107, 206, 23, 59, 3, 221, 95, 14, 170,
28, 171, 36, 179, 75, 101, 177, 40, 198, 12, 193, 82, 105, 155, 177, 62, 158, 72, 209, 252,
51, 169, 109, 32, 121, 179, 194, 73, 164, 14, 8, 206, 181, 9, 5, 38, 74, 136, 97, 0, 89,
80, 75, 88, 228, 94, 46, 196, 199, 83, 229, 11, 103, 115, 25, 31, 215, 137, 65, 159, 95,
192,
];
let sp1_public_values = vec![
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 8,
];
let sp1_vkey_hash: String =
"0x00aea8e9c83c73d74036923de1b4a66d18547d58eee4eacfee70235ed291954c".to_string();
let _ = Groth16Verifier::verify(&proof, &sp1_public_values, &sp1_vkey_hash, groth16_vk);
true
}

View File

@@ -1,106 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "bls12_381"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc6d6292be3a19e6379786dac800f551e5865a5bb51ebbe3064ab80433f403"
dependencies = [
"ff",
"group",
"pairing",
"rand_core",
"subtle",
]
[[package]]
name = "ff"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
dependencies = [
"bitvec",
"rand_core",
"subtle",
]
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "group"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
dependencies = [
"ff",
"rand_core",
"subtle",
]
[[package]]
name = "pairing"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f"
dependencies = [
"group",
]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]]
name = "zk_proof"
version = "0.0.1"
dependencies = [
"bls12_381",
"group",
]

View File

@@ -1,19 +0,0 @@
[package]
edition = "2021"
name = "zk_proof"
version = "0.0.1"
[lib]
crate-type = ["cdylib"]
[dependencies]
# bellman = "=0.14.0"
bls12_381 = "=0.8.0"
group = "0.13.0"
[profile.release]
# opt-level = 3 # Optimize for time
opt-level = "z" # Optimize for size
lto = true # Enable Link Time Optimization
codegen-units = 1
panic = "abort" # Remove unnecessary panic machinery

View File

@@ -1,254 +0,0 @@
use bls12_381::multi_miller_loop;
use bls12_381::Scalar;
use bls12_381::{G1Affine, G2Affine, G2Prepared};
use group::prime::PrimeCurveAffine;
use group::Curve;
use std::mem;
use std::os::raw::c_void;
// use std::time::{Instant};
// Groth16 proof struct
pub struct Proof {
pub a: G1Affine,
pub b: G2Affine,
pub c: G1Affine,
}
// Groth16 verification key struct
pub struct VerifyingKey {
pub alpha_g1: G1Affine,
pub beta_g1: G1Affine,
pub beta_g2: G2Affine,
pub gamma_g2: G2Affine,
pub delta_g1: G1Affine,
pub delta_g2: G2Affine,
pub ic: Vec<G1Affine>,
}
#[no_mangle]
pub extern "C" fn allocate(size: usize) -> *mut c_void {
let mut buffer = Vec::with_capacity(size);
let pointer = buffer.as_mut_ptr();
mem::forget(buffer);
pointer as *mut c_void
// }
}
#[no_mangle]
fn deserialize_g1_wasm(buffer: &mut Vec<u8>) -> G1Affine {
let d_g1 = G1Affine::from_compressed(&buffer[0..48].try_into().unwrap())
.expect("Failed to deserialize vk");
d_g1
}
fn deserialize_g2_wasm(buffer: &mut Vec<u8>) -> G2Affine {
let d_g2 = G2Affine::from_compressed(&buffer[0..96].try_into().unwrap())
.expect("Failed to deserialize vk");
d_g2
}
#[no_mangle]
// pub extern fn bellman_groth16_test(pointer: *mut u8, capacity: usize) -> bool {
pub extern "C" fn bellman_groth16_test() -> bool {
// let mut bytes = Vec::new();
// unsafe {
// // println!("Test in vm {:?}", pointer);
// let v = Vec::from_raw_parts(pointer, capacity, capacity); //TODO no need to deallocate??
// bytes.extend_from_slice(&v);
// }
// Hardcode the input bytes for testing in different WASM VMs
// let bytes = [172, 197, 81, 189, 121, 193, 159, 27, 92, 95, 151, 164, 40, 59, 214, 96, 132, 58, 87, 37, 169, 1, 63, 230, 35, 74, 245, 6, 185, 56, 120, 108, 214, 179, 187, 21, 36, 206, 43, 160, 10, 250, 249, 73, 210, 35, 137, 87, 177, 66, 65, 154, 11, 232, 137, 246, 125, 72, 227, 222, 116, 168, 87, 24, 165, 160, 132, 109, 108, 101, 222, 143, 78, 97, 48, 95, 59, 177, 29, 247, 219, 166, 73, 249, 69, 206, 15, 151, 30, 248, 235, 63, 148, 240, 17, 22, 150, 67, 252, 141, 95, 179, 94, 111, 207, 201, 192, 144, 154, 94, 21, 2, 22, 58, 96, 144, 227, 107, 107, 182, 142, 0, 57, 27, 168, 39, 226, 40, 163, 159, 112, 83, 196, 182, 215, 74, 92, 20, 158, 60, 23, 184, 198, 143, 17, 6, 242, 7, 75, 220, 87, 47, 224, 145, 99, 169, 203, 218, 112, 185, 51, 102, 59, 56, 171, 46, 49, 255, 116, 108, 241, 50, 180, 247, 62, 218, 181, 197, 155, 80, 61, 252, 8, 41, 232, 73, 51, 250, 223, 82, 94, 8, 185, 83, 223, 187, 6, 41, 20, 62, 189, 254, 11, 11, 58, 187, 200, 88, 53, 234, 98, 172, 213, 62, 22, 34, 90, 166, 182, 133, 8, 230, 103, 219, 233, 141, 10, 137, 210, 151, 4, 129, 29, 92, 103, 251, 72, 182, 162, 59, 20, 222, 188, 232, 13, 74, 214, 182, 172, 120, 33, 198, 57, 204, 134, 93, 26, 79, 213, 45, 146, 6, 128, 103, 63, 202, 226, 120, 141, 193, 248, 65, 196, 235, 21, 184, 104, 228, 206, 117, 190, 28, 153, 183, 68, 36, 63, 60, 131, 87, 137, 213, 105, 27, 110, 37, 238, 200, 250, 145, 76, 25, 57, 81, 69, 164, 208, 255, 49, 80, 14, 64, 181, 143, 12, 58, 35, 63, 199, 35, 70, 25, 86, 158, 210, 150, 59, 159, 253, 238, 174, 211, 142, 166, 223, 51, 134, 118, 171, 27, 218, 219, 117, 163, 71, 134, 95, 142, 83, 251, 240, 241, 162, 232, 93, 248, 167, 112, 197, 212, 169, 209, 159, 101, 140, 248, 222, 234, 201, 169, 76, 242, 7, 10, 192, 30, 151, 167, 74, 186, 97, 121, 144, 36, 6, 187, 92, 7, 248, 45, 134, 85, 240, 112, 74, 224, 70, 64, 198, 59, 26, 195, 192, 140, 101, 118, 175, 17, 160, 195, 142, 133, 1, 139, 5, 130, 245, 17, 73, 176, 232, 107, 130, 172, 110, 20, 190, 37, 108, 250, 178, 187, 151, 158, 35, 248, 246, 143, 38, 212, 133, 226, 24, 45, 33, 164, 46, 125, 200, 157, 253, 225, 132, 181, 60, 90, 7, 240, 80, 232, 97, 206, 164, 28, 12, 75, 68, 126, 230, 145, 216, 45, 180, 203, 19, 152, 29, 203, 9, 4, 145, 122, 206, 146, 179, 44, 145, 191, 126, 199, 175, 171, 127, 189, 222, 108, 126, 161, 80, 190, 47, 44, 8, 40, 65, 68, 95, 61, 109, 148, 175, 113, 226, 8, 93, 126, 53, 39, 192, 196, 6, 152, 194, 105, 169, 226, 192, 201, 184, 198, 134, 210, 153, 170, 12, 241, 90, 250, 233, 20, 152, 119, 142, 120, 83, 2, 164, 80, 178, 125, 227, 253, 207, 240, 201, 127, 213, 196, 100, 90, 65, 120, 50, 108, 175, 34, 192, 197, 173, 202, 176, 210, 131, 22, 216, 57, 169, 241, 28, 40, 44, 62, 11, 42, 50, 46, 204, 242, 109, 158, 114, 41, 127, 206, 25, 194, 255, 128, 245, 232, 193, 189, 229, 51, 93, 94, 64, 117, 33, 132, 75, 253, 114, 64, 116, 155, 183, 137, 112, 201, 243, 13, 221, 142, 164, 59, 98, 152, 249, 40, 133, 70, 185, 231, 249, 151, 253, 240, 122, 214, 60, 18, 132, 177, 37, 42, 75, 206, 12, 100, 214, 248, 234, 78, 165, 74, 212, 248, 32, 162, 254, 227, 218, 46, 9, 87, 0, 118, 13, 249, 107, 83, 5, 138, 223, 9, 247, 70, 160, 228, 197, 54, 87, 18, 1, 37, 199, 162, 84, 189, 161, 10, 26, 75, 45, 168, 185, 153, 245, 243, 51, 176, 208, 187, 235, 135, 239, 231, 42, 43, 233, 150, 46, 249, 73, 229, 138, 84, 89, 75, 129, 238, 211, 80, 147, 67, 159, 227, 214, 131, 188, 130, 70, 224, 1, 77, 139, 239, 185, 53, 68, 41, 193, 207, 16, 2, 33, 139, 214, 103, 240, 14, 141, 223, 24, 236, 50, 64, 79, 178, 6, 79, 38, 165, 35, 173, 203, 101, 3, 162, 49, 51, 4, 151, 127, 49, 47, 223, 244, 157, 229, 7, 88, 106, 141, 167, 183, 220, 15, 8, 119, 12, 82, 218, 14, 207, 0, 73, 27, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let bytes = [
147, 235, 138, 182, 249, 146, 149, 28, 58, 36, 144, 99, 188, 155, 153, 135, 239, 79, 76,
109, 152, 156, 202, 1, 153, 84, 239, 184, 69, 145, 133, 48, 156, 80, 122, 227, 231, 161,
137, 232, 67, 183, 34, 186, 230, 135, 25, 90, 136, 201, 110, 134, 208, 93, 78, 82, 153,
239, 208, 236, 160, 231, 192, 150, 215, 128, 193, 255, 107, 39, 133, 12, 136, 148, 119, 17,
59, 198, 100, 49, 37, 89, 132, 205, 45, 79, 151, 112, 247, 140, 94, 179, 215, 165, 52, 182,
153, 68, 204, 210, 218, 156, 69, 74, 192, 30, 160, 13, 80, 188, 23, 112, 21, 124, 91, 147,
21, 140, 217, 226, 248, 60, 182, 119, 18, 34, 32, 41, 181, 128, 165, 97, 168, 76, 98, 44,
114, 122, 128, 215, 68, 156, 18, 91, 5, 33, 22, 141, 249, 137, 49, 252, 82, 122, 206, 58,
183, 108, 176, 15, 38, 183, 87, 254, 34, 102, 195, 78, 166, 227, 96, 180, 137, 173, 131,
178, 179, 25, 89, 159, 5, 73, 125, 24, 25, 86, 227, 19, 184, 117, 228, 173, 150, 1, 82,
142, 48, 251, 236, 132, 73, 79, 201, 165, 192, 191, 195, 60, 100, 198, 251, 187, 161, 220,
63, 143, 38, 21, 189, 219, 194, 100, 64, 186, 102, 7, 186, 213, 227, 92, 228, 52, 181, 171,
223, 222, 218, 206, 221, 22, 15, 46, 77, 175, 34, 43, 221, 110, 21, 89, 149, 213, 68, 242,
140, 185, 176, 73, 88, 216, 75, 237, 209, 10, 75, 251, 152, 101, 15, 146, 168, 27, 81, 8,
61, 76, 103, 230, 171, 23, 144, 171, 6, 118, 157, 233, 234, 214, 132, 106, 30, 171, 121,
77, 147, 175, 170, 62, 48, 251, 12, 221, 202, 109, 80, 97, 180, 27, 45, 87, 162, 19, 168,
152, 27, 205, 113, 91, 83, 52, 99, 109, 17, 149, 189, 244, 174, 164, 192, 79, 133, 111,
195, 215, 232, 129, 166, 204, 3, 169, 248, 49, 18, 190, 198, 145, 177, 169, 10, 4, 66, 134,
46, 11, 163, 170, 94, 230, 234, 234, 43, 122, 51, 230, 100, 106, 149, 228, 208, 217, 87,
231, 125, 170, 47, 143, 151, 45, 208, 64, 91, 10, 188, 136, 15, 155, 131, 200, 141, 243,
200, 5, 109, 22, 98, 189, 193, 44, 40, 95, 126, 145, 234, 190, 205, 179, 172, 224, 147,
253, 238, 162, 157, 60, 126, 9, 174, 34, 16, 161, 197, 60, 243, 211, 241, 78, 114, 51, 167,
214, 53, 149, 172, 56, 149, 32, 66, 123, 48, 240, 179, 53, 154, 29, 134, 34, 141, 204, 168,
184, 158, 165, 115, 241, 119, 228, 11, 35, 82, 186, 132, 103, 65, 243, 215, 31, 105, 201,
191, 155, 210, 53, 194, 76, 63, 199, 181, 28, 138, 181, 181, 211, 145, 15, 139, 244, 38,
56, 159, 161, 95, 46, 147, 141, 163, 221, 88, 167, 134, 73, 45, 70, 98, 98, 167, 55, 52,
234, 110, 150, 79, 248, 157, 167, 84, 210, 89, 10, 193, 169, 32, 40, 218, 7, 236, 206, 85,
178, 174, 157, 132, 181, 192, 119, 60, 205, 46, 217, 120, 97, 59, 82, 121, 11, 189, 21,
213, 176, 255, 225, 57, 76, 239, 38, 99, 226, 55, 98, 227, 10, 45, 193, 69, 255, 247, 39,
121, 86, 150, 6, 220, 98, 41, 132, 237, 189, 169, 110, 213, 115, 33, 228, 197, 61, 219,
202, 58, 54, 70, 223, 179, 208, 139, 232, 103, 76, 165, 169, 68, 6, 148, 47, 244, 26, 203,
186, 110, 69, 44, 175, 128, 119, 212, 188, 167, 223, 87, 119, 238, 199, 201, 61, 78, 96,
175, 0, 156, 145, 196, 253, 162, 175, 172, 227, 80, 251, 96, 61, 189, 35, 13, 97, 22, 157,
86, 249, 128, 148, 172, 66, 80, 172, 208, 222, 131, 0, 207, 80, 163, 27, 155, 113, 57, 186,
246, 139, 111, 71, 117, 152, 184, 60, 1, 230, 44, 169, 213, 88, 82, 156, 194, 234, 41, 183,
87, 36, 175, 154, 156, 128, 59, 187, 208, 101, 9, 51, 205, 42, 174, 29, 215, 43, 150, 183,
129, 125, 2, 84, 210, 149, 245, 126, 140, 166, 255, 134, 116, 162, 107, 82, 178, 158, 38,
11, 135, 91, 224, 157, 112, 189, 164, 250, 1, 215, 49, 21, 214, 211, 73, 243, 251, 58, 198,
1, 165, 196, 122, 13, 238, 252, 227, 229, 149, 47, 13, 173, 171, 176, 185, 220, 82, 96,
163, 4, 36, 199, 152, 88, 3, 162, 49, 51, 4, 151, 127, 49, 47, 223, 244, 157, 229, 7, 88,
106, 141, 167, 183, 220, 15, 8, 119, 12, 82, 218, 14, 207, 0, 73, 27, 5, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
// ***** Test deserialization and reconstruction of vk *****
// let start_key_recons = Instant::now();
// println!("Start verification key reconstruction");
// alpha_g1
let mut vec_alpha_g1 = bytes[0..48].to_vec();
let r_alpha_g1 = deserialize_g1_wasm(&mut vec_alpha_g1);
// beta_g1
let mut vec_beta_g1 = bytes[48..96].to_vec();
let r_beta_g1 = deserialize_g1_wasm(&mut vec_beta_g1);
// beta_g2
let mut vec_beta_g2 = bytes[96..192].to_vec();
let r_beta_g2 = deserialize_g2_wasm(&mut vec_beta_g2);
// gamma_g2
let mut vec_gamma_g2 = bytes[192..288].to_vec();
let r_gamma_g2 = deserialize_g2_wasm(&mut vec_gamma_g2);
// delta_g1
let mut vec_delta_g1 = bytes[288..336].to_vec();
let r_delta_g1 = deserialize_g1_wasm(&mut vec_delta_g1);
// delta_g2
let mut vec_delta_g2 = bytes[336..432].to_vec();
let r_delta_g2 = deserialize_g2_wasm(&mut vec_delta_g2);
// ic
let vec_ic = bytes[432..576].to_vec();
// println!("\nic vector: {:?}", vec_ic);
let mut r_ic: Vec<G1Affine> = Vec::new();
let mut vec_ic_de = vec_ic[0..48].to_vec();
r_ic.push(deserialize_g1_wasm(&mut vec_ic_de));
vec_ic_de = vec_ic[48..96].to_vec();
r_ic.push(deserialize_g1_wasm(&mut vec_ic_de));
vec_ic_de = vec_ic[96..144].to_vec();
r_ic.push(deserialize_g1_wasm(&mut vec_ic_de));
// Reconstruct vk
// replace following if using bellman::{groth16, groth16::Proof};
// let deserialized_vk = groth16::VerifyingKey::<Bls12> {
let deserialized_vk = VerifyingKey {
alpha_g1: r_alpha_g1,
beta_g1: r_beta_g1,
beta_g2: r_beta_g2,
gamma_g2: r_gamma_g2,
delta_g1: r_delta_g1,
delta_g2: r_delta_g2,
ic: r_ic,
};
// Uncomment following if using bellman::{groth16, groth16::Proof};
// let pvk = groth16::prepare_verifying_key(&deserialized_vk);
// println!("Key reconstruction time: {:?}", start_key_recons.elapsed());
// ***** Reconstruct proof *****
// let start_proof_recons = Instant::now();
// proof.g1
let r_a = G1Affine::from_compressed(&bytes[576..624].try_into().unwrap())
.expect("Failed to deserialize a");
// proof.g2
let r_b = G2Affine::from_compressed(&bytes[624..720].try_into().unwrap())
.expect("Failed to deserialize b");
// proof.g1
let r_c = G1Affine::from_compressed(&bytes[720..768].try_into().unwrap())
.expect("Failed to deserialize c");
// Replace following if using bellman::{groth16, groth16::Proof};
// let r_proof: Proof<Bls12> = Proof{a: r_a, b: r_b, c: r_c};
let r_proof: Proof = Proof {
a: r_a,
b: r_b,
c: r_c,
};
// println!("Proof reconstruction time: {:?}", start_proof_recons.elapsed());
// ***** Reconstruct input *****
// let start_input_recons = Instant::now();
let last_64_bytes = &bytes[bytes.len() - 64..];
let r_inputs: Vec<Scalar> = last_64_bytes
.chunks(32) // Each Scalar in bls12_381 uses 32 bytes
.map(|chunk| {
Scalar::from_bytes(chunk.try_into().unwrap()).expect("Invalid bytes for Scalar")
})
.collect();
// println!("Input reconstruction time: {:?}", start_input_recons.elapsed());
/***** proof verification *****/
// uncomment following if bellman groth16 is used
// assert!(groth16::verify_proof(&pvk, &r_proof, &r_inputs).is_ok());
// let start_verify = Instant::now();
// Ensure the number of inputs matches the vk.ic length minus 1 (for IC[0])
if (r_inputs.len() + 1) != deserialized_vk.ic.len() {
return false;
}
/***** Compute linear combination: input_acc = IC[0] + sum(input[i] * IC[i+1]) *****/
let mut acc = deserialized_vk.ic[0].to_curve(); // Convert G1Affine to G1Projective
// Computes multi-scalar multiplication,
// which is a weighted sum of elliptic curve points.
// In Groth16, this builds the point:
// acc = IC₀ + input₁ × IC₁ + input₂ × IC₂ + ... + inputₙ × ICₙ
// Where: ICᵢ are fixed elliptic curve points (from the verifying key).
// inputᵢ are the public inputs to the circuit.
// Example: public_inputs = [x₁, x₂], vk.ic = [IC₀, IC₁, IC₂], acc = IC₀ + x₁ * IC₁ + x₂ * IC₂
// This binds the public inputs to the proof
for (input, ic_point) in r_inputs.iter().zip(&deserialized_vk.ic[1..]) {
acc += ic_point.to_curve() * input;
}
let acc_affine = acc.to_affine(); // converts the point acc from projective form back to affine form.
// Preparing G2 elements for pairing by converting them into G2Prepared format.
let proof_b_prepared = G2Prepared::from(r_proof.b);
let gamma_g2_prepared = G2Prepared::from(deserialized_vk.gamma_g2);
let delta_g2_prepared = G2Prepared::from(deserialized_vk.delta_g2);
let beta_g2_prepared = G2Prepared::from(deserialized_vk.beta_g2);
// Compute required product of pairings in their Miller loop form
// Groth16 verifier checks if e(A, B) * e(acc, γ)⁻¹ * e(C, δ)⁻¹ * e(α, β)⁻¹ == 1
// which boils down to
// let start_miller = Instant::now();
let ml_result = multi_miller_loop(&[
(&r_proof.a, &proof_b_prepared), // e(A,B)
(&(-acc_affine), &gamma_g2_prepared), // e(acc, γ)⁻¹
(&(-r_proof.c), &delta_g2_prepared), // e(C, δ)⁻¹
(&(-deserialized_vk.alpha_g1), &beta_g2_prepared), //e(α, β)⁻¹
]);
// println!("Miller time: {:?}", start_miller.elapsed());
// let start_final = Instant::now();
let result = ml_result.final_exponentiation();
// println!("Final time: {:?}", start_final.elapsed());
// println!("Proof verification time: {:?}", start_verify.elapsed());
// true
result == bls12_381::Gt::identity()
}

View File

@@ -178,7 +178,6 @@ struct Peer
using NodeKey = Validation::NodeKey;
//! Logging support that prefixes messages with the peer ID
beast::WrappedSink sink;
beast::Journal j;
//! Generic consensus
@@ -284,8 +283,7 @@ struct Peer
TrustGraph<Peer*>& tg,
CollectorRefs& c,
beast::Journal jIn)
: sink(jIn, "Peer " + to_string(i) + ": ")
, j(sink)
: j(jIn, log::attributes(log::attr("Peer", "Peer " + to_string(i))))
, consensus(s.clock(), *this, j)
, id{i}
, key{id, 0}

View File

@@ -94,81 +94,16 @@ std::array<std::uint8_t, 39> const cb3 = {
0x26, 0x4A, 0x2D, 0x85, 0x7B, 0xE8, 0xA0, 0x9C, 0x1D, 0xFD,
0x57, 0x0D, 0x15, 0x85, 0x8B, 0xD4, 0x81, 0x01, 0x04}};
/** Set the "FinishAfter" time tag on a JTx */
auto const finish_time = JTxFieldWrapper<timePointField>(sfFinishAfter);
/** Set the "CancelAfter" time tag on a JTx */
auto const cancel_time = JTxFieldWrapper<timePointField>(sfCancelAfter);
auto const condition = JTxFieldWrapper<blobField>(sfCondition);
auto const fulfillment = JTxFieldWrapper<blobField>(sfFulfillment);
struct finish_function
{
private:
std::string value_;
public:
explicit finish_function(std::string func) : value_(func)
{
}
explicit finish_function(Slice const& func) : value_(strHex(func))
{
}
template <size_t N>
explicit finish_function(std::array<std::uint8_t, N> const& f)
: finish_function(makeSlice(f))
{
}
void
operator()(Env&, JTx& jt) const
{
jt.jv[sfFinishFunction.jsonName] = value_;
}
};
struct data
{
private:
std::string value_;
public:
explicit data(std::string func) : value_(func)
{
}
explicit data(Slice const& func) : value_(strHex(func))
{
}
template <size_t N>
explicit data(std::array<std::uint8_t, N> const& f) : data(makeSlice(f))
{
}
void
operator()(Env&, JTx& jt) const
{
jt.jv[sfData.jsonName] = value_;
}
};
struct comp_allowance
{
private:
std::uint32_t value_;
public:
explicit comp_allowance(std::uint32_t const& value) : value_(value)
{
}
void
operator()(Env&, JTx& jt) const
{
jt.jv[sfComputationAllowance.jsonName] = value_;
}
};
} // namespace escrow
} // namespace jtx

View File

@@ -33,14 +33,9 @@ setupConfigForUnitTests(Config& cfg)
using namespace jtx;
// Default fees to old values, so tests don't have to worry about changes in
// Config.h
// NOTE: For new `FEES` fields, you need to wait for the first flag ledger
// to close for the values to be activated.
cfg.FEES.reference_fee = UNIT_TEST_REFERENCE_FEE;
cfg.FEES.account_reserve = XRP(200).value().xrp().drops();
cfg.FEES.owner_reserve = XRP(50).value().xrp().drops();
cfg.FEES.extension_compute_limit = 1'000'000;
cfg.FEES.extension_size_limit = 100'000;
cfg.FEES.gas_price = 1'000'000; // 1 drop = 1,000,000 micro-drops
// The Beta API (currently v2) is always available to tests
cfg.BETA_RPC_API = true;

View File

@@ -122,27 +122,10 @@ struct STAccount_test : public beast::unit_test::suite
}
}
void
testAccountID()
{
auto const s = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
if (auto const parsed = parseBase58<AccountID>(s); BEAST_EXPECT(parsed))
{
BEAST_EXPECT(toBase58(*parsed) == s);
}
{
auto const s =
"âabcd1rNxp4h8apvRis6mJf9Sh8C6iRxfrDWNâabcdAVâ\xc2\x80\xc2\x8f";
BEAST_EXPECT(!parseBase58<AccountID>(s));
}
}
void
run() override
{
testSTAccount();
testAccountID();
}
};

View File

@@ -18,7 +18,10 @@
//==============================================================================
#include <xrpl/beast/unit_test.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/Permissions.h>
#include <xrpl/protocol/STInteger.h>
#include <xrpl/protocol/TxFormats.h>
namespace ripple {
@@ -27,11 +30,27 @@ struct STInteger_test : public beast::unit_test::suite
void
testUInt8()
{
STUInt8 u8(42);
BEAST_EXPECT(u8.value() == 42);
BEAST_EXPECT(u8.getText() == "42");
STUInt8 u8(255);
BEAST_EXPECT(u8.value() == 255);
BEAST_EXPECT(u8.getText() == "255");
BEAST_EXPECT(u8.getSType() == STI_UINT8);
BEAST_EXPECT(u8.getJson(JsonOptions::none) == 42);
BEAST_EXPECT(u8.getJson(JsonOptions::none) == 255);
// there is some special handling for sfTransactionResult
STUInt8 tr(sfTransactionResult, 0);
BEAST_EXPECT(tr.value() == 0);
BEAST_EXPECT(
tr.getText() ==
"The transaction was applied. Only final in a validated ledger.");
BEAST_EXPECT(tr.getSType() == STI_UINT8);
BEAST_EXPECT(tr.getJson(JsonOptions::none) == "tesSUCCESS");
// invalid transaction result
STUInt8 tr2(sfTransactionResult, 255);
BEAST_EXPECT(tr2.value() == 255);
BEAST_EXPECT(tr2.getText() == "255");
BEAST_EXPECT(tr2.getSType() == STI_UINT8);
BEAST_EXPECT(tr2.getJson(JsonOptions::none) == 255);
}
void
@@ -42,40 +61,63 @@ struct STInteger_test : public beast::unit_test::suite
BEAST_EXPECT(u16.getText() == "65535");
BEAST_EXPECT(u16.getSType() == STI_UINT16);
BEAST_EXPECT(u16.getJson(JsonOptions::none) == 65535);
// there is some special handling for sfLedgerEntryType
STUInt16 let(sfLedgerEntryType, ltACCOUNT_ROOT);
BEAST_EXPECT(let.value() == ltACCOUNT_ROOT);
BEAST_EXPECT(let.getText() == "AccountRoot");
BEAST_EXPECT(let.getSType() == STI_UINT16);
BEAST_EXPECT(let.getJson(JsonOptions::none) == "AccountRoot");
// there is some special handling for sfTransactionType
STUInt16 tlt(sfTransactionType, ttPAYMENT);
BEAST_EXPECT(tlt.value() == ttPAYMENT);
BEAST_EXPECT(tlt.getText() == "Payment");
BEAST_EXPECT(tlt.getSType() == STI_UINT16);
BEAST_EXPECT(tlt.getJson(JsonOptions::none) == "Payment");
}
void
testUInt32()
{
STUInt32 u32(1234567890);
BEAST_EXPECT(u32.value() == 1234567890);
BEAST_EXPECT(u32.getText() == "1234567890");
STUInt32 u32(4'294'967'295u);
BEAST_EXPECT(u32.value() == 4'294'967'295u);
BEAST_EXPECT(u32.getText() == "4294967295");
BEAST_EXPECT(u32.getSType() == STI_UINT32);
BEAST_EXPECT(u32.getJson(JsonOptions::none) == 1234567890);
BEAST_EXPECT(u32.getJson(JsonOptions::none) == 4'294'967'295u);
// there is some special handling for sfPermissionValue
STUInt32 pv(sfPermissionValue, ttPAYMENT + 1);
BEAST_EXPECT(pv.value() == ttPAYMENT + 1);
BEAST_EXPECT(pv.getText() == "Payment");
BEAST_EXPECT(pv.getSType() == STI_UINT32);
BEAST_EXPECT(pv.getJson(JsonOptions::none) == "Payment");
STUInt32 pv2(sfPermissionValue, PaymentMint);
BEAST_EXPECT(pv2.value() == PaymentMint);
BEAST_EXPECT(pv2.getText() == "PaymentMint");
BEAST_EXPECT(pv2.getSType() == STI_UINT32);
BEAST_EXPECT(pv2.getJson(JsonOptions::none) == "PaymentMint");
}
void
testUInt64()
{
STUInt64 u64(0x123456789ABCDEF0ull);
BEAST_EXPECT(u64.value() == 0x123456789ABCDEF0ull);
BEAST_EXPECT(u64.getText() == "1311768467463790320");
STUInt64 u64(0xFFFFFFFFFFFFFFFFull);
BEAST_EXPECT(u64.value() == 0xFFFFFFFFFFFFFFFFull);
BEAST_EXPECT(u64.getText() == "18446744073709551615");
BEAST_EXPECT(u64.getSType() == STI_UINT64);
// By default, getJson returns hex string
auto jsonVal = u64.getJson(JsonOptions::none);
BEAST_EXPECT(jsonVal.isString());
BEAST_EXPECT(jsonVal.asString() == "123456789abcdef0");
}
BEAST_EXPECT(jsonVal.asString() == "ffffffffffffffff");
void
testInt32()
{
STInt32 i32(-123456789);
BEAST_EXPECT(i32.value() == -123456789);
BEAST_EXPECT(i32.getText() == "-123456789");
BEAST_EXPECT(i32.getSType() == STI_INT32);
BEAST_EXPECT(i32.getJson(JsonOptions::none) == -123456789);
STUInt64 u64_2(sfMaximumAmount, 0xFFFFFFFFFFFFFFFFull);
BEAST_EXPECT(u64_2.value() == 0xFFFFFFFFFFFFFFFFull);
BEAST_EXPECT(u64_2.getText() == "18446744073709551615");
BEAST_EXPECT(u64_2.getSType() == STI_UINT64);
BEAST_EXPECT(
u64_2.getJson(JsonOptions::none) == "18446744073709551615");
}
void
@@ -85,7 +127,6 @@ struct STInteger_test : public beast::unit_test::suite
testUInt16();
testUInt32();
testUInt64();
testInt32();
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <xrpl/beast/unit_test.h>
#include <xrpl/protocol/UintTypes.h>
namespace ripple {
struct types_test : public beast::unit_test::suite
{
void
testAccountID()
{
auto const s = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
if (auto const parsed = parseBase58<AccountID>(s); BEAST_EXPECT(parsed))
{
BEAST_EXPECT(toBase58(*parsed) == s);
}
{
auto const s =
"âabcd1rNxp4h8apvRis6mJf9Sh8C6iRxfrDWNâabcdAVâ\xc2\x80\xc2\x8f";
BEAST_EXPECT(!parseBase58<AccountID>(s));
}
}
void
run() override
{
testAccountID();
}
};
BEAST_DEFINE_TESTSUITE(types, protocol, ripple);
} // namespace ripple

View File

@@ -12,3 +12,5 @@ xrpl_add_test(basics)
target_link_libraries(xrpl.test.basics PRIVATE xrpl.imports.test)
xrpl_add_test(crypto)
target_link_libraries(xrpl.test.crypto PRIVATE xrpl.imports.test)
xrpl_add_test(net)
target_link_libraries(xrpl.test.net PRIVATE xrpl.imports.test)

View File

@@ -0,0 +1,766 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <xrpl/basics/Log.h>
#include <boost/json.hpp>
#include <doctest/doctest.h>
#include <iostream>
#include <numbers>
using namespace ripple;
class MockLogs : public Logs
{
private:
class Sink : public beast::Journal::Sink
{
private:
MockLogs& logs_;
std::string partition_;
public:
Sink(
std::string const& partition,
beast::severities::Severity thresh,
MockLogs& logs)
: beast::Journal::Sink(thresh, false)
, logs_(logs)
, partition_(partition)
{
}
Sink(Sink const&) = delete;
Sink&
operator=(Sink const&) = delete;
void
write(beast::severities::Severity level, std::string const& text)
override
{
logs_.write(level, partition_, text, false);
}
void
writeAlways(beast::severities::Severity level, std::string const& text)
override
{
logs_.write(level, partition_, text, false);
}
};
std::string& logStream_;
public:
MockLogs(std::string& logStream, beast::severities::Severity level)
: Logs(level), logStream_(logStream)
{
}
std::unique_ptr<beast::Journal::Sink>
makeSink(
std::string const& partition,
beast::severities::Severity startingLevel) override
{
return std::make_unique<Sink>(partition, startingLevel, *this);
}
void
write(
beast::severities::Severity level,
std::string const& partition,
std::string const& text,
bool console)
{
std::string s;
std::string_view result = text;
if (!beast::Journal::isStructuredJournalEnabled())
{
format(s, text, level, partition);
result = s;
}
logStream_.append(result);
}
};
TEST_CASE("Text logs")
{
std::string logStream;
MockLogs logs{logStream, beast::severities::kAll};
logs.journal("Test").debug() << "Test";
CHECK(logStream.find("Test") != std::string::npos);
logStream.clear();
logs.journal("Test").debug() << "\n";
CHECK(logStream.find("\n") == std::string::npos);
}
TEST_CASE("Test format output")
{
std::string output;
Logs::format(output, "Msg", beast::severities::kDebug, "Test");
CHECK(output.find("Msg") != std::string::npos);
CHECK(output != "Msg");
}
TEST_CASE("Enable json logs")
{
std::string logStream;
MockLogs logs{logStream, beast::severities::kAll};
logs.journal("Test ").debug() << "Test123";
CHECK(logStream.find("Test123") != std::string::npos);
logStream.clear();
beast::Journal::enableStructuredJournal();
logs.journal("Test").debug() << "\n";
boost::system::error_code ec;
auto doc = boost::json::parse(logStream, ec);
CHECK(ec == boost::system::errc::success);
CHECK(doc.is_object());
CHECK(doc.as_object().contains("Msg"));
CHECK(doc.as_object()["Msg"].is_string());
CHECK(doc.as_object()["Msg"].get_string() == "");
beast::Journal::disableStructuredJournal();
}
TEST_CASE("Global attributes")
{
std::string logStream;
MockLogs logs{logStream, beast::severities::kAll};
beast::Journal::enableStructuredJournal();
beast::Journal::addGlobalAttributes(
log::attributes(log::attr("Field1", "Value1")));
logs.journal("Test").debug() << "Test";
boost::system::error_code ec;
auto jsonLog = boost::json::parse(logStream, ec);
CHECK(ec == boost::system::errc::success);
CHECK(jsonLog.is_object());
CHECK(jsonLog.as_object().contains("Glb"));
CHECK(jsonLog.as_object()["Glb"].is_object());
CHECK(jsonLog.as_object()["Glb"].as_object().contains("Field1"));
CHECK(jsonLog.as_object()["Glb"].as_object()["Field1"].is_string());
CHECK(
jsonLog.as_object()["Glb"].as_object()["Field1"].get_string() ==
"Value1");
beast::Journal::disableStructuredJournal();
}
TEST_CASE("Global attributes inheritable")
{
std::string logStream;
MockLogs logs{logStream, beast::severities::kAll};
beast::Journal::enableStructuredJournal();
beast::Journal::addGlobalAttributes(
log::attributes(log::attr("Field1", "Value1")));
logs.journal(
"Test",
log::attributes(
log::attr("Field1", "Value3"), log::attr("Field2", "Value2")))
.debug()
<< "Test";
boost::system::error_code ec;
auto jsonLog = boost::json::parse(logStream, ec);
CHECK(ec == boost::system::errc::success);
CHECK(jsonLog.is_object());
CHECK(jsonLog.as_object()["Glb"].as_object().contains("Field1"));
CHECK(jsonLog.as_object()["Glb"].as_object()["Field1"].is_string());
CHECK(
jsonLog.as_object()["Glb"].as_object()["Field1"].get_string() ==
"Value1");
CHECK(
jsonLog.as_object()["Jnl"].as_object()["Field1"].get_string() ==
"Value3");
CHECK(
jsonLog.as_object()["Jnl"].as_object()["Field2"].get_string() ==
"Value2");
beast::Journal::disableStructuredJournal();
}
TEST_CASE("Test JsonWriter")
{
{
std::string buffer;
beast::detail::SimpleJsonWriter writer{&buffer};
writer.writeString("\n\r\t123\b\f123");
writer.finish();
CHECK(writer.buffer() == "\"\\n\\r\\t123\\b\\f123\"");
}
{
std::string buffer;
beast::detail::SimpleJsonWriter writer{&buffer};
writer.writeString("\t");
writer.finish();
CHECK(writer.buffer() == "\"\\t\"");
}
{
std::string buffer;
beast::detail::SimpleJsonWriter writer{&buffer};
writer.writeString(std::string_view{"\0", 1});
writer.finish();
CHECK(writer.buffer() == "\"\\u0000\"");
}
{
std::string buffer;
beast::detail::SimpleJsonWriter writer{&buffer};
writer.writeString("\"\\");
writer.finish();
CHECK(writer.buffer() == "\"\\\"\\\\\"");
}
{
std::string buffer;
beast::detail::SimpleJsonWriter writer{&buffer};
writer.startArray();
writer.writeBool(true);
writer.writeBool(false);
writer.writeNull();
writer.endArray();
writer.finish();
CHECK(writer.buffer() == "[true,false,null]");
}
}
namespace test_detail {
struct ToCharsStruct
{
};
std::to_chars_result
to_chars(char* first, char* last, ToCharsStruct)
{
*first = '0';
return std::to_chars_result{first + 1, std::errc{}};
}
struct StreamStruct
{
};
std::ostream&
operator<<(std::ostream& os, StreamStruct)
{
os << "0";
return os;
}
} // namespace test_detail
TEST_CASE("Test setJsonValue")
{
std::ostringstream stringBuf;
std::string buffer;
beast::detail::SimpleJsonWriter writer{&buffer};
writer.startObject();
log::detail::setJsonValue<bool>(writer, "testBool", true, &stringBuf);
log::detail::setJsonValue<std::int32_t>(
writer, "testInt32", -1, &stringBuf);
log::detail::setJsonValue<std::uint32_t>(
writer, "testUInt32", 1, &stringBuf);
log::detail::setJsonValue<std::int64_t>(
writer, "testInt64", -1, &stringBuf);
log::detail::setJsonValue<std::uint64_t>(
writer, "testUInt64", 1, &stringBuf);
log::detail::setJsonValue<double>(writer, "testDouble", 1.1, &stringBuf);
log::detail::setJsonValue<char const*>(
writer, "testCharStar", "Char*", &stringBuf);
log::detail::setJsonValue<std::string>(
writer, "testStdString", "StdString", &stringBuf);
log::detail::setJsonValue<std::string_view>(
writer, "testStdStringView", "StdStringView", &stringBuf);
log::detail::setJsonValue<test_detail::ToCharsStruct>(
writer, "testToChars", {}, &stringBuf);
log::detail::setJsonValue<test_detail::StreamStruct>(
writer, "testStream", {}, &stringBuf);
writer.endObject();
writer.finish();
CHECK(
writer.buffer() ==
R"AAA({"testBool":true,"testInt32":-1,"testUInt32":1,"testInt64":-1,"testUInt64":1,"testDouble":1.1,"testCharStar":"Char*","testStdString":"StdString","testStdStringView":"StdStringView","testToChars":"0","testStream":"0"})AAA");
}
TEST_CASE("Test json logging not enabled")
{
std::string logStream;
MockLogs logs{logStream, beast::severities::kAll};
beast::Journal::disableStructuredJournal();
beast::Journal::addGlobalAttributes(
log::attributes(log::attr("Field1", "Value1")));
logs.journal("Test123").debug()
<< "Test " << log::param(" Field1", "Value1")
<< log::field("Field2", "Value2");
CHECK(logStream.find("Test Value1") != std::string::npos);
}
/**
* @brief sink for writing all log messages to a stringstream
*/
class MockSink : public beast::Journal::Sink
{
std::stringstream& strm_;
public:
MockSink(beast::severities::Severity threshold, std::stringstream& strm)
: beast::Journal::Sink(threshold, false), strm_(strm)
{
}
void
write(beast::severities::Severity level, std::string const& text) override
{
strm_ << text;
}
void
writeAlways(beast::severities::Severity level, std::string const& text)
override
{
strm_ << text;
}
};
class JsonLogStreamFixture
{
public:
JsonLogStreamFixture()
: sink_(beast::severities::kAll, logStream_)
, j_(beast::Journal::getNullSink())
{
beast::Journal::resetGlobalAttributes();
beast::Journal::enableStructuredJournal();
j_ = beast::Journal{
sink_, "Test", log::attributes(log::attr("Field1", "Value1"))};
}
~JsonLogStreamFixture()
{
beast::Journal::disableStructuredJournal();
}
std::stringstream&
stream()
{
return logStream_;
}
beast::Journal&
journal()
{
return j_;
}
private:
MockSink sink_;
std::stringstream logStream_;
beast::Journal j_;
};
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test json log fields")
{
beast::Journal::addGlobalAttributes(
log::attributes(log::attr("Field2", "Value2")));
journal().debug() << std::boolalpha << true << std::noboolalpha << " Test "
<< std::boolalpha << false
<< log::field("Field3", "Value3");
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.is_object());
CHECK(logValue.as_object().contains("Glb"));
CHECK(logValue.as_object().contains("Jnl"));
CHECK(logValue.as_object().contains("Mtd"));
CHECK(logValue.as_object().contains("Msg"));
CHECK(logValue.as_object()["Glb"].is_object());
CHECK(logValue.as_object()["Jnl"].is_object());
CHECK(logValue.as_object()["Mtd"].is_object());
CHECK(logValue.as_object()["Msg"].is_string());
CHECK(logValue.as_object()["Mtd"].as_object().contains("Fl"));
CHECK(logValue.as_object()["Mtd"].as_object().contains("Ln"));
CHECK(logValue.as_object()["Mtd"].as_object().contains("ThId"));
CHECK(logValue.as_object()["Mtd"].as_object().contains("Lv"));
CHECK(logValue.as_object()["Mtd"].as_object().contains("Tm"));
CHECK(logValue.as_object()["Mtd"].as_object()["Fl"].is_string());
CHECK(logValue.as_object()["Mtd"].as_object()["Ln"].is_number());
CHECK(
logValue.as_object()["Msg"].get_string() ==
std::string{"true Test false"});
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test json log levels")
{
{
stream().str("");
journal().trace() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(
logValue.as_object()["Mtd"].as_object()["Lv"].get_string() ==
beast::severities::to_string(beast::severities::kTrace));
}
{
stream().str("");
journal().debug() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(
logValue.as_object()["Mtd"].as_object()["Lv"].get_string() ==
beast::severities::to_string(beast::severities::kDebug));
}
{
stream().str("");
journal().info() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(
logValue.as_object()["Mtd"].as_object()["Lv"].get_string() ==
beast::severities::to_string(beast::severities::kInfo));
}
{
stream().str("");
journal().warn() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(
logValue.as_object()["Mtd"].as_object()["Lv"].get_string() ==
beast::severities::to_string(beast::severities::kWarning));
}
{
stream().str("");
journal().error() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(
logValue.as_object()["Mtd"].as_object()["Lv"].get_string() ==
beast::severities::to_string(beast::severities::kError));
}
{
stream().str("");
journal().fatal() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(
logValue.as_object()["Mtd"].as_object()["Lv"].get_string() ==
beast::severities::to_string(beast::severities::kFatal));
}
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test json log stream")
{
journal().stream(beast::severities::kError) << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(
logValue.as_object()["Mtd"].as_object()["Lv"].get_string() ==
beast::severities::to_string(beast::severities::kError));
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test json log params")
{
journal().debug() << "Test: " << log::param("Field1", 1) << ", "
<< log::param(
"Field2",
std::numeric_limits<std::uint64_t>::max())
<< ", " << log::param("Field3", std::numbers::pi);
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["Dt"].is_object());
CHECK(logValue.as_object()["Dt"].as_object()["Field1"].is_number());
CHECK(logValue.as_object()["Dt"].as_object()["Field1"].get_int64() == 1);
CHECK(logValue.as_object()["Dt"].as_object()["Field2"].is_number());
CHECK(
logValue.as_object()["Dt"].as_object()["Field2"].get_uint64() ==
std::numeric_limits<std::uint64_t>::max());
auto field3Val =
logValue.as_object()["Dt"].as_object()["Field3"].get_double();
auto difference = std::abs(field3Val - std::numbers::pi);
CHECK(difference < 1e-4);
CHECK(logValue.as_object()["Msg"].is_string());
CHECK(
logValue.as_object()["Msg"].get_string() ==
std::string{"Test: 1, 18446744073709551615, 3.141592653589793"});
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test json log fields")
{
journal().debug() << "Test" << log::field("Field1", 1)
<< log::field(
"Field2",
std::numeric_limits<std::uint64_t>::max());
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["Dt"].is_object());
CHECK(logValue.as_object()["Dt"].as_object()["Field1"].is_number());
CHECK(logValue.as_object()["Dt"].as_object()["Field1"].get_int64() == 1);
// UInt64 doesn't fit in Json::Value so it should be converted to a string
// NOTE: We should expect it to be an int64 after we make the json library
// support in64 and uint64
CHECK(logValue.as_object()["Dt"].as_object()["Field2"].is_number());
CHECK(
logValue.as_object()["Dt"].as_object()["Field2"].get_uint64() ==
std::numeric_limits<std::uint64_t>::max());
CHECK(logValue.as_object()["Msg"].is_string());
CHECK(logValue.as_object()["Msg"].get_string() == "Test");
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test journal attributes")
{
beast::Journal j{
journal(),
log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
j.debug() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["Jnl"].as_object()["Field1"].is_string());
CHECK(
logValue.as_object()["Jnl"].as_object()["Field1"].get_string() ==
std::string{"Value1"});
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].is_number());
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].get_int64() == 2);
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test journal attributes inheritable")
{
beast::Journal j{
journal(),
log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
beast::Journal j2{j, log::attributes(log::attr("Field3", "Value3"))};
j2.debug() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["Jnl"].as_object()["Field1"].is_string());
CHECK(
logValue.as_object()["Jnl"].as_object()["Field1"].get_string() ==
std::string{"Value1"});
CHECK(logValue.as_object()["Jnl"].as_object()["Field3"].is_string());
CHECK(
logValue.as_object()["Jnl"].as_object()["Field3"].get_string() ==
std::string{"Value3"});
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].is_number());
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].get_int64() == 2);
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test copying journal")
{
{
beast::Journal j{
journal(),
log::attributes(
log::attr("Field1", "Value1"), log::attr("Field2", 2))};
beast::Journal j2{j};
j2.debug() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["Jnl"].as_object()["Field1"].is_string());
CHECK(
logValue.as_object()["Jnl"].as_object()["Field1"].get_string() ==
std::string{"Value1"});
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].is_number());
CHECK(
logValue.as_object()["Jnl"].as_object()["Field2"].get_int64() == 2);
}
{
stream().str("");
beast::Journal j{journal().sink()};
beast::Journal j2{
j,
log::attributes(
log::attr("Field1", "Value1"), log::attr("Field2", 2))};
j2.debug() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["Jnl"].as_object()["Field1"].is_string());
CHECK(
logValue.as_object()["Jnl"].as_object()["Field1"].get_string() ==
std::string{"Value1"});
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].is_number());
CHECK(
logValue.as_object()["Jnl"].as_object()["Field2"].get_int64() == 2);
}
}
TEST_CASE_FIXTURE(
JsonLogStreamFixture,
"Test journal attributes inheritable after moving")
{
beast::Journal j{
journal(),
log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
beast::Journal j2{j, log::attributes(log::attr("Field3", "Value3"))};
j2.debug() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["Jnl"].as_object()["Field1"].is_string());
CHECK(
logValue.as_object()["Jnl"].as_object()["Field1"].get_string() ==
std::string{"Value1"});
CHECK(logValue.as_object()["Jnl"].as_object()["Field3"].is_string());
CHECK(
logValue.as_object()["Jnl"].as_object()["Field3"].get_string() ==
std::string{"Value3"});
// Field2 should be overwritten to 0
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].is_number());
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].get_int64() == 2);
}
TEST_CASE_FIXTURE(
JsonLogStreamFixture,
"Test journal attributes inheritable after copy assignment")
{
beast::Journal j{
std::move(journal()),
log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
beast::Journal j2{beast::Journal::getNullSink()};
j2 = j;
j2.debug() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["Jnl"].as_object()["Field1"].is_string());
CHECK(
logValue.as_object()["Jnl"].as_object()["Field1"].get_string() ==
std::string{"Value1"});
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].is_number());
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].get_int64() == 2);
}
TEST_CASE_FIXTURE(
JsonLogStreamFixture,
"Test journal attributes inheritable after move assignment")
{
beast::Journal j{
journal(),
log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
beast::Journal j2{beast::Journal::getNullSink()};
j2 = std::move(j);
j2.debug() << "Test";
boost::system::error_code ec;
auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["Jnl"].as_object()["Field1"].is_string());
CHECK(
logValue.as_object()["Jnl"].as_object()["Field1"].get_string() ==
std::string{"Value1"});
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].is_number());
CHECK(logValue.as_object()["Jnl"].as_object()["Field2"].get_int64() == 2);
}

View File

@@ -0,0 +1,346 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2024 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <xrpl/basics/Log.h>
#include <xrpl/net/HTTPClient.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <doctest/doctest.h>
#include <atomic>
#include <map>
#include <thread>
using namespace ripple;
namespace {
// Simple HTTP server using Beast for testing
class TestHTTPServer
{
private:
boost::asio::io_context ioc_;
boost::asio::ip::tcp::acceptor acceptor_;
boost::asio::ip::tcp::endpoint endpoint_;
std::atomic<bool> running_{true};
unsigned short port_;
// Custom headers to return
std::map<std::string, std::string> custom_headers_;
std::string response_body_;
unsigned int status_code_{200};
public:
TestHTTPServer() : acceptor_(ioc_), port_(0)
{
// Bind to any available port
endpoint_ = {boost::asio::ip::tcp::v4(), 0};
acceptor_.open(endpoint_.protocol());
acceptor_.set_option(boost::asio::socket_base::reuse_address(true));
acceptor_.bind(endpoint_);
acceptor_.listen();
// Get the actual port that was assigned
port_ = acceptor_.local_endpoint().port();
accept();
}
~TestHTTPServer()
{
stop();
}
boost::asio::io_context&
ioc()
{
return ioc_;
}
unsigned short
port() const
{
return port_;
}
void
setHeader(std::string const& name, std::string const& value)
{
custom_headers_[name] = value;
}
void
setResponseBody(std::string const& body)
{
response_body_ = body;
}
void
setStatusCode(unsigned int code)
{
status_code_ = code;
}
private:
void
stop()
{
running_ = false;
acceptor_.close();
}
void
accept()
{
if (!running_)
return;
acceptor_.async_accept(
ioc_,
endpoint_,
[&](boost::system::error_code const& error,
boost::asio::ip::tcp::socket peer) {
if (!running_)
return;
if (!error)
{
handleConnection(std::move(peer));
}
});
}
void
handleConnection(boost::asio::ip::tcp::socket socket)
{
try
{
// Read the HTTP request
boost::beast::flat_buffer buffer;
boost::beast::http::request<boost::beast::http::string_body> req;
boost::beast::http::read(socket, buffer, req);
// Create response
boost::beast::http::response<boost::beast::http::string_body> res;
res.version(req.version());
res.result(status_code_);
res.set(boost::beast::http::field::server, "TestServer");
// Add custom headers
for (auto const& [name, value] : custom_headers_)
{
res.set(name, value);
}
// Set body and prepare payload first
res.body() = response_body_;
res.prepare_payload();
// Override Content-Length with custom headers after prepare_payload
// This allows us to test case-insensitive header parsing
for (auto const& [name, value] : custom_headers_)
{
if (boost::iequals(name, "Content-Length"))
{
res.erase(boost::beast::http::field::content_length);
res.set(name, value);
}
}
// Send response
boost::beast::http::write(socket, res);
// Shutdown socket gracefully
boost::system::error_code ec;
socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
}
catch (std::exception const&)
{
// Connection handling errors are expected
}
if (running_)
accept();
}
};
// Helper function to run HTTP client test
bool
runHTTPTest(
TestHTTPServer& server,
std::string const& path,
std::atomic<bool>& completed,
std::atomic<int>& result_status,
std::string& result_data,
boost::system::error_code& result_error)
{
// Create a null journal for testing
beast::Journal j{beast::Journal::getNullSink()};
// Initialize HTTPClient SSL context
HTTPClient::initializeSSLContext("", "", false, j);
HTTPClient::get(
false, // no SSL
server.ioc(),
"127.0.0.1",
server.port(),
path,
1024, // max response size
std::chrono::seconds(5),
[&](boost::system::error_code const& ec,
int status,
std::string const& data) -> bool {
result_error = ec;
result_status = status;
result_data = data;
completed = true;
return false; // don't retry
},
j);
// Run the IO context until completion
auto start = std::chrono::steady_clock::now();
while (!completed &&
std::chrono::steady_clock::now() - start < std::chrono::seconds(10))
{
if (server.ioc().run_one() == 0)
{
break;
}
}
return completed;
}
} // anonymous namespace
TEST_CASE("HTTPClient case insensitive Content-Length")
{
// Test different cases of Content-Length header
std::vector<std::string> header_cases = {
"Content-Length", // Standard case
"content-length", // Lowercase - this tests the regex icase fix
"CONTENT-LENGTH", // Uppercase
"Content-length", // Mixed case
"content-Length" // Mixed case 2
};
for (auto const& header_name : header_cases)
{
TestHTTPServer server;
std::string test_body = "Hello World!";
server.setResponseBody(test_body);
server.setHeader(header_name, std::to_string(test_body.size()));
std::atomic<bool> completed{false};
std::atomic<int> result_status{0};
std::string result_data;
boost::system::error_code result_error;
bool test_completed = runHTTPTest(
server,
"/test",
completed,
result_status,
result_data,
result_error);
// Verify results
CHECK(test_completed);
CHECK(!result_error);
CHECK(result_status == 200);
CHECK(result_data == test_body);
}
}
TEST_CASE("HTTPClient basic HTTP request")
{
TestHTTPServer server;
std::string test_body = "Test response body";
server.setResponseBody(test_body);
server.setHeader("Content-Type", "text/plain");
std::atomic<bool> completed{false};
std::atomic<int> result_status{0};
std::string result_data;
boost::system::error_code result_error;
bool test_completed = runHTTPTest(
server, "/basic", completed, result_status, result_data, result_error);
CHECK(test_completed);
CHECK(!result_error);
CHECK(result_status == 200);
CHECK(result_data == test_body);
}
TEST_CASE("HTTPClient empty response")
{
TestHTTPServer server;
server.setResponseBody(""); // Empty body
server.setHeader("Content-Length", "0");
std::atomic<bool> completed{false};
std::atomic<int> result_status{0};
std::string result_data;
boost::system::error_code result_error;
bool test_completed = runHTTPTest(
server, "/empty", completed, result_status, result_data, result_error);
CHECK(test_completed);
CHECK(!result_error);
CHECK(result_status == 200);
CHECK(result_data.empty());
}
TEST_CASE("HTTPClient different status codes")
{
std::vector<unsigned int> status_codes = {200, 404, 500};
for (auto status : status_codes)
{
TestHTTPServer server;
server.setStatusCode(status);
server.setResponseBody("Status " + std::to_string(status));
std::atomic<bool> completed{false};
std::atomic<int> result_status{0};
std::string result_data;
boost::system::error_code result_error;
bool test_completed = runHTTPTest(
server,
"/status",
completed,
result_status,
result_data,
result_error);
CHECK(test_completed);
CHECK(!result_error);
CHECK(result_status == static_cast<int>(status));
}
}

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2025 Ripple Labs Inc.
Copyright (c) 2024 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -17,36 +17,5 @@
*/
//==============================================================================
#pragma once
// TODO: consider moving these to separate files (and figure out the build)
#include <string>
extern std::string const ledgerSqnWasmHex;
extern std::string const allHostFunctionsWasmHex;
extern std::string const deepRecursionHex;
extern std::string const fibWasmHex;
extern std::string const b58WasmHex;
extern std::string const sha512PureWasmHex;
extern std::string const zkProofWasmHex;
extern std::string const sp1WasmHex;
extern std::string const hfPerfTest;
extern std::string const allKeyletsWasmHex;
extern std::string const codecovTestsWasmHex;
extern std::string const floatTestsWasmHex;
extern std::string const float0Hex;
extern std::string const disabledFloatHex;
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>

View File

@@ -1129,7 +1129,25 @@ RclConsensusLogger::~RclConsensusLogger()
outSs << header_ << "duration " << (duration.count() / 1000) << '.'
<< std::setw(3) << std::setfill('0') << (duration.count() % 1000)
<< "s. " << ss_->str();
j_.sink().writeAlways(beast::severities::kInfo, outSs.str());
thread_local std::string buffer;
if (beast::Journal::isStructuredJournalEnabled())
{
buffer.resize(5 * 1024);
beast::detail::SimpleJsonWriter writer{&buffer};
writer.startObject();
writer.writeKey("Msg");
writer.writeString(outSs.str());
writer.writeKey("Tm");
writer.writeString(to_string(std::chrono::system_clock::now()));
writer.endObject();
writer.finish();
}
else
{
buffer = outSs.str();
}
j_.sink().writeAlways(beast::severities::kInfo, buffer);
}
} // namespace ripple

View File

@@ -831,9 +831,6 @@ public:
bool
serverOkay(std::string& reason) override;
beast::Journal
journal(std::string const& name) override;
//--------------------------------------------------------------------------
bool
@@ -1210,8 +1207,11 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline)
}
JLOG(m_journal.info()) << "Process starting: "
<< BuildInfo::getFullVersionString()
<< ", Instance Cookie: " << instanceCookie_;
<< log::param(
"RippledVersion",
BuildInfo::getFullVersionString())
<< ", Instance Cookie: "
<< log::param("InstanceCookie", instanceCookie_);
if (numberOfThreads(*config_) < 2)
{
@@ -2162,12 +2162,6 @@ ApplicationImp::serverOkay(std::string& reason)
return true;
}
beast::Journal
ApplicationImp::journal(std::string const& name)
{
return logs_->journal(name);
}
void
ApplicationImp::setMaxDisallowedLedger()
{

View File

@@ -257,8 +257,18 @@ public:
virtual bool
serverOkay(std::string& reason) = 0;
virtual beast::Journal
journal(std::string const& name) = 0;
template <typename TAttributesFactory>
beast::Journal
journal(std::string const& name, TAttributesFactory&& factory)
{
return logs().journal(name, std::forward<TAttributesFactory>(factory));
}
beast::Journal
journal(std::string const& name)
{
return logs().journal(name);
}
/* Returns the number of file descriptors the application needs */
virtual int

View File

@@ -794,6 +794,11 @@ run(int argc, char** argv)
else if (vm.count("verbose"))
thresh = kTrace;
if (config->LOG_STYLE == LogStyle::Json)
{
beast::Journal::enableStructuredJournal();
}
auto logs = std::make_unique<Logs>(thresh);
// No arguments. Run server.

View File

@@ -877,7 +877,7 @@ private:
verify(
lock_guard const&,
Json::Value& list,
std::string const& manifest,
Manifest manifest,
std::string const& blob,
std::string const& signature);

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