mirror of
https://github.com/Xahau/xahaud.git
synced 2026-07-11 17:20:08 +00:00
Compare commits
100 Commits
SecureUI
...
sync-2.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32680dde5e | ||
|
|
89e2b3b468 | ||
|
|
579357c152 | ||
|
|
cdeecbce93 | ||
|
|
b4ea66de07 | ||
|
|
f9699c21e7 | ||
|
|
2075cda2af | ||
|
|
6a18c92c5c | ||
|
|
f512fbec5d | ||
|
|
81a8fe1419 | ||
|
|
76fe761743 | ||
|
|
fcbee3c24a | ||
|
|
6a323d791f | ||
|
|
0817c442c2 | ||
|
|
346d26c482 | ||
|
|
31c2d78326 | ||
|
|
16e154a655 | ||
|
|
60d42be155 | ||
|
|
8411c5b371 | ||
|
|
9ba4e8d3ba | ||
|
|
9d33d7fbe2 | ||
|
|
85051f7781 | ||
|
|
90cca91b1d | ||
|
|
300dae7a22 | ||
|
|
b0f22ba51a | ||
|
|
cc32defa18 | ||
|
|
3a4519c83b | ||
|
|
2bafbe80e0 | ||
|
|
0f5dc78e28 | ||
|
|
13c21b533d | ||
|
|
9a9ac0a1e3 | ||
|
|
0dee07e966 | ||
|
|
10ec06ebf6 | ||
|
|
6d86df3ff5 | ||
|
|
f47b341388 | ||
|
|
3abe659f34 | ||
|
|
17205ac0a8 | ||
|
|
ba35b49b8f | ||
|
|
b10f68254c | ||
|
|
dd432d8636 | ||
|
|
10625d11f9 | ||
|
|
d9ac4face3 | ||
|
|
cff528dcdb | ||
|
|
36b8cd42e1 | ||
|
|
051da27285 | ||
|
|
d92e54431b | ||
|
|
e5079ebc59 | ||
|
|
2251b67eb4 | ||
|
|
147cb4b7f4 | ||
|
|
2aade4a277 | ||
|
|
a3a606463f | ||
|
|
33b65f9033 | ||
|
|
39615e2686 | ||
|
|
93149d7ac9 | ||
|
|
216f078490 | ||
|
|
9045cf64a5 | ||
|
|
040e334513 | ||
|
|
38057efbae | ||
|
|
c57dc1196f | ||
|
|
0e9ebc928f | ||
|
|
a48a954719 | ||
|
|
39a70d9252 | ||
|
|
dab0bcebd1 | ||
|
|
accbfc392f | ||
|
|
59284d49a4 | ||
|
|
4bb31e52dc | ||
|
|
6252f76c58 | ||
|
|
1696896277 | ||
|
|
6f23308a9a | ||
|
|
d9b54f0fb7 | ||
|
|
3c2c400530 | ||
|
|
9ebee4fa1d | ||
|
|
3ba33be395 | ||
|
|
a1da2b5de1 | ||
|
|
11eb243adf | ||
|
|
3e560ef311 | ||
|
|
9163f342be | ||
|
|
3175501e84 | ||
|
|
7be8cc700d | ||
|
|
672d9cfec1 | ||
|
|
4d8ab245b1 | ||
|
|
5fc784d98c | ||
|
|
aca3bfaed4 | ||
|
|
0042c01a16 | ||
|
|
7f471422cb | ||
|
|
9d5f54c724 | ||
|
|
6a2b5fc1c0 | ||
|
|
96ed68d86d | ||
|
|
f1490215cb | ||
|
|
4d25c36026 | ||
|
|
284fe1878a | ||
|
|
7a44234b2a | ||
|
|
b65eb8549e | ||
|
|
947588bc0e | ||
|
|
fd6904ea91 | ||
|
|
ddcfdced00 | ||
|
|
0861fa085e | ||
|
|
a51d0c760b | ||
|
|
169191abb8 | ||
|
|
e568d4e8fc |
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
AccessModifierOffset: -4
|
AccessModifierOffset: -4
|
||||||
AlignAfterOpenBracket: AlwaysBreak
|
AlignAfterOpenBracket: AlwaysBreak
|
||||||
AlignConsecutiveAssignments: false
|
AlignConsecutiveAssignments: false
|
||||||
@@ -19,47 +19,52 @@ AlwaysBreakTemplateDeclarations: true
|
|||||||
BinPackArguments: false
|
BinPackArguments: false
|
||||||
BinPackParameters: false
|
BinPackParameters: false
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
AfterClass: true
|
AfterClass: true
|
||||||
AfterControlStatement: true
|
AfterControlStatement: true
|
||||||
AfterEnum: false
|
AfterEnum: false
|
||||||
AfterFunction: true
|
AfterFunction: true
|
||||||
AfterNamespace: false
|
AfterNamespace: false
|
||||||
AfterObjCDeclaration: true
|
AfterObjCDeclaration: true
|
||||||
AfterStruct: true
|
AfterStruct: true
|
||||||
AfterUnion: true
|
AfterUnion: true
|
||||||
BeforeCatch: true
|
BeforeCatch: true
|
||||||
BeforeElse: true
|
BeforeElse: true
|
||||||
IndentBraces: false
|
IndentBraces: false
|
||||||
BreakBeforeBinaryOperators: false
|
BreakBeforeBinaryOperators: false
|
||||||
BreakBeforeBraces: Custom
|
BreakBeforeBraces: Custom
|
||||||
BreakBeforeTernaryOperators: true
|
BreakBeforeTernaryOperators: true
|
||||||
BreakConstructorInitializersBeforeComma: true
|
BreakConstructorInitializersBeforeComma: true
|
||||||
ColumnLimit: 80
|
ColumnLimit: 80
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
CommentPragmas: "^ IWYU pragma:"
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
ConstructorInitializerIndentWidth: 4
|
ConstructorInitializerIndentWidth: 4
|
||||||
ContinuationIndentWidth: 4
|
ContinuationIndentWidth: 4
|
||||||
Cpp11BracedListStyle: true
|
Cpp11BracedListStyle: true
|
||||||
DerivePointerAlignment: false
|
DerivePointerAlignment: false
|
||||||
DisableFormat: false
|
DisableFormat: false
|
||||||
ExperimentalAutoDetectBinPacking: false
|
ExperimentalAutoDetectBinPacking: false
|
||||||
ForEachMacros: [ Q_FOREACH, BOOST_FOREACH ]
|
ForEachMacros: [Q_FOREACH, BOOST_FOREACH]
|
||||||
|
IncludeBlocks: Regroup
|
||||||
IncludeCategories:
|
IncludeCategories:
|
||||||
- Regex: '^<(test)/'
|
- Regex: "^<(test)/"
|
||||||
Priority: 0
|
Priority: 0
|
||||||
- Regex: '^<(xrpld)/'
|
- Regex: "^<(xrpld)/"
|
||||||
Priority: 1
|
Priority: 1
|
||||||
- Regex: '^<(xrpl)/'
|
- Regex: "^<(xrpl)/"
|
||||||
Priority: 2
|
Priority: 2
|
||||||
- Regex: '^<(boost)/'
|
- Regex: "^<(boost)/"
|
||||||
Priority: 3
|
Priority: 3
|
||||||
- Regex: '.*'
|
- Regex: "^.*/"
|
||||||
Priority: 4
|
Priority: 4
|
||||||
IncludeIsMainRegex: '$'
|
- Regex: '^.*\.h'
|
||||||
|
Priority: 5
|
||||||
|
- Regex: ".*"
|
||||||
|
Priority: 6
|
||||||
|
IncludeIsMainRegex: "$"
|
||||||
IndentCaseLabels: true
|
IndentCaseLabels: true
|
||||||
IndentFunctionDeclarationAfterType: false
|
IndentFunctionDeclarationAfterType: false
|
||||||
IndentRequiresClause: true
|
IndentRequiresClause: true
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
IndentWrappedFunctionNames: false
|
IndentWrappedFunctionNames: false
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
MaxEmptyLinesToKeep: 1
|
MaxEmptyLinesToKeep: 1
|
||||||
@@ -73,19 +78,25 @@ PenaltyBreakString: 1000
|
|||||||
PenaltyExcessCharacter: 1000000
|
PenaltyExcessCharacter: 1000000
|
||||||
PenaltyReturnTypeOnItsOwnLine: 200
|
PenaltyReturnTypeOnItsOwnLine: 200
|
||||||
PointerAlignment: Left
|
PointerAlignment: Left
|
||||||
ReflowComments: true
|
ReflowComments: true
|
||||||
RequiresClausePosition: OwnLine
|
RequiresClausePosition: OwnLine
|
||||||
SortIncludes: true
|
SortIncludes: true
|
||||||
SpaceAfterCStyleCast: false
|
SpaceAfterCStyleCast: false
|
||||||
SpaceBeforeAssignmentOperators: true
|
SpaceBeforeAssignmentOperators: true
|
||||||
SpaceBeforeParens: ControlStatements
|
SpaceBeforeParens: ControlStatements
|
||||||
SpaceInEmptyParentheses: false
|
SpaceInEmptyParentheses: false
|
||||||
SpacesBeforeTrailingComments: 2
|
SpacesBeforeTrailingComments: 2
|
||||||
SpacesInAngles: false
|
SpacesInAngles: false
|
||||||
SpacesInContainerLiterals: true
|
SpacesInContainerLiterals: true
|
||||||
SpacesInCStyleCastParentheses: false
|
SpacesInCStyleCastParentheses: false
|
||||||
SpacesInParentheses: false
|
SpacesInParentheses: false
|
||||||
SpacesInSquareBrackets: false
|
SpacesInSquareBrackets: false
|
||||||
Standard: Cpp11
|
Standard: Cpp11
|
||||||
TabWidth: 8
|
TabWidth: 8
|
||||||
UseTab: Never
|
UseTab: Never
|
||||||
|
QualifierAlignment: Right
|
||||||
|
---
|
||||||
|
Language: JavaScript
|
||||||
|
---
|
||||||
|
Language: Json
|
||||||
|
IndentWidth: 2
|
||||||
|
|||||||
13
.codecov.yml
13
.codecov.yml
@@ -1,15 +1,4 @@
|
|||||||
codecov:
|
|
||||||
require_ci_to_pass: true
|
|
||||||
|
|
||||||
comment:
|
|
||||||
behavior: default
|
|
||||||
layout: reach,diff,flags,tree,reach
|
|
||||||
show_carryforward_flags: false
|
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
range: "60..80"
|
|
||||||
precision: 1
|
|
||||||
round: nearest
|
|
||||||
status:
|
status:
|
||||||
project:
|
project:
|
||||||
default:
|
default:
|
||||||
@@ -27,7 +16,7 @@ github_checks:
|
|||||||
parsers:
|
parsers:
|
||||||
cobertura:
|
cobertura:
|
||||||
partials_as_hits: true
|
partials_as_hits: true
|
||||||
handle_missing_conditions : true
|
handle_missing_conditions: true
|
||||||
|
|
||||||
slack_app: false
|
slack_app: false
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,5 @@ e61880699997398f5a746e6c4034edc7632661f5
|
|||||||
d25b5dcd568bb96c18e347d55fac10fe901a1bfb
|
d25b5dcd568bb96c18e347d55fac10fe901a1bfb
|
||||||
# Reformat code with clang-format-18
|
# Reformat code with clang-format-18
|
||||||
02749feea88ce61c1f7eeb2d61a57d8ecf07ab11
|
02749feea88ce61c1f7eeb2d61a57d8ecf07ab11
|
||||||
|
# chore: Run prettier on all files (#5657) (rippled)
|
||||||
|
97f0747e103f13e26e45b731731059b32f7679ac
|
||||||
|
|||||||
13
.github/ISSUE_TEMPLATE/bug_report.md
vendored
13
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -2,30 +2,35 @@
|
|||||||
name: Bug Report
|
name: Bug Report
|
||||||
about: Create a report to help us improve rippled
|
about: Create a report to help us improve rippled
|
||||||
title: "[Title with short description] (Version: [rippled version])"
|
title: "[Title with short description] (Version: [rippled version])"
|
||||||
labels: ''
|
labels: ""
|
||||||
assignees: ''
|
assignees: ""
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Please search existing issues to avoid creating duplicates.-->
|
<!-- Please search existing issues to avoid creating duplicates.-->
|
||||||
|
|
||||||
## Issue Description
|
## Issue Description
|
||||||
|
|
||||||
<!--Provide a summary for your issue/bug.-->
|
<!--Provide a summary for your issue/bug.-->
|
||||||
|
|
||||||
## Steps to Reproduce
|
## Steps to Reproduce
|
||||||
|
|
||||||
<!--List in detail the exact steps to reproduce the unexpected behavior of the software.-->
|
<!--List in detail the exact steps to reproduce the unexpected behavior of the software.-->
|
||||||
|
|
||||||
## Expected Result
|
## Expected Result
|
||||||
|
|
||||||
<!--Explain in detail what behavior you expected to happen.-->
|
<!--Explain in detail what behavior you expected to happen.-->
|
||||||
|
|
||||||
## Actual Result
|
## Actual Result
|
||||||
|
|
||||||
<!--Explain in detail what behavior actually happened.-->
|
<!--Explain in detail what behavior actually happened.-->
|
||||||
|
|
||||||
## Environment
|
## Environment
|
||||||
|
|
||||||
<!--Please describe your environment setup (such as Ubuntu 18.04 with Boost 1.70).-->
|
<!--Please describe your environment setup (such as Ubuntu 18.04 with Boost 1.70).-->
|
||||||
<!-- If you are using a formal release, please use the version returned by './rippled --version' as the version number-->
|
<!-- If you are using a formal release, please use the version returned by './rippled --version' as the version number-->
|
||||||
<!-- If you are working off of develop, please add the git hash via 'git rev-parse HEAD'-->
|
<!-- If you are working off of develop, please add the git hash via 'git rev-parse HEAD'-->
|
||||||
|
|
||||||
## Supporting Files
|
## Supporting Files
|
||||||
|
|
||||||
<!--If you have supporting files such as a log, feel free to post a link here using Github Gist.-->
|
<!--If you have supporting files such as a log, feel free to post a link here using Github Gist.-->
|
||||||
<!--Consider adding configuration files with private information removed via Github Gist. -->
|
<!--Consider adding configuration files with private information removed via Github Gist. -->
|
||||||
|
|
||||||
|
|||||||
8
.github/ISSUE_TEMPLATE/feature_request.md
vendored
8
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -3,19 +3,23 @@ name: Feature Request
|
|||||||
about: Suggest a new feature for the rippled project
|
about: Suggest a new feature for the rippled project
|
||||||
title: "[Title with short description] (Version: [rippled version])"
|
title: "[Title with short description] (Version: [rippled version])"
|
||||||
labels: Feature Request
|
labels: Feature Request
|
||||||
assignees: ''
|
assignees: ""
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Please search existing issues to avoid creating duplicates.-->
|
<!-- Please search existing issues to avoid creating duplicates.-->
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
<!-- Provide a summary to the feature request-->
|
<!-- Provide a summary to the feature request-->
|
||||||
|
|
||||||
## Motivation
|
## Motivation
|
||||||
|
|
||||||
<!-- Why do we need this feature?-->
|
<!-- Why do we need this feature?-->
|
||||||
|
|
||||||
## Solution
|
## Solution
|
||||||
|
|
||||||
<!-- What is the solution?-->
|
<!-- What is the solution?-->
|
||||||
|
|
||||||
## Paths Not Taken
|
## Paths Not Taken
|
||||||
|
|
||||||
<!-- What other alternatives have been considered?-->
|
<!-- What other alternatives have been considered?-->
|
||||||
|
|||||||
11
.github/workflows/clang-format.yml
vendored
11
.github/workflows/clang-format.yml
vendored
@@ -8,6 +8,15 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CLANG_VERSION: 18
|
CLANG_VERSION: 18
|
||||||
steps:
|
steps:
|
||||||
|
# For jobs running in containers, $GITHUB_WORKSPACE and ${{ github.workspace }} might not be the
|
||||||
|
# same directory. The actions/checkout step is *supposed* to checkout into $GITHUB_WORKSPACE and
|
||||||
|
# then add it to safe.directory (see instructions at https://github.com/actions/checkout)
|
||||||
|
# but that's apparently not happening for some container images. We can't be sure what is actually
|
||||||
|
# happening, so let's pre-emptively add both directories to safe.directory. There's a
|
||||||
|
# Github issue opened in 2022 and not resolved in 2025 https://github.com/actions/runner/issues/2058 ¯\_(ツ)_/¯
|
||||||
|
- run: |
|
||||||
|
git config --global --add safe.directory $GITHUB_WORKSPACE
|
||||||
|
git config --global --add safe.directory ${{ github.workspace }}
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install clang-format
|
- name: Install clang-format
|
||||||
run: |
|
run: |
|
||||||
@@ -20,7 +29,7 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install clang-format-${CLANG_VERSION}
|
sudo apt-get install clang-format-${CLANG_VERSION}
|
||||||
- name: Format first-party sources
|
- name: Format first-party sources
|
||||||
run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} +
|
run: find include src tests -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} +
|
||||||
- name: Check for differences
|
- name: Check for differences
|
||||||
id: assert
|
id: assert
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
4
.github/workflows/xahau-ga-macos.yml
vendored
4
.github/workflows/xahau-ga-macos.yml
vendored
@@ -122,4 +122,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: |
|
run: |
|
||||||
${{ env.build_dir }}/rippled --unittest --unittest-jobs $(nproc)
|
cd ${{ env.build_dir }}
|
||||||
|
./rippled --unittest --unittest-jobs $(nproc)
|
||||||
|
ctest -j $(nproc) --output-on-failure
|
||||||
|
|||||||
4
.github/workflows/xahau-ga-nix.yml
vendored
4
.github/workflows/xahau-ga-nix.yml
vendored
@@ -433,7 +433,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
# Ensure the binary exists before trying to run
|
# Ensure the binary exists before trying to run
|
||||||
if [ -f "${{ env.build_dir }}/rippled" ]; then
|
if [ -f "${{ env.build_dir }}/rippled" ]; then
|
||||||
${{ env.build_dir }}/rippled --unittest --unittest-jobs $(nproc)
|
cd ${{ env.build_dir }}
|
||||||
|
./rippled --unittest --unittest-jobs $(nproc)
|
||||||
|
ctest -j $(nproc) --output-on-failure
|
||||||
else
|
else
|
||||||
echo "Error: rippled executable not found in ${{ env.build_dir }}"
|
echo "Error: rippled executable not found in ${{ env.build_dir }}"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# .pre-commit-config.yaml
|
# .pre-commit-config.yaml
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
rev: v18.1.3
|
rev: v18.1.8
|
||||||
hooks:
|
hooks:
|
||||||
- id: clang-format
|
- id: clang-format
|
||||||
|
|||||||
@@ -83,9 +83,17 @@ The [commandline](https://xrpl.org/docs/references/http-websocket-apis/api-conve
|
|||||||
|
|
||||||
The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). However, use of reporting mode is now discouraged, in favor of using [Clio](https://github.com/XRPLF/clio) instead.
|
The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). However, use of reporting mode is now discouraged, in favor of using [Clio](https://github.com/XRPLF/clio) instead.
|
||||||
|
|
||||||
|
## XRP Ledger server version 2.5.0
|
||||||
|
|
||||||
|
As of 2025-04-04, version 2.5.0 is in development. You can use a pre-release version by building from source or [using the `nightly` package](https://xrpl.org/docs/infrastructure/installation/install-rippled-on-ubuntu).
|
||||||
|
|
||||||
|
### Additions and bugfixes in 2.5.0
|
||||||
|
|
||||||
|
- `channel_authorize`: If `signing_support` is not enabled in the config, the RPC is disabled.
|
||||||
|
|
||||||
## XRP Ledger server version 2.4.0
|
## XRP Ledger server version 2.4.0
|
||||||
|
|
||||||
As of 2025-01-28, version 2.4.0 is in development. You can use a pre-release version by building from source or [using the `nightly` package](https://xrpl.org/docs/infrastructure/installation/install-rippled-on-ubuntu).
|
[Version 2.4.0](https://github.com/XRPLF/rippled/releases/tag/2.4.0) was released on March 4, 2025.
|
||||||
|
|
||||||
### Additions and bugfixes in 2.4.0
|
### Additions and bugfixes in 2.4.0
|
||||||
|
|
||||||
|
|||||||
136
BUILD.md
136
BUILD.md
@@ -84,9 +84,9 @@ If you are unfamiliar with Conan, then please read [this crash course](./docs/bu
|
|||||||
|
|
||||||
You'll need at least one Conan profile:
|
You'll need at least one Conan profile:
|
||||||
|
|
||||||
```
|
```
|
||||||
conan profile detect --force
|
conan profile detect --force
|
||||||
```
|
```
|
||||||
|
|
||||||
Update the compiler settings:
|
Update the compiler settings:
|
||||||
|
|
||||||
@@ -182,16 +182,6 @@ which allows you to statically link it with GCC, if you want.
|
|||||||
conan export external/snappy --version 1.1.10 --user xahaud --channel stable
|
conan export external/snappy --version 1.1.10 --user xahaud --channel stable
|
||||||
```
|
```
|
||||||
|
|
||||||
Export our [Conan recipe for RocksDB](./external/rocksdb).
|
|
||||||
It does not override paths to dependencies when building with Visual Studio.
|
|
||||||
|
|
||||||
```
|
|
||||||
# Conan 1.x
|
|
||||||
conan export external/rocksdb rocksdb/6.29.5@
|
|
||||||
# Conan 2.x
|
|
||||||
conan export --version 6.29.5 external/rocksdb
|
|
||||||
```
|
|
||||||
|
|
||||||
Export our [Conan recipe for SOCI](./external/soci).
|
Export our [Conan recipe for SOCI](./external/soci).
|
||||||
It patches their CMake to correctly import its dependencies.
|
It patches their CMake to correctly import its dependencies.
|
||||||
|
|
||||||
@@ -205,17 +195,6 @@ It patches their CMake to correctly import its dependencies.
|
|||||||
conan export external/wasmedge --version 0.11.2 --user xahaud --channel stable
|
conan export external/wasmedge --version 0.11.2 --user xahaud --channel stable
|
||||||
```
|
```
|
||||||
|
|
||||||
Export our [Conan recipe for NuDB](./external/nudb).
|
|
||||||
It fixes some source files to add missing `#include`s.
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
# Conan 1.x
|
|
||||||
conan export external/nudb nudb/2.0.8@
|
|
||||||
# Conan 2.x
|
|
||||||
conan export --version 2.0.8 external/nudb
|
|
||||||
```
|
|
||||||
|
|
||||||
### Build and Test
|
### Build and Test
|
||||||
|
|
||||||
1. Create a build directory and move into it.
|
1. Create a build directory and move into it.
|
||||||
@@ -236,60 +215,60 @@ It fixes some source files to add missing `#include`s.
|
|||||||
|
|
||||||
2. Use conan to generate CMake files for every configuration you want to build:
|
2. Use conan to generate CMake files for every configuration you want to build:
|
||||||
|
|
||||||
```
|
```
|
||||||
conan install .. --output-folder . --build missing --settings build_type=Release
|
conan install .. --output-folder . --build missing --settings build_type=Release
|
||||||
conan install .. --output-folder . --build missing --settings build_type=Debug
|
conan install .. --output-folder . --build missing --settings build_type=Debug
|
||||||
```
|
```
|
||||||
|
|
||||||
To build Debug, in the next step, be sure to set `-DCMAKE_BUILD_TYPE=Debug`
|
To build Debug, in the next step, be sure to set `-DCMAKE_BUILD_TYPE=Debug`
|
||||||
|
|
||||||
For a single-configuration generator, e.g. `Unix Makefiles` or `Ninja`,
|
For a single-configuration generator, e.g. `Unix Makefiles` or `Ninja`,
|
||||||
you only need to run this command once.
|
you only need to run this command once.
|
||||||
For a multi-configuration generator, e.g. `Visual Studio`, you may want to
|
For a multi-configuration generator, e.g. `Visual Studio`, you may want to
|
||||||
run it more than once.
|
run it more than once.
|
||||||
|
|
||||||
Each of these commands should also have a different `build_type` setting.
|
Each of these commands should also have a different `build_type` setting.
|
||||||
A second command with the same `build_type` setting will overwrite the files
|
A second command with the same `build_type` setting will overwrite the files
|
||||||
generated by the first. You can pass the build type on the command line with
|
generated by the first. You can pass the build type on the command line with
|
||||||
`--settings build_type=$BUILD_TYPE` or in the profile itself,
|
`--settings build_type=$BUILD_TYPE` or in the profile itself,
|
||||||
under the section `[settings]` with the key `build_type`.
|
under the section `[settings]` with the key `build_type`.
|
||||||
|
|
||||||
If you are using a Microsoft Visual C++ compiler,
|
If you are using a Microsoft Visual C++ compiler,
|
||||||
then you will need to ensure consistency between the `build_type` setting
|
then you will need to ensure consistency between the `build_type` setting
|
||||||
and the `compiler.runtime` setting.
|
and the `compiler.runtime` setting.
|
||||||
|
|
||||||
When `build_type` is `Release`, `compiler.runtime` should be `MT`.
|
When `build_type` is `Release`, `compiler.runtime` should be `MT`.
|
||||||
|
|
||||||
When `build_type` is `Debug`, `compiler.runtime` should be `MTd`.
|
When `build_type` is `Debug`, `compiler.runtime` should be `MTd`.
|
||||||
|
|
||||||
```
|
```
|
||||||
conan install .. --output-folder . --build missing --settings build_type=Release --settings compiler.runtime=MT
|
conan install .. --output-folder . --build missing --settings build_type=Release --settings compiler.runtime=MT
|
||||||
conan install .. --output-folder . --build missing --settings build_type=Debug --settings compiler.runtime=MTd
|
conan install .. --output-folder . --build missing --settings build_type=Debug --settings compiler.runtime=MTd
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Configure CMake and pass the toolchain file generated by Conan, located at
|
3. Configure CMake and pass the toolchain file generated by Conan, located at
|
||||||
`$OUTPUT_FOLDER/build/generators/conan_toolchain.cmake`.
|
`$OUTPUT_FOLDER/build/generators/conan_toolchain.cmake`.
|
||||||
|
|
||||||
Single-config generators:
|
Single-config generators:
|
||||||
|
|
||||||
Pass the CMake variable [`CMAKE_BUILD_TYPE`][build_type]
|
Pass the CMake variable [`CMAKE_BUILD_TYPE`][build_type]
|
||||||
and make sure it matches the one of the `build_type` settings
|
and make sure it matches the one of the `build_type` settings
|
||||||
you chose in the previous step.
|
you chose in the previous step.
|
||||||
|
|
||||||
For example, to build Debug, in the next command, replace "Release" with "Debug"
|
For example, to build Debug, in the next command, replace "Release" with "Debug"
|
||||||
|
|
||||||
```
|
```
|
||||||
cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -Dxrpld=ON -Dtests=ON ..
|
cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -Dxrpld=ON -Dtests=ON ..
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Multi-config generators:
|
Multi-config generators:
|
||||||
|
|
||||||
```
|
```
|
||||||
cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -Dxrpld=ON -Dtests=ON ..
|
cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -Dxrpld=ON -Dtests=ON ..
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** You can pass build options for `xahaud` in this step.
|
**Note:** You can pass build options for `xahaud` in this step.
|
||||||
|
|
||||||
4. Build `xahaud`.
|
4. Build `xahaud`.
|
||||||
|
|
||||||
@@ -301,7 +280,7 @@ It fixes some source files to add missing `#include`s.
|
|||||||
Single-config generators:
|
Single-config generators:
|
||||||
|
|
||||||
```
|
```
|
||||||
cmake --build .
|
cmake --build . -j $(nproc)
|
||||||
```
|
```
|
||||||
|
|
||||||
Multi-config generators:
|
Multi-config generators:
|
||||||
@@ -329,7 +308,6 @@ It fixes some source files to add missing `#include`s.
|
|||||||
The location of `xahaud` in your build directory depends on your CMake
|
The location of `xahaud` in your build directory depends on your CMake
|
||||||
generator. Pass `--help` to see the rest of the command line options.
|
generator. Pass `--help` to see the rest of the command line options.
|
||||||
|
|
||||||
|
|
||||||
## Coverage report
|
## Coverage report
|
||||||
|
|
||||||
The coverage report is intended for developers using compilers GCC
|
The coverage report is intended for developers using compilers GCC
|
||||||
@@ -369,7 +347,7 @@ variable in `cmake`. The specific command line used to run the `gcovr` tool will
|
|||||||
displayed if the `CODE_COVERAGE_VERBOSE` variable is set.
|
displayed if the `CODE_COVERAGE_VERBOSE` variable is set.
|
||||||
|
|
||||||
By default, the code coverage tool runs parallel unit tests with `--unittest-jobs`
|
By default, the code coverage tool runs parallel unit tests with `--unittest-jobs`
|
||||||
set to the number of available CPU cores. This may cause spurious test
|
set to the number of available CPU cores. This may cause spurious test
|
||||||
errors on Apple. Developers can override the number of unit test jobs with
|
errors on Apple. Developers can override the number of unit test jobs with
|
||||||
the `coverage_test_parallelism` variable in `cmake`.
|
the `coverage_test_parallelism` variable in `cmake`.
|
||||||
|
|
||||||
@@ -388,24 +366,24 @@ stored inside the build directory, as either of:
|
|||||||
- file named `coverage.`_extension_ , with a suitable extension for the report format, or
|
- file named `coverage.`_extension_ , with a suitable extension for the report format, or
|
||||||
- directory named `coverage`, with the `index.html` and other files inside, for the `html-details` or `html-nested` report formats.
|
- directory named `coverage`, with the `index.html` and other files inside, for the `html-details` or `html-nested` report formats.
|
||||||
|
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
| Option | Default Value | Description |
|
| Option | Default Value | Description |
|
||||||
| --- | ---| ---|
|
| ---------- | ------------- | -------------------------------------------------------------------------- |
|
||||||
| `assert` | OFF | Enable assertions.
|
| `assert` | OFF | Enable assertions. |
|
||||||
| `coverage` | OFF | Prepare the coverage report. |
|
| `coverage` | OFF | Prepare the coverage report. |
|
||||||
| `san` | N/A | Enable a sanitizer with Clang. Choices are `thread` and `address`. |
|
| `san` | N/A | Enable a sanitizer with Clang. Choices are `thread` and `address`. |
|
||||||
| `tests` | OFF | Build tests. |
|
| `tests` | OFF | Build tests. |
|
||||||
| `unity` | ON | Configure a unity build. |
|
| `unity` | OFF | Configure a unity build. |
|
||||||
| `xrpld` | OFF | Build the xrpld (`rippled`) application, and not just the libxrpl library. |
|
| `xrpld` | OFF | Build the xrpld (`rippled`) application, and not just the libxrpl library. |
|
||||||
|
| `werr` | OFF | Treat compilation warnings as errors |
|
||||||
|
| `wextra` | OFF | Enable additional compilation warnings |
|
||||||
|
|
||||||
[Unity builds][5] may be faster for the first build
|
[Unity builds][5] may be faster for the first build
|
||||||
(at the cost of much more memory) since they concatenate sources into fewer
|
(at the cost of much more memory) since they concatenate sources into fewer
|
||||||
translation units. Non-unity builds may be faster for incremental builds,
|
translation units. Non-unity builds may be faster for incremental builds,
|
||||||
and can be helpful for detecting `#include` omissions.
|
and can be helpful for detecting `#include` omissions.
|
||||||
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|
||||||
@@ -475,13 +453,13 @@ If you want to experiment with a new package, follow these steps:
|
|||||||
|
|
||||||
1. Search for the package on [Conan Center](https://conan.io/center/).
|
1. Search for the package on [Conan Center](https://conan.io/center/).
|
||||||
2. Modify [`conanfile.py`](./conanfile.py):
|
2. Modify [`conanfile.py`](./conanfile.py):
|
||||||
- Add a version of the package to the `requires` property.
|
- Add a version of the package to the `requires` property.
|
||||||
- Change any default options for the package by adding them to the
|
- Change any default options for the package by adding them to the
|
||||||
`default_options` property (with syntax `'$package:$option': $value`).
|
`default_options` property (with syntax `'$package:$option': $value`).
|
||||||
3. Modify [`CMakeLists.txt`](./CMakeLists.txt):
|
3. Modify [`CMakeLists.txt`](./CMakeLists.txt):
|
||||||
- Add a call to `find_package($package REQUIRED)`.
|
- Add a call to `find_package($package REQUIRED)`.
|
||||||
- Link a library from the package to the target `ripple_libs`
|
- Link a library from the package to the target `ripple_libs`
|
||||||
(search for the existing call to `target_link_libraries(ripple_libs INTERFACE ...)`).
|
(search for the existing call to `target_link_libraries(ripple_libs INTERFACE ...)`).
|
||||||
4. Start coding! Don't forget to include whatever headers you need from the package.
|
4. Start coding! Don't forget to include whatever headers you need from the package.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,28 +25,28 @@ more dependencies listed later.
|
|||||||
**tl;dr:** The modules listed first are more independent than the modules
|
**tl;dr:** The modules listed first are more independent than the modules
|
||||||
listed later.
|
listed later.
|
||||||
|
|
||||||
| Level / Tier | Module(s) |
|
| Level / Tier | Module(s) |
|
||||||
|--------------|-----------------------------------------------|
|
| ------------ | -------------------------------------------------------------------------------------------------------- |
|
||||||
| 01 | ripple/beast ripple/unity
|
| 01 | ripple/beast ripple/unity |
|
||||||
| 02 | ripple/basics
|
| 02 | ripple/basics |
|
||||||
| 03 | ripple/json ripple/crypto
|
| 03 | ripple/json ripple/crypto |
|
||||||
| 04 | ripple/protocol
|
| 04 | ripple/protocol |
|
||||||
| 05 | ripple/core ripple/conditions ripple/consensus ripple/resource ripple/server
|
| 05 | ripple/core ripple/conditions ripple/consensus ripple/resource ripple/server |
|
||||||
| 06 | ripple/peerfinder ripple/ledger ripple/nodestore ripple/net
|
| 06 | ripple/peerfinder ripple/ledger ripple/nodestore ripple/net |
|
||||||
| 07 | ripple/shamap ripple/overlay
|
| 07 | ripple/shamap ripple/overlay |
|
||||||
| 08 | ripple/app
|
| 08 | ripple/app |
|
||||||
| 09 | ripple/rpc
|
| 09 | ripple/rpc |
|
||||||
| 10 | ripple/perflog
|
| 10 | ripple/perflog |
|
||||||
| 11 | test/jtx test/beast test/csf
|
| 11 | test/jtx test/beast test/csf |
|
||||||
| 12 | test/unit_test
|
| 12 | test/unit_test |
|
||||||
| 13 | test/crypto test/conditions test/json test/resource test/shamap test/peerfinder test/basics test/overlay
|
| 13 | test/crypto test/conditions test/json test/resource test/shamap test/peerfinder test/basics test/overlay |
|
||||||
| 14 | test
|
| 14 | test |
|
||||||
| 15 | test/net test/protocol test/ledger test/consensus test/core test/server test/nodestore
|
| 15 | test/net test/protocol test/ledger test/consensus test/core test/server test/nodestore |
|
||||||
| 16 | test/rpc test/app
|
| 16 | test/rpc test/app |
|
||||||
|
|
||||||
(Note that `test` levelization is *much* less important and *much* less
|
(Note that `test` levelization is _much_ less important and _much_ less
|
||||||
strictly enforced than `ripple` levelization, other than the requirement
|
strictly enforced than `ripple` levelization, other than the requirement
|
||||||
that `test` code should *never* be included in `ripple` code.)
|
that `test` code should _never_ be included in `ripple` code.)
|
||||||
|
|
||||||
## Validation
|
## Validation
|
||||||
|
|
||||||
@@ -59,48 +59,48 @@ the rippled source. The only caveat is that it runs much slower
|
|||||||
under Windows than in Linux. It hasn't yet been tested under MacOS.
|
under Windows than in Linux. It hasn't yet been tested under MacOS.
|
||||||
It generates many files of [results](results):
|
It generates many files of [results](results):
|
||||||
|
|
||||||
* `rawincludes.txt`: The raw dump of the `#includes`
|
- `rawincludes.txt`: The raw dump of the `#includes`
|
||||||
* `paths.txt`: A second dump grouping the source module
|
- `paths.txt`: A second dump grouping the source module
|
||||||
to the destination module, deduped, and with frequency counts.
|
to the destination module, deduped, and with frequency counts.
|
||||||
* `includes/`: A directory where each file represents a module and
|
- `includes/`: A directory where each file represents a module and
|
||||||
contains a list of modules and counts that the module _includes_.
|
contains a list of modules and counts that the module _includes_.
|
||||||
* `includedby/`: Similar to `includes/`, but the other way around. Each
|
- `includedby/`: Similar to `includes/`, but the other way around. Each
|
||||||
file represents a module and contains a list of modules and counts
|
file represents a module and contains a list of modules and counts
|
||||||
that _include_ the module.
|
that _include_ the module.
|
||||||
* [`loops.txt`](results/loops.txt): A list of direct loops detected
|
- [`loops.txt`](results/loops.txt): A list of direct loops detected
|
||||||
between modules as they actually exist, as opposed to how they are
|
between modules as they actually exist, as opposed to how they are
|
||||||
desired as described above. In a perfect repo, this file will be
|
desired as described above. In a perfect repo, this file will be
|
||||||
empty.
|
empty.
|
||||||
This file is committed to the repo, and is used by the [levelization
|
This file is committed to the repo, and is used by the [levelization
|
||||||
Github workflow](../../.github/workflows/levelization.yml) to validate
|
Github workflow](../../.github/workflows/levelization.yml) to validate
|
||||||
that nothing changed.
|
that nothing changed.
|
||||||
* [`ordering.txt`](results/ordering.txt): A list showing relationships
|
- [`ordering.txt`](results/ordering.txt): A list showing relationships
|
||||||
between modules where there are no loops as they actually exist, as
|
between modules where there are no loops as they actually exist, as
|
||||||
opposed to how they are desired as described above.
|
opposed to how they are desired as described above.
|
||||||
This file is committed to the repo, and is used by the [levelization
|
This file is committed to the repo, and is used by the [levelization
|
||||||
Github workflow](../../.github/workflows/levelization.yml) to validate
|
Github workflow](../../.github/workflows/levelization.yml) to validate
|
||||||
that nothing changed.
|
that nothing changed.
|
||||||
* [`levelization.yml`](../../.github/workflows/levelization.yml)
|
- [`levelization.yml`](../../.github/workflows/levelization.yml)
|
||||||
Github Actions workflow to test that levelization loops haven't
|
Github Actions workflow to test that levelization loops haven't
|
||||||
changed. Unfortunately, if changes are detected, it can't tell if
|
changed. Unfortunately, if changes are detected, it can't tell if
|
||||||
they are improvements or not, so if you have resolved any issues or
|
they are improvements or not, so if you have resolved any issues or
|
||||||
done anything else to improve levelization, run `levelization.py`,
|
done anything else to improve levelization, run `levelization.py`,
|
||||||
and commit the updated results.
|
and commit the updated results.
|
||||||
|
|
||||||
The `loops.txt` and `ordering.txt` files relate the modules
|
The `loops.txt` and `ordering.txt` files relate the modules
|
||||||
using comparison signs, which indicate the number of times each
|
using comparison signs, which indicate the number of times each
|
||||||
module is included in the other.
|
module is included in the other.
|
||||||
|
|
||||||
* `A > B` means that A should probably be at a higher level than B,
|
- `A > B` means that A should probably be at a higher level than B,
|
||||||
because B is included in A significantly more than A is included in B.
|
because B is included in A significantly more than A is included in B.
|
||||||
These results can be included in both `loops.txt` and `ordering.txt`.
|
These results can be included in both `loops.txt` and `ordering.txt`.
|
||||||
Because `ordering.txt`only includes relationships where B is not
|
Because `ordering.txt`only includes relationships where B is not
|
||||||
included in A at all, it will only include these types of results.
|
included in A at all, it will only include these types of results.
|
||||||
* `A ~= B` means that A and B are included in each other a different
|
- `A ~= B` means that A and B are included in each other a different
|
||||||
number of times, but the values are so close that the script can't
|
number of times, but the values are so close that the script can't
|
||||||
definitively say that one should be above the other. These results
|
definitively say that one should be above the other. These results
|
||||||
will only be included in `loops.txt`.
|
will only be included in `loops.txt`.
|
||||||
* `A == B` means that A and B include each other the same number of
|
- `A == B` means that A and B include each other the same number of
|
||||||
times, so the script has no clue which should be higher. These results
|
times, so the script has no clue which should be higher. These results
|
||||||
will only be included in `loops.txt`.
|
will only be included in `loops.txt`.
|
||||||
|
|
||||||
@@ -110,5 +110,5 @@ get those details locally.
|
|||||||
|
|
||||||
1. Run `levelization.py`
|
1. Run `levelization.py`
|
||||||
2. Grep the modules in `paths.txt`.
|
2. Grep the modules in `paths.txt`.
|
||||||
* For example, if a cycle is found `A ~= B`, simply `grep -w
|
- For example, if a cycle is found `A ~= B`, simply `grep -w
|
||||||
A Builds/levelization/results/paths.txt | grep -w B`
|
A Builds/levelization/results/paths.txt | grep -w B`
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ Loop: xrpld.app xrpld.nodestore
|
|||||||
xrpld.app > xrpld.nodestore
|
xrpld.app > xrpld.nodestore
|
||||||
|
|
||||||
Loop: xrpld.app xrpld.overlay
|
Loop: xrpld.app xrpld.overlay
|
||||||
xrpld.overlay ~= xrpld.app
|
xrpld.overlay > xrpld.app
|
||||||
|
|
||||||
Loop: xrpld.app xrpld.peerfinder
|
Loop: xrpld.app xrpld.peerfinder
|
||||||
xrpld.app > xrpld.peerfinder
|
xrpld.peerfinder ~= xrpld.app
|
||||||
|
|
||||||
Loop: xrpld.app xrpld.rpc
|
Loop: xrpld.app xrpld.rpc
|
||||||
xrpld.rpc > xrpld.app
|
xrpld.rpc > xrpld.app
|
||||||
@@ -44,7 +44,7 @@ Loop: xrpld.core xrpld.perflog
|
|||||||
xrpld.perflog == xrpld.core
|
xrpld.perflog == xrpld.core
|
||||||
|
|
||||||
Loop: xrpld.net xrpld.rpc
|
Loop: xrpld.net xrpld.rpc
|
||||||
xrpld.rpc > xrpld.net
|
xrpld.rpc ~= xrpld.net
|
||||||
|
|
||||||
Loop: xrpld.overlay xrpld.rpc
|
Loop: xrpld.overlay xrpld.rpc
|
||||||
xrpld.rpc ~= xrpld.overlay
|
xrpld.rpc ~= xrpld.overlay
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ libxrpl.protocol > xrpl.hook
|
|||||||
libxrpl.protocol > xrpl.json
|
libxrpl.protocol > xrpl.json
|
||||||
libxrpl.protocol > xrpl.protocol
|
libxrpl.protocol > xrpl.protocol
|
||||||
libxrpl.resource > xrpl.basics
|
libxrpl.resource > xrpl.basics
|
||||||
|
libxrpl.resource > xrpl.json
|
||||||
libxrpl.resource > xrpl.resource
|
libxrpl.resource > xrpl.resource
|
||||||
libxrpl.server > xrpl.basics
|
libxrpl.server > xrpl.basics
|
||||||
libxrpl.server > xrpl.json
|
libxrpl.server > xrpl.json
|
||||||
@@ -43,6 +44,7 @@ test.consensus > xrpld.app
|
|||||||
test.consensus > xrpld.consensus
|
test.consensus > xrpld.consensus
|
||||||
test.consensus > xrpld.core
|
test.consensus > xrpld.core
|
||||||
test.consensus > xrpld.ledger
|
test.consensus > xrpld.ledger
|
||||||
|
test.consensus > xrpl.json
|
||||||
test.consensus > xrpl.protocol
|
test.consensus > xrpl.protocol
|
||||||
test.core > test.jtx
|
test.core > test.jtx
|
||||||
test.core > test.toplevel
|
test.core > test.toplevel
|
||||||
@@ -60,7 +62,6 @@ test.json > test.jtx
|
|||||||
test.json > xrpl.json
|
test.json > xrpl.json
|
||||||
test.jtx > xrpl.basics
|
test.jtx > xrpl.basics
|
||||||
test.jtx > xrpld.app
|
test.jtx > xrpld.app
|
||||||
test.jtx > xrpld.consensus
|
|
||||||
test.jtx > xrpld.core
|
test.jtx > xrpld.core
|
||||||
test.jtx > xrpld.ledger
|
test.jtx > xrpld.ledger
|
||||||
test.jtx > xrpld.net
|
test.jtx > xrpld.net
|
||||||
@@ -141,6 +142,7 @@ test.shamap > xrpl.protocol
|
|||||||
test.toplevel > test.csf
|
test.toplevel > test.csf
|
||||||
test.toplevel > xrpl.json
|
test.toplevel > xrpl.json
|
||||||
test.unit_test > xrpl.basics
|
test.unit_test > xrpl.basics
|
||||||
|
tests.libxrpl > xrpl.basics
|
||||||
xrpl.hook > xrpl.basics
|
xrpl.hook > xrpl.basics
|
||||||
xrpl.hook > xrpl.protocol
|
xrpl.hook > xrpl.protocol
|
||||||
xrpl.json > xrpl.basics
|
xrpl.json > xrpl.basics
|
||||||
@@ -169,7 +171,6 @@ xrpld.core > xrpl.basics
|
|||||||
xrpld.core > xrpl.json
|
xrpld.core > xrpl.json
|
||||||
xrpld.core > xrpl.protocol
|
xrpld.core > xrpl.protocol
|
||||||
xrpld.ledger > xrpl.basics
|
xrpld.ledger > xrpl.basics
|
||||||
xrpld.ledger > xrpld.core
|
|
||||||
xrpld.ledger > xrpl.json
|
xrpld.ledger > xrpl.json
|
||||||
xrpld.ledger > xrpl.protocol
|
xrpld.ledger > xrpl.protocol
|
||||||
xrpld.net > xrpl.basics
|
xrpld.net > xrpl.basics
|
||||||
@@ -194,7 +195,6 @@ xrpld.peerfinder > xrpld.core
|
|||||||
xrpld.peerfinder > xrpl.protocol
|
xrpld.peerfinder > xrpl.protocol
|
||||||
xrpld.perflog > xrpl.basics
|
xrpld.perflog > xrpl.basics
|
||||||
xrpld.perflog > xrpl.json
|
xrpld.perflog > xrpl.json
|
||||||
xrpld.perflog > xrpl.protocol
|
|
||||||
xrpld.rpc > xrpl.basics
|
xrpld.rpc > xrpl.basics
|
||||||
xrpld.rpc > xrpld.core
|
xrpld.rpc > xrpld.core
|
||||||
xrpld.rpc > xrpld.ledger
|
xrpld.rpc > xrpld.ledger
|
||||||
|
|||||||
@@ -21,6 +21,18 @@ endif()
|
|||||||
project (xrpl)
|
project (xrpl)
|
||||||
set(Boost_NO_BOOST_CMAKE ON)
|
set(Boost_NO_BOOST_CMAKE ON)
|
||||||
|
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
|
# GCC-specific fixes
|
||||||
|
add_compile_options(-Wno-unknown-pragmas -Wno-subobject-linkage)
|
||||||
|
# -Wno-subobject-linkage can be removed when we upgrade GCC version to at least 13.3
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
# Clang-specific fixes
|
||||||
|
add_compile_options(-Wno-unknown-warning-option) # Ignore unknown warning options
|
||||||
|
elseif(MSVC)
|
||||||
|
# MSVC-specific fixes
|
||||||
|
add_compile_options(/wd4068) # Ignore unknown pragmas
|
||||||
|
endif()
|
||||||
|
|
||||||
# make GIT_COMMIT_HASH define available to all sources
|
# make GIT_COMMIT_HASH define available to all sources
|
||||||
find_package(Git)
|
find_package(Git)
|
||||||
if(Git_FOUND)
|
if(Git_FOUND)
|
||||||
@@ -97,6 +109,11 @@ set_target_properties(OpenSSL::SSL PROPERTIES
|
|||||||
INTERFACE_COMPILE_DEFINITIONS OPENSSL_NO_SSL2
|
INTERFACE_COMPILE_DEFINITIONS OPENSSL_NO_SSL2
|
||||||
)
|
)
|
||||||
set(SECP256K1_INSTALL TRUE)
|
set(SECP256K1_INSTALL TRUE)
|
||||||
|
set(SECP256K1_BUILD_BENCHMARK FALSE)
|
||||||
|
set(SECP256K1_BUILD_TESTS FALSE)
|
||||||
|
set(SECP256K1_BUILD_EXHAUSTIVE_TESTS FALSE)
|
||||||
|
set(SECP256K1_BUILD_CTIME_TESTS FALSE)
|
||||||
|
set(SECP256K1_BUILD_EXAMPLES FALSE)
|
||||||
add_subdirectory(external/secp256k1)
|
add_subdirectory(external/secp256k1)
|
||||||
add_library(secp256k1::secp256k1 ALIAS secp256k1)
|
add_library(secp256k1::secp256k1 ALIAS secp256k1)
|
||||||
add_subdirectory(external/ed25519-donna)
|
add_subdirectory(external/ed25519-donna)
|
||||||
@@ -154,3 +171,8 @@ include(RippledCore)
|
|||||||
include(RippledInstall)
|
include(RippledInstall)
|
||||||
include(RippledDocs)
|
include(RippledDocs)
|
||||||
include(RippledValidatorKeys)
|
include(RippledValidatorKeys)
|
||||||
|
|
||||||
|
if(tests)
|
||||||
|
include(CTest)
|
||||||
|
add_subdirectory(src/tests/libxrpl)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ We assume you are familiar with the general practice of [making
|
|||||||
contributions on GitHub][1]. This file includes only special
|
contributions on GitHub][1]. This file includes only special
|
||||||
instructions specific to this project.
|
instructions specific to this project.
|
||||||
|
|
||||||
|
|
||||||
## Before you start
|
## Before you start
|
||||||
|
|
||||||
In general, contributions should be developed in your personal
|
In general, contributions should be developed in your personal
|
||||||
@@ -28,7 +27,6 @@ your verifying key. Please set up [signature verification][signing].
|
|||||||
[signing]:
|
[signing]:
|
||||||
https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification
|
https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification
|
||||||
|
|
||||||
|
|
||||||
## Major contributions
|
## Major contributions
|
||||||
|
|
||||||
If your contribution is a major feature or breaking change, then you
|
If your contribution is a major feature or breaking change, then you
|
||||||
@@ -45,7 +43,6 @@ responsibility of the XLS author to update the draft to match the final
|
|||||||
implementation when its corresponding pull request is merged, unless the
|
implementation when its corresponding pull request is merged, unless the
|
||||||
author delegates that responsibility to others.
|
author delegates that responsibility to others.
|
||||||
|
|
||||||
|
|
||||||
## Before making a pull request
|
## Before making a pull request
|
||||||
|
|
||||||
Changes that alter transaction processing must be guarded by an
|
Changes that alter transaction processing must be guarded by an
|
||||||
@@ -75,16 +72,17 @@ Changes should be usually squashed down into a single commit.
|
|||||||
Some larger or more complicated change sets make more sense,
|
Some larger or more complicated change sets make more sense,
|
||||||
and are easier to review if organized into multiple logical commits.
|
and are easier to review if organized into multiple logical commits.
|
||||||
Either way, all commits should fit the following criteria:
|
Either way, all commits should fit the following criteria:
|
||||||
* Changes should be presented in a single commit or a logical
|
|
||||||
|
- Changes should be presented in a single commit or a logical
|
||||||
sequence of commits.
|
sequence of commits.
|
||||||
Specifically, chronological commits that simply
|
Specifically, chronological commits that simply
|
||||||
reflect the history of how the author implemented
|
reflect the history of how the author implemented
|
||||||
the change, "warts and all", are not useful to
|
the change, "warts and all", are not useful to
|
||||||
reviewers.
|
reviewers.
|
||||||
* Every commit should have a [good message](#good-commit-messages).
|
- Every commit should have a [good message](#good-commit-messages).
|
||||||
to explain a specific aspects of the change.
|
to explain a specific aspects of the change.
|
||||||
* Every commit should be signed.
|
- Every commit should be signed.
|
||||||
* Every commit should be well-formed (builds successfully,
|
- Every commit should be well-formed (builds successfully,
|
||||||
unit tests passing), as this helps to resolve merge
|
unit tests passing), as this helps to resolve merge
|
||||||
conflicts, and makes it easier to use `git bisect`
|
conflicts, and makes it easier to use `git bisect`
|
||||||
to find bugs.
|
to find bugs.
|
||||||
@@ -96,13 +94,14 @@ Refer to
|
|||||||
for general rules on writing a good commit message.
|
for general rules on writing a good commit message.
|
||||||
|
|
||||||
tl;dr
|
tl;dr
|
||||||
|
|
||||||
> 1. Separate subject from body with a blank line.
|
> 1. Separate subject from body with a blank line.
|
||||||
> 2. Limit the subject line to 50 characters.
|
> 2. Limit the subject line to 50 characters.
|
||||||
> * [...]shoot for 50 characters, but consider 72 the hard limit.
|
> - [...]shoot for 50 characters, but consider 72 the hard limit.
|
||||||
> 3. Capitalize the subject line.
|
> 3. Capitalize the subject line.
|
||||||
> 4. Do not end the subject line with a period.
|
> 4. Do not end the subject line with a period.
|
||||||
> 5. Use the imperative mood in the subject line.
|
> 5. Use the imperative mood in the subject line.
|
||||||
> * A properly formed Git commit subject line should always be able
|
> - A properly formed Git commit subject line should always be able
|
||||||
> to complete the following sentence: "If applied, this commit will
|
> to complete the following sentence: "If applied, this commit will
|
||||||
> _your subject line here_".
|
> _your subject line here_".
|
||||||
> 6. Wrap the body at 72 characters.
|
> 6. Wrap the body at 72 characters.
|
||||||
@@ -110,16 +109,17 @@ tl;dr
|
|||||||
|
|
||||||
In addition to those guidelines, please add one of the following
|
In addition to those guidelines, please add one of the following
|
||||||
prefixes to the subject line if appropriate.
|
prefixes to the subject line if appropriate.
|
||||||
* `fix:` - The primary purpose is to fix an existing bug.
|
|
||||||
* `perf:` - The primary purpose is performance improvements.
|
- `fix:` - The primary purpose is to fix an existing bug.
|
||||||
* `refactor:` - The changes refactor code without affecting
|
- `perf:` - The primary purpose is performance improvements.
|
||||||
|
- `refactor:` - The changes refactor code without affecting
|
||||||
functionality.
|
functionality.
|
||||||
* `test:` - The changes _only_ affect unit tests.
|
- `test:` - The changes _only_ affect unit tests.
|
||||||
* `docs:` - The changes _only_ affect documentation. This can
|
- `docs:` - The changes _only_ affect documentation. This can
|
||||||
include code comments in addition to `.md` files like this one.
|
include code comments in addition to `.md` files like this one.
|
||||||
* `build:` - The changes _only_ affect the build process,
|
- `build:` - The changes _only_ affect the build process,
|
||||||
including CMake and/or Conan settings.
|
including CMake and/or Conan settings.
|
||||||
* `chore:` - Other tasks that don't affect the binary, but don't fit
|
- `chore:` - Other tasks that don't affect the binary, but don't fit
|
||||||
any of the other cases. e.g. formatting, git settings, updating
|
any of the other cases. e.g. formatting, git settings, updating
|
||||||
Github Actions jobs.
|
Github Actions jobs.
|
||||||
|
|
||||||
@@ -169,11 +169,11 @@ meets a few criteria:
|
|||||||
2. All CI checks must be complete and passed. (One-off failures may
|
2. All CI checks must be complete and passed. (One-off failures may
|
||||||
be acceptable if they are related to a known issue.)
|
be acceptable if they are related to a known issue.)
|
||||||
3. The PR must have a [good commit message](#good-commit-messages).
|
3. The PR must have a [good commit message](#good-commit-messages).
|
||||||
* If the PR started with a good commit message, and it doesn't
|
- If the PR started with a good commit message, and it doesn't
|
||||||
need to be updated, the author can indicate that in a comment.
|
need to be updated, the author can indicate that in a comment.
|
||||||
* Any contributor, preferably the author, can leave a comment
|
- Any contributor, preferably the author, can leave a comment
|
||||||
suggesting a commit message.
|
suggesting a commit message.
|
||||||
* If the author squashes and rebases the code in preparation for
|
- If the author squashes and rebases the code in preparation for
|
||||||
merge, they should also ensure the commit message(s) are updated
|
merge, they should also ensure the commit message(s) are updated
|
||||||
as well.
|
as well.
|
||||||
4. The PR branch must be up to date with the base branch (usually
|
4. The PR branch must be up to date with the base branch (usually
|
||||||
@@ -320,7 +320,6 @@ This is a non-exhaustive list of recommended style guidelines. These are
|
|||||||
not always strictly enforced and serve as a way to keep the codebase
|
not always strictly enforced and serve as a way to keep the codebase
|
||||||
coherent rather than a set of _thou shalt not_ commandments.
|
coherent rather than a set of _thou shalt not_ commandments.
|
||||||
|
|
||||||
|
|
||||||
## Formatting
|
## Formatting
|
||||||
|
|
||||||
All code must conform to `clang-format` version 10,
|
All code must conform to `clang-format` version 10,
|
||||||
@@ -349,6 +348,7 @@ To download the patch file:
|
|||||||
5. Commit and push.
|
5. Commit and push.
|
||||||
|
|
||||||
You can install a pre-commit hook to automatically run `clang-format` before every commit:
|
You can install a pre-commit hook to automatically run `clang-format` before every commit:
|
||||||
|
|
||||||
```
|
```
|
||||||
pip3 install pre-commit
|
pip3 install pre-commit
|
||||||
pre-commit install
|
pre-commit install
|
||||||
@@ -379,49 +379,51 @@ locations, where the reporting of contract violations on the Antithesis
|
|||||||
platform is either not possible or not useful.
|
platform is either not possible or not useful.
|
||||||
|
|
||||||
For this reason:
|
For this reason:
|
||||||
* The locations where `assert` or `assert(false)` contracts should continue to be used:
|
|
||||||
* `constexpr` functions
|
- The locations where `assert` or `assert(false)` contracts should continue to be used:
|
||||||
* unit tests i.e. files under `src/test`
|
- `constexpr` functions
|
||||||
* unit tests-related modules (files under `beast/test` and `beast/unit_test`)
|
- unit tests i.e. files under `src/test`
|
||||||
* Outside of the listed locations, do not use `assert`; use `XRPL_ASSERT` instead,
|
- unit tests-related modules (files under `beast/test` and `beast/unit_test`)
|
||||||
|
- Outside of the listed locations, do not use `assert`; use `XRPL_ASSERT` instead,
|
||||||
giving it unique name, with the short description of the contract.
|
giving it unique name, with the short description of the contract.
|
||||||
* Outside of the listed locations, do not use `assert(false)`; use
|
- Outside of the listed locations, do not use `assert(false)`; use
|
||||||
`UNREACHABLE` instead, giving it unique name, with the description of the
|
`UNREACHABLE` instead, giving it unique name, with the description of the
|
||||||
condition being violated
|
condition being violated
|
||||||
* The contract name should start with a full name (including scope) of the
|
- The contract name should start with a full name (including scope) of the
|
||||||
function, optionally a named lambda, followed by a colon ` : ` and a brief
|
function, optionally a named lambda, followed by a colon `:` and a brief
|
||||||
(typically at most five words) description. `UNREACHABLE` contracts
|
(typically at most five words) description. `UNREACHABLE` contracts
|
||||||
can use slightly longer descriptions. If there are multiple overloads of the
|
can use slightly longer descriptions. If there are multiple overloads of the
|
||||||
function, use common sense to balance both brevity and unambiguity of the
|
function, use common sense to balance both brevity and unambiguity of the
|
||||||
function name. NOTE: the purpose of name is to provide stable means of
|
function name. NOTE: the purpose of name is to provide stable means of
|
||||||
unique identification of every contract; for this reason try to avoid elements
|
unique identification of every contract; for this reason try to avoid elements
|
||||||
which can change in some obvious refactors or when reinforcing the condition.
|
which can change in some obvious refactors or when reinforcing the condition.
|
||||||
* Contract description typically (except for `UNREACHABLE`) should describe the
|
- Contract description typically (except for `UNREACHABLE`) should describe the
|
||||||
_expected_ condition, as in "I assert that _expected_ is true".
|
_expected_ condition, as in "I assert that _expected_ is true".
|
||||||
* Contract description for `UNREACHABLE` should describe the _unexpected_
|
- Contract description for `UNREACHABLE` should describe the _unexpected_
|
||||||
situation which caused the line to have been reached.
|
situation which caused the line to have been reached.
|
||||||
* Example good name for an
|
- Example good name for an
|
||||||
`UNREACHABLE` macro `"Json::operator==(Value, Value) : invalid type"`; example
|
`UNREACHABLE` macro `"Json::operator==(Value, Value) : invalid type"`; example
|
||||||
good name for an `XRPL_ASSERT` macro `"Json::Value::asCString : valid type"`.
|
good name for an `XRPL_ASSERT` macro `"Json::Value::asCString : valid type"`.
|
||||||
* Example **bad** name
|
- Example **bad** name
|
||||||
`"RFC1751::insert(char* s, int x, int start, int length) : length is greater than or equal zero"`
|
`"RFC1751::insert(char* s, int x, int start, int length) : length is greater than or equal zero"`
|
||||||
(missing namespace, unnecessary full function signature, description too verbose).
|
(missing namespace, unnecessary full function signature, description too verbose).
|
||||||
Good name: `"ripple::RFC1751::insert : minimum length"`.
|
Good name: `"ripple::RFC1751::insert : minimum length"`.
|
||||||
* In **few** well-justified cases a non-standard name can be used, in which case a
|
- In **few** well-justified cases a non-standard name can be used, in which case a
|
||||||
comment should be placed to explain the rationale (example in `contract.cpp`)
|
comment should be placed to explain the rationale (example in `contract.cpp`)
|
||||||
* Do **not** rename a contract without a good reason (e.g. the name no longer
|
- Do **not** rename a contract without a good reason (e.g. the name no longer
|
||||||
reflects the location or the condition being checked)
|
reflects the location or the condition being checked)
|
||||||
* Do not use `std::unreachable`
|
- Do not use `std::unreachable`
|
||||||
* Do not put contracts where they can be violated by an external condition
|
- Do not put contracts where they can be violated by an external condition
|
||||||
(e.g. timing, data payload before mandatory validation etc.) as this creates
|
(e.g. timing, data payload before mandatory validation etc.) as this creates
|
||||||
bogus bug reports (and causes crashes of Debug builds)
|
bogus bug reports (and causes crashes of Debug builds)
|
||||||
|
|
||||||
## Unit Tests
|
## Unit Tests
|
||||||
|
|
||||||
To execute all unit tests:
|
To execute all unit tests:
|
||||||
|
|
||||||
```rippled --unittest --unittest-jobs=<number of cores>```
|
`rippled --unittest --unittest-jobs=<number of cores>`
|
||||||
|
|
||||||
(Note: Using multiple cores on a Mac M1 can cause spurious test failures. The
|
(Note: Using multiple cores on a Mac M1 can cause spurious test failures. The
|
||||||
cause is still under investigation. If you observe this problem, try specifying fewer jobs.)
|
cause is still under investigation. If you observe this problem, try specifying fewer jobs.)
|
||||||
|
|
||||||
To run a specific set of test suites:
|
To run a specific set of test suites:
|
||||||
@@ -429,10 +431,11 @@ To run a specific set of test suites:
|
|||||||
```
|
```
|
||||||
rippled --unittest TestSuiteName
|
rippled --unittest TestSuiteName
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: In this example, all tests with prefix `TestSuiteName` will be run, so if
|
Note: In this example, all tests with prefix `TestSuiteName` will be run, so if
|
||||||
`TestSuiteName1` and `TestSuiteName2` both exist, then both tests will run.
|
`TestSuiteName1` and `TestSuiteName2` both exist, then both tests will run.
|
||||||
Alternatively, if the unit test name finds an exact match, it will stop
|
Alternatively, if the unit test name finds an exact match, it will stop
|
||||||
doing partial matches, i.e. if a unit test with a title of `TestSuiteName`
|
doing partial matches, i.e. if a unit test with a title of `TestSuiteName`
|
||||||
exists, then no other unit test will be executed, apart from `TestSuiteName`.
|
exists, then no other unit test will be executed, apart from `TestSuiteName`.
|
||||||
|
|
||||||
## Avoid
|
## Avoid
|
||||||
@@ -448,7 +451,6 @@ exists, then no other unit test will be executed, apart from `TestSuiteName`.
|
|||||||
explanatory comments.
|
explanatory comments.
|
||||||
8. Importing new libraries unless there is a very good reason to do so.
|
8. Importing new libraries unless there is a very good reason to do so.
|
||||||
|
|
||||||
|
|
||||||
## Seek to
|
## Seek to
|
||||||
|
|
||||||
9. Extend functionality of existing code rather than creating new code.
|
9. Extend functionality of existing code rather than creating new code.
|
||||||
@@ -463,14 +465,12 @@ exists, then no other unit test will be executed, apart from `TestSuiteName`.
|
|||||||
14. Provide as many comments as you feel that a competent programmer
|
14. Provide as many comments as you feel that a competent programmer
|
||||||
would need to understand what your code does.
|
would need to understand what your code does.
|
||||||
|
|
||||||
|
|
||||||
# Maintainers
|
# Maintainers
|
||||||
|
|
||||||
Maintainers are ecosystem participants with elevated access to the repository.
|
Maintainers are ecosystem participants with elevated access to the repository.
|
||||||
They are able to push new code, make decisions on when a release should be
|
They are able to push new code, make decisions on when a release should be
|
||||||
made, etc.
|
made, etc.
|
||||||
|
|
||||||
|
|
||||||
## Adding and removing
|
## Adding and removing
|
||||||
|
|
||||||
New maintainers can be proposed by two existing maintainers, subject to a vote
|
New maintainers can be proposed by two existing maintainers, subject to a vote
|
||||||
@@ -485,7 +485,6 @@ A minimum of 60% agreement and 50% participation are required.
|
|||||||
The XRP Ledger Foundation will have the ability, for cause, to remove an
|
The XRP Ledger Foundation will have the ability, for cause, to remove an
|
||||||
existing maintainer without a vote.
|
existing maintainer without a vote.
|
||||||
|
|
||||||
|
|
||||||
## Current Maintainers
|
## Current Maintainers
|
||||||
|
|
||||||
* [Richard Holland](https://github.com/RichardAH) (XRPL Labs + INFTF)
|
* [Richard Holland](https://github.com/RichardAH) (XRPL Labs + INFTF)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
ISC License
|
ISC License
|
||||||
|
|
||||||
Copyright (c) 2011, Arthur Britto, David Schwartz, Jed McCaleb, Vinnie Falco, Bob Way, Eric Lombrozo, Nikolaos D. Bougalis, Howard Hinnant.
|
Copyright (c) 2011, Arthur Britto, David Schwartz, Jed McCaleb, Vinnie Falco, Bob Way, Eric Lombrozo, Nikolaos D. Bougalis, Howard Hinnant.
|
||||||
Copyright (c) 2012-2020, the XRP Ledger developers.
|
Copyright (c) 2012-2020, the XRP Ledger developers.
|
||||||
@@ -15,4 +15,3 @@ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,11 @@
|
|||||||
[Xahau](https://xahau.network/) is a decentralized cryptographic ledger that builds upon the robust foundation of the XRP Ledger. It inherits the XRP Ledger's Byzantine Fault Tolerant consensus algorithm and enhances it with additional features and functionalities. Developers and users familiar with the XRP Ledger will find that most documentation and tutorials available on [xrpl.org](https://xrpl.org) are relevant and applicable to Xahau, including those related to running validators and managing validator keys. For Xahau specific documentation you can visit our [documentation](https://xahau.network/)
|
[Xahau](https://xahau.network/) is a decentralized cryptographic ledger that builds upon the robust foundation of the XRP Ledger. It inherits the XRP Ledger's Byzantine Fault Tolerant consensus algorithm and enhances it with additional features and functionalities. Developers and users familiar with the XRP Ledger will find that most documentation and tutorials available on [xrpl.org](https://xrpl.org) are relevant and applicable to Xahau, including those related to running validators and managing validator keys. For Xahau specific documentation you can visit our [documentation](https://xahau.network/)
|
||||||
|
|
||||||
## XAH
|
## XAH
|
||||||
|
|
||||||
XAH is the public, counterparty-free asset native to Xahau and functions primarily as network gas. Transactions submitted to the Xahau network must supply an appropriate amount of XAH, to be burnt by the network as a fee, in order to be successfully included in a validated ledger. In addition, XAH also acts as a bridge currency within the Xahau DEX. XAH is traded on the open-market and is available for anyone to access. Xahau was created in 2023 with a supply of 600 million units of XAH.
|
XAH is the public, counterparty-free asset native to Xahau and functions primarily as network gas. Transactions submitted to the Xahau network must supply an appropriate amount of XAH, to be burnt by the network as a fee, in order to be successfully included in a validated ledger. In addition, XAH also acts as a bridge currency within the Xahau DEX. XAH is traded on the open-market and is available for anyone to access. Xahau was created in 2023 with a supply of 600 million units of XAH.
|
||||||
|
|
||||||
## xahaud
|
## xahaud
|
||||||
|
|
||||||
The server software that powers Xahau is called `xahaud` and is available in this repository under the permissive [ISC open-source license](LICENSE.md). The `xahaud` server software is written primarily in C++ and runs on a variety of platforms. The `xahaud` server software can run in several modes depending on its configuration.
|
The server software that powers Xahau is called `xahaud` and is available in this repository under the permissive [ISC open-source license](LICENSE.md). The `xahaud` server software is written primarily in C++ and runs on a variety of platforms. The `xahaud` server software can run in several modes depending on its configuration.
|
||||||
|
|
||||||
### Build from Source
|
### Build from Source
|
||||||
|
|||||||
4716
RELEASENOTES.md
4716
RELEASENOTES.md
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
For more details on operating the Xahau server securely, please visit https://docs.xahau.network/infrastructure/building-xahau.
|
For more details on operating the Xahau server securely, please visit https://docs.xahau.network/infrastructure/building-xahau.
|
||||||
|
|
||||||
|
|
||||||
# Security Policy
|
# Security Policy
|
||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|||||||
218
bin/physical.sh
218
bin/physical.sh
@@ -1,218 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -o errexit
|
|
||||||
|
|
||||||
marker_base=f62f74da10c5936c64bd16cd509a8b68f1464e41
|
|
||||||
marker_commit=${1:-${marker_base}}
|
|
||||||
|
|
||||||
if [ $(git merge-base ${marker_commit} ${marker_base}) != ${marker_base} ]; then
|
|
||||||
echo "first marker commit not an ancestor: ${marker_commit}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $(git merge-base ${marker_commit} HEAD) != $(git rev-parse --verify ${marker_commit}) ]; then
|
|
||||||
echo "given marker commit not an ancestor: ${marker_commit}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -e Builds/CMake ]; then
|
|
||||||
echo move CMake
|
|
||||||
git mv Builds/CMake cmake
|
|
||||||
git add --update .
|
|
||||||
git commit -m 'Move CMake directory' --author 'Pretty Printer <cpp@ripple.com>'
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -e src/ripple ]; then
|
|
||||||
|
|
||||||
echo move protocol buffers
|
|
||||||
mkdir -p include/xrpl
|
|
||||||
if [ -e src/ripple/proto ]; then
|
|
||||||
git mv src/ripple/proto include/xrpl
|
|
||||||
fi
|
|
||||||
|
|
||||||
extract_list() {
|
|
||||||
git show ${marker_commit}:Builds/CMake/RippledCore.cmake | \
|
|
||||||
awk "/END ${1}/ { p = 0 } p && /src\/ripple/; /BEGIN ${1}/ { p = 1 }" | \
|
|
||||||
sed -e 's#src/ripple/##' -e 's#[^a-z]\+$##'
|
|
||||||
}
|
|
||||||
|
|
||||||
move_files() {
|
|
||||||
oldroot="$1"; shift
|
|
||||||
newroot="$1"; shift
|
|
||||||
detail="$1"; shift
|
|
||||||
files=("$@")
|
|
||||||
for file in ${files[@]}; do
|
|
||||||
if [ ! -e ${oldroot}/${file} ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
dir=$(dirname ${file})
|
|
||||||
if [ $(basename ${dir}) == 'details' ]; then
|
|
||||||
dir=$(dirname ${dir})
|
|
||||||
fi
|
|
||||||
if [ $(basename ${dir}) == 'impl' ]; then
|
|
||||||
dir="$(dirname ${dir})/${detail}"
|
|
||||||
fi
|
|
||||||
mkdir -p ${newroot}/${dir}
|
|
||||||
git mv ${oldroot}/${file} ${newroot}/${dir}
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
echo move libxrpl headers
|
|
||||||
files=$(extract_list 'LIBXRPL HEADERS')
|
|
||||||
files+=(
|
|
||||||
basics/SlabAllocator.h
|
|
||||||
|
|
||||||
beast/asio/io_latency_probe.h
|
|
||||||
beast/container/aged_container.h
|
|
||||||
beast/container/aged_container_utility.h
|
|
||||||
beast/container/aged_map.h
|
|
||||||
beast/container/aged_multimap.h
|
|
||||||
beast/container/aged_multiset.h
|
|
||||||
beast/container/aged_set.h
|
|
||||||
beast/container/aged_unordered_map.h
|
|
||||||
beast/container/aged_unordered_multimap.h
|
|
||||||
beast/container/aged_unordered_multiset.h
|
|
||||||
beast/container/aged_unordered_set.h
|
|
||||||
beast/container/detail/aged_associative_container.h
|
|
||||||
beast/container/detail/aged_container_iterator.h
|
|
||||||
beast/container/detail/aged_ordered_container.h
|
|
||||||
beast/container/detail/aged_unordered_container.h
|
|
||||||
beast/container/detail/empty_base_optimization.h
|
|
||||||
beast/core/LockFreeStack.h
|
|
||||||
beast/insight/Collector.h
|
|
||||||
beast/insight/Counter.h
|
|
||||||
beast/insight/CounterImpl.h
|
|
||||||
beast/insight/Event.h
|
|
||||||
beast/insight/EventImpl.h
|
|
||||||
beast/insight/Gauge.h
|
|
||||||
beast/insight/GaugeImpl.h
|
|
||||||
beast/insight/Group.h
|
|
||||||
beast/insight/Groups.h
|
|
||||||
beast/insight/Hook.h
|
|
||||||
beast/insight/HookImpl.h
|
|
||||||
beast/insight/Insight.h
|
|
||||||
beast/insight/Meter.h
|
|
||||||
beast/insight/MeterImpl.h
|
|
||||||
beast/insight/NullCollector.h
|
|
||||||
beast/insight/StatsDCollector.h
|
|
||||||
beast/test/fail_counter.h
|
|
||||||
beast/test/fail_stream.h
|
|
||||||
beast/test/pipe_stream.h
|
|
||||||
beast/test/sig_wait.h
|
|
||||||
beast/test/string_iostream.h
|
|
||||||
beast/test/string_istream.h
|
|
||||||
beast/test/string_ostream.h
|
|
||||||
beast/test/test_allocator.h
|
|
||||||
beast/test/yield_to.h
|
|
||||||
beast/utility/hash_pair.h
|
|
||||||
beast/utility/maybe_const.h
|
|
||||||
beast/utility/temp_dir.h
|
|
||||||
|
|
||||||
# included by only json/impl/json_assert.h
|
|
||||||
json/json_errors.h
|
|
||||||
|
|
||||||
protocol/PayChan.h
|
|
||||||
protocol/RippleLedgerHash.h
|
|
||||||
protocol/messages.h
|
|
||||||
protocol/st.h
|
|
||||||
)
|
|
||||||
files+=(
|
|
||||||
basics/README.md
|
|
||||||
crypto/README.md
|
|
||||||
json/README.md
|
|
||||||
protocol/README.md
|
|
||||||
resource/README.md
|
|
||||||
)
|
|
||||||
move_files src/ripple include/xrpl detail ${files[@]}
|
|
||||||
|
|
||||||
echo move libxrpl sources
|
|
||||||
files=$(extract_list 'LIBXRPL SOURCES')
|
|
||||||
move_files src/ripple src/libxrpl "" ${files[@]}
|
|
||||||
|
|
||||||
echo check leftovers
|
|
||||||
dirs=$(cd include/xrpl; ls -d */)
|
|
||||||
dirs=$(cd src/ripple; ls -d ${dirs} 2>/dev/null || true)
|
|
||||||
files="$(cd src/ripple; find ${dirs} -type f)"
|
|
||||||
if [ -n "${files}" ]; then
|
|
||||||
echo "leftover files:"
|
|
||||||
echo ${files}
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo remove empty directories
|
|
||||||
empty_dirs="$(cd src/ripple; find ${dirs} -depth -type d)"
|
|
||||||
for dir in ${empty_dirs[@]}; do
|
|
||||||
if [ -e ${dir} ]; then
|
|
||||||
rmdir ${dir}
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo move xrpld sources
|
|
||||||
files=$(
|
|
||||||
extract_list 'XRPLD SOURCES'
|
|
||||||
cd src/ripple
|
|
||||||
find * -regex '.*\.\(h\|ipp\|md\|pu\|uml\|png\)'
|
|
||||||
)
|
|
||||||
move_files src/ripple src/xrpld detail ${files[@]}
|
|
||||||
|
|
||||||
files="$(cd src/ripple; find . -type f)"
|
|
||||||
if [ -n "${files}" ]; then
|
|
||||||
echo "leftover files:"
|
|
||||||
echo ${files}
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -rf src/ripple
|
|
||||||
|
|
||||||
echo rename .hpp to .h
|
|
||||||
find include src -name '*.hpp' -exec bash -c 'f="{}"; git mv "${f}" "${f%hpp}h"' \;
|
|
||||||
|
|
||||||
echo move PerfLog.h
|
|
||||||
if [ -e include/xrpl/basics/PerfLog.h ]; then
|
|
||||||
git mv include/xrpl/basics/PerfLog.h src/xrpld/perflog
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Make sure all protobuf includes have the correct prefix.
|
|
||||||
protobuf_replace='s:^#include\s*["<].*org/xrpl\([^">]\+\)[">]:#include <xrpl/proto/org/xrpl\1>:'
|
|
||||||
# Make sure first-party includes use angle brackets and .h extension.
|
|
||||||
ripple_replace='s:include\s*["<]ripple/\(.*\)\.h\(pp\)\?[">]:include <ripple/\1.h>:'
|
|
||||||
beast_replace='s:include\s*<beast/:include <xrpl/beast/:'
|
|
||||||
# Rename impl directories to detail.
|
|
||||||
impl_rename='s:\(<xrpl.*\)/impl\(/details\)\?/:\1/detail/:'
|
|
||||||
|
|
||||||
echo rewrite includes in libxrpl
|
|
||||||
find include/xrpl src/libxrpl -type f -exec sed -i \
|
|
||||||
-e "${protobuf_replace}" \
|
|
||||||
-e "${ripple_replace}" \
|
|
||||||
-e "${beast_replace}" \
|
|
||||||
-e 's:^#include <ripple/:#include <xrpl/:' \
|
|
||||||
-e "${impl_rename}" \
|
|
||||||
{} +
|
|
||||||
|
|
||||||
echo rewrite includes in xrpld
|
|
||||||
# # https://www.baeldung.com/linux/join-multiple-lines
|
|
||||||
libxrpl_dirs="$(cd include/xrpl; ls -d1 */ | sed 's:/$::')"
|
|
||||||
# libxrpl_dirs='a\nb\nc\n'
|
|
||||||
readarray -t libxrpl_dirs <<< "${libxrpl_dirs}"
|
|
||||||
# libxrpl_dirs=(a b c)
|
|
||||||
libxrpl_dirs=$(printf -v txt '%s\\|' "${libxrpl_dirs[@]}"; echo "${txt%\\|}")
|
|
||||||
# libxrpl_dirs='a\|b\|c'
|
|
||||||
find src/xrpld src/test -type f -exec sed -i \
|
|
||||||
-e "${protobuf_replace}" \
|
|
||||||
-e "${ripple_replace}" \
|
|
||||||
-e "${beast_replace}" \
|
|
||||||
-e "s:^#include <ripple/basics/PerfLog.h>:#include <xrpld/perflog/PerfLog.h>:" \
|
|
||||||
-e "s:^#include <ripple/\(${libxrpl_dirs}\)/:#include <xrpl/\1/:" \
|
|
||||||
-e 's:^#include <ripple/:#include <xrpld/:' \
|
|
||||||
-e "${impl_rename}" \
|
|
||||||
{} +
|
|
||||||
|
|
||||||
git commit -m 'Rearrange sources' --author 'Pretty Printer <cpp@ripple.com>'
|
|
||||||
find include src -type f \( -name '*.cpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-10 -i {} +
|
|
||||||
git add --update .
|
|
||||||
git commit -m 'Rewrite includes' --author 'Pretty Printer <cpp@ripple.com>'
|
|
||||||
./Builds/levelization/levelization.sh
|
|
||||||
git add --update .
|
|
||||||
git commit -m 'Recompute loops' --author 'Pretty Printer <cpp@ripple.com>'
|
|
||||||
@@ -95,16 +95,8 @@ if [[ "$4" == "" ]]; then
|
|||||||
echo "Non GH, local building, no Action runner magic"
|
echo "Non GH, local building, no Action runner magic"
|
||||||
else
|
else
|
||||||
# GH Action, runner
|
# GH Action, runner
|
||||||
if [[ "$(git rev-parse --abbrev-ref HEAD)" == "release" ]]; then
|
cp /io/release-build/xahaud /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
|
||||||
echo "building on the release branch... placing it in builds/candidate"
|
cp /io/release-build/release.info /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
|
||||||
mkdir /data/builds/candidate
|
|
||||||
cp /io/release-build/xahaud /data/builds/candidate/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
|
|
||||||
cp /io/release-build/release.info /data/builds/candidate/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
|
|
||||||
else
|
|
||||||
echo "building non-release branch, placing it in builds root"
|
|
||||||
cp /io/release-build/xahaud /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
|
|
||||||
cp /io/release-build/release.info /data/builds/$(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4.releaseinfo
|
|
||||||
fi
|
|
||||||
echo "Published build to: http://build.xahau.tech/"
|
echo "Published build to: http://build.xahau.tech/"
|
||||||
echo $(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
|
echo $(date +%Y).$(date +%-m).$(date +%-d)-$(git rev-parse --abbrev-ref HEAD)+$4
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -95,9 +95,6 @@
|
|||||||
# - replace both functions setup_target_for_coverage_gcovr_* with a single setup_target_for_coverage_gcovr
|
# - replace both functions setup_target_for_coverage_gcovr_* with a single setup_target_for_coverage_gcovr
|
||||||
# - add support for all gcovr output formats
|
# - add support for all gcovr output formats
|
||||||
#
|
#
|
||||||
# 2024-04-03, Bronek Kozicki
|
|
||||||
# - add support for output formats: jacoco, clover, lcov
|
|
||||||
#
|
|
||||||
# USAGE:
|
# USAGE:
|
||||||
#
|
#
|
||||||
# 1. Copy this file into your cmake modules path.
|
# 1. Copy this file into your cmake modules path.
|
||||||
@@ -259,10 +256,10 @@ endif()
|
|||||||
# BASE_DIRECTORY "../" # Base directory for report
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
# # (defaults to PROJECT_SOURCE_DIR)
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
# FORMAT "cobertura" # Output format, one of:
|
# FORMAT "cobertura" # Output format, one of:
|
||||||
# # xml cobertura sonarqube jacoco clover
|
# # xml cobertura sonarqube json-summary
|
||||||
# # json-summary json-details coveralls csv
|
# # json-details coveralls csv txt
|
||||||
# # txt html-single html-nested html-details
|
# # html-single html-nested html-details
|
||||||
# # lcov (xml is an alias to cobertura;
|
# # (xml is an alias to cobertura;
|
||||||
# # if no format is set, defaults to xml)
|
# # if no format is set, defaults to xml)
|
||||||
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||||
# # to BASE_DIRECTORY, with CMake 3.4+)
|
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||||
@@ -311,8 +308,6 @@ function(setup_target_for_coverage_gcovr)
|
|||||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.txt)
|
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.txt)
|
||||||
elseif(Coverage_FORMAT STREQUAL "csv")
|
elseif(Coverage_FORMAT STREQUAL "csv")
|
||||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.csv)
|
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.csv)
|
||||||
elseif(Coverage_FORMAT STREQUAL "lcov")
|
|
||||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.lcov)
|
|
||||||
else()
|
else()
|
||||||
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.xml)
|
set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.xml)
|
||||||
endif()
|
endif()
|
||||||
@@ -325,14 +320,6 @@ function(setup_target_for_coverage_gcovr)
|
|||||||
set(Coverage_FORMAT cobertura) # overwrite xml
|
set(Coverage_FORMAT cobertura) # overwrite xml
|
||||||
elseif(Coverage_FORMAT STREQUAL "sonarqube")
|
elseif(Coverage_FORMAT STREQUAL "sonarqube")
|
||||||
list(APPEND GCOVR_ADDITIONAL_ARGS --sonarqube "${GCOVR_OUTPUT_FILE}" )
|
list(APPEND GCOVR_ADDITIONAL_ARGS --sonarqube "${GCOVR_OUTPUT_FILE}" )
|
||||||
elseif(Coverage_FORMAT STREQUAL "jacoco")
|
|
||||||
list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco "${GCOVR_OUTPUT_FILE}" )
|
|
||||||
list(APPEND GCOVR_ADDITIONAL_ARGS --jacoco-pretty )
|
|
||||||
elseif(Coverage_FORMAT STREQUAL "clover")
|
|
||||||
list(APPEND GCOVR_ADDITIONAL_ARGS --clover "${GCOVR_OUTPUT_FILE}" )
|
|
||||||
list(APPEND GCOVR_ADDITIONAL_ARGS --clover-pretty )
|
|
||||||
elseif(Coverage_FORMAT STREQUAL "lcov")
|
|
||||||
list(APPEND GCOVR_ADDITIONAL_ARGS --lcov "${GCOVR_OUTPUT_FILE}" )
|
|
||||||
elseif(Coverage_FORMAT STREQUAL "json-summary")
|
elseif(Coverage_FORMAT STREQUAL "json-summary")
|
||||||
list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary "${GCOVR_OUTPUT_FILE}" )
|
list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary "${GCOVR_OUTPUT_FILE}" )
|
||||||
list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary-pretty)
|
list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary-pretty)
|
||||||
|
|||||||
@@ -93,27 +93,16 @@ if (MSVC)
|
|||||||
-errorreport:none
|
-errorreport:none
|
||||||
-machine:X64)
|
-machine:X64)
|
||||||
else ()
|
else ()
|
||||||
# HACK : because these need to come first, before any warning demotion
|
|
||||||
string (APPEND CMAKE_CXX_FLAGS " -Wall -Wdeprecated")
|
|
||||||
if (wextra)
|
|
||||||
string (APPEND CMAKE_CXX_FLAGS " -Wextra -Wno-unused-parameter")
|
|
||||||
endif ()
|
|
||||||
# not MSVC
|
|
||||||
target_compile_options (common
|
target_compile_options (common
|
||||||
INTERFACE
|
INTERFACE
|
||||||
|
-Wall
|
||||||
|
-Wdeprecated
|
||||||
|
$<$<BOOL:${is_clang}>:-Wno-deprecated-declarations>
|
||||||
|
$<$<BOOL:${wextra}>:-Wextra -Wno-unused-parameter>
|
||||||
$<$<BOOL:${werr}>:-Werror>
|
$<$<BOOL:${werr}>:-Werror>
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:
|
-fstack-protector
|
||||||
-frtti
|
|
||||||
-Wnon-virtual-dtor
|
|
||||||
>
|
|
||||||
-Wno-sign-compare
|
-Wno-sign-compare
|
||||||
-Wno-char-subscripts
|
-Wno-unused-but-set-variable
|
||||||
-Wno-format
|
|
||||||
-Wno-unused-local-typedefs
|
|
||||||
$<$<BOOL:${is_gcc}>:
|
|
||||||
-Wno-unused-but-set-variable
|
|
||||||
-Wno-deprecated
|
|
||||||
>
|
|
||||||
$<$<NOT:$<CONFIG:Debug>>:-fno-strict-aliasing>
|
$<$<NOT:$<CONFIG:Debug>>:-fno-strict-aliasing>
|
||||||
# tweak gcc optimization for debug
|
# tweak gcc optimization for debug
|
||||||
$<$<AND:$<BOOL:${is_gcc}>,$<CONFIG:Debug>>:-O0>
|
$<$<AND:$<BOOL:${is_gcc}>,$<CONFIG:Debug>>:-O0>
|
||||||
|
|||||||
@@ -164,6 +164,9 @@ if(xrpld)
|
|||||||
add_executable(rippled)
|
add_executable(rippled)
|
||||||
if(tests)
|
if(tests)
|
||||||
target_compile_definitions(rippled PUBLIC ENABLE_TESTS)
|
target_compile_definitions(rippled PUBLIC ENABLE_TESTS)
|
||||||
|
target_compile_definitions(rippled PRIVATE
|
||||||
|
UNIT_TEST_REFERENCE_FEE=${UNIT_TEST_REFERENCE_FEE}
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
target_include_directories(rippled
|
target_include_directories(rippled
|
||||||
PRIVATE
|
PRIVATE
|
||||||
|
|||||||
@@ -2,22 +2,7 @@
|
|||||||
convenience variables and sanity checks
|
convenience variables and sanity checks
|
||||||
#]===================================================================]
|
#]===================================================================]
|
||||||
|
|
||||||
include(ProcessorCount)
|
get_property(is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
|
||||||
if (NOT ep_procs)
|
|
||||||
ProcessorCount(ep_procs)
|
|
||||||
if (ep_procs GREATER 1)
|
|
||||||
# never use more than half of cores for EP builds
|
|
||||||
math (EXPR ep_procs "${ep_procs} / 2")
|
|
||||||
message (STATUS "Using ${ep_procs} cores for ExternalProject builds.")
|
|
||||||
endif ()
|
|
||||||
endif ()
|
|
||||||
get_property (is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
|
||||||
if (is_multiconfig STREQUAL "NOTFOUND")
|
|
||||||
if (${CMAKE_GENERATOR} STREQUAL "Xcode" OR ${CMAKE_GENERATOR} MATCHES "^Visual Studio")
|
|
||||||
set (is_multiconfig TRUE)
|
|
||||||
endif ()
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set (CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE)
|
set (CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE)
|
||||||
if (NOT is_multiconfig)
|
if (NOT is_multiconfig)
|
||||||
|
|||||||
@@ -11,8 +11,14 @@ option(assert "Enables asserts, even in release builds" OFF)
|
|||||||
option(xrpld "Build xrpld" ON)
|
option(xrpld "Build xrpld" ON)
|
||||||
|
|
||||||
option(tests "Build tests" ON)
|
option(tests "Build tests" ON)
|
||||||
|
if(tests)
|
||||||
|
# This setting allows making a separate workflow to test fees other than default 10
|
||||||
|
if(NOT UNIT_TEST_REFERENCE_FEE)
|
||||||
|
set(UNIT_TEST_REFERENCE_FEE "10" CACHE STRING "")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
option(unity "Creates a build using UNITY support in cmake. This is the default" ON)
|
option(unity "Creates a build using UNITY support in cmake." OFF)
|
||||||
if(unity)
|
if(unity)
|
||||||
if(NOT is_ci)
|
if(NOT is_ci)
|
||||||
set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "")
|
set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "")
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ find_package(Boost 1.86 REQUIRED
|
|||||||
COMPONENTS
|
COMPONENTS
|
||||||
chrono
|
chrono
|
||||||
container
|
container
|
||||||
context
|
|
||||||
coroutine
|
coroutine
|
||||||
date_time
|
date_time
|
||||||
filesystem
|
filesystem
|
||||||
@@ -25,7 +24,7 @@ endif()
|
|||||||
|
|
||||||
target_link_libraries(ripple_boost
|
target_link_libraries(ripple_boost
|
||||||
INTERFACE
|
INTERFACE
|
||||||
Boost::boost
|
Boost::headers
|
||||||
Boost::chrono
|
Boost::chrono
|
||||||
Boost::container
|
Boost::container
|
||||||
Boost::coroutine
|
Boost::coroutine
|
||||||
|
|||||||
41
cmake/xrpl_add_test.cmake
Normal file
41
cmake/xrpl_add_test.cmake
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
include(isolate_headers)
|
||||||
|
|
||||||
|
function(xrpl_add_test name)
|
||||||
|
set(target ${PROJECT_NAME}.test.${name})
|
||||||
|
|
||||||
|
file(GLOB_RECURSE sources CONFIGURE_DEPENDS
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp"
|
||||||
|
)
|
||||||
|
add_executable(${target} EXCLUDE_FROM_ALL ${ARGN} ${sources})
|
||||||
|
|
||||||
|
isolate_headers(
|
||||||
|
${target}
|
||||||
|
"${CMAKE_SOURCE_DIR}"
|
||||||
|
"${CMAKE_SOURCE_DIR}/tests/${name}"
|
||||||
|
PRIVATE
|
||||||
|
)
|
||||||
|
|
||||||
|
# Make sure the test isn't optimized away in unity builds
|
||||||
|
set_target_properties(${target} PROPERTIES
|
||||||
|
UNITY_BUILD_MODE GROUP
|
||||||
|
UNITY_BUILD_BATCH_SIZE 0) # Adjust as needed
|
||||||
|
|
||||||
|
add_test(NAME ${target} COMMAND ${target})
|
||||||
|
set_tests_properties(
|
||||||
|
${target} PROPERTIES
|
||||||
|
FIXTURES_REQUIRED ${target}_fixture
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(
|
||||||
|
NAME ${target}.build
|
||||||
|
COMMAND
|
||||||
|
${CMAKE_COMMAND}
|
||||||
|
--build ${CMAKE_BINARY_DIR}
|
||||||
|
--config $<CONFIG>
|
||||||
|
--target ${target}
|
||||||
|
)
|
||||||
|
set_tests_properties(${target}.build PROPERTIES
|
||||||
|
FIXTURES_SETUP ${target}_fixture
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
37
conan/profiles/default
Normal file
37
conan/profiles/default
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{% set os = detect_api.detect_os() %}
|
||||||
|
{% set arch = detect_api.detect_arch() %}
|
||||||
|
{% set compiler, version, compiler_exe = detect_api.detect_default_compiler() %}
|
||||||
|
{% set compiler_version = version %}
|
||||||
|
{% if os == "Linux" %}
|
||||||
|
{% set compiler_version = detect_api.default_compiler_version(compiler, version) %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
[settings]
|
||||||
|
os={{ os }}
|
||||||
|
arch={{ arch }}
|
||||||
|
build_type=Debug
|
||||||
|
compiler={{compiler}}
|
||||||
|
compiler.version={{ compiler_version }}
|
||||||
|
compiler.cppstd=20
|
||||||
|
{% if os == "Windows" %}
|
||||||
|
compiler.runtime=static
|
||||||
|
{% else %}
|
||||||
|
compiler.libcxx={{detect_api.detect_libcxx(compiler, version, compiler_exe)}}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
[conf]
|
||||||
|
{% if compiler == "clang" and compiler_version >= 19 %}
|
||||||
|
tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
|
||||||
|
{% endif %}
|
||||||
|
{% if compiler == "apple-clang" and compiler_version >= 17 %}
|
||||||
|
tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
|
||||||
|
{% endif %}
|
||||||
|
{% if compiler == "clang" and compiler_version == 16 %}
|
||||||
|
tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS']
|
||||||
|
{% endif %}
|
||||||
|
{% if compiler == "gcc" and compiler_version < 13 %}
|
||||||
|
tools.build:cxxflags=['-Wno-restrict']
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
[tool_requires]
|
||||||
|
!cmake/*: cmake/[>=3 <4]
|
||||||
54
conanfile.py
54
conanfile.py
@@ -1,4 +1,4 @@
|
|||||||
from conan import ConanFile
|
from conan import ConanFile, __version__ as conan_version
|
||||||
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
|
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@@ -26,17 +26,19 @@ class Xrpl(ConanFile):
|
|||||||
}
|
}
|
||||||
|
|
||||||
requires = [
|
requires = [
|
||||||
'date/3.0.3',
|
|
||||||
'grpc/1.50.1',
|
'grpc/1.50.1',
|
||||||
'libarchive/3.7.6',
|
'libarchive/3.8.1',
|
||||||
'magic_enum/0.9.5',
|
'magic_enum/0.9.5',
|
||||||
'nudb/2.0.8',
|
'nudb/2.0.9',
|
||||||
'openssl/3.6.0',
|
'openssl/3.6.0',
|
||||||
'soci/4.0.3@xahaud/stable',
|
'soci/4.0.3@xahaud/stable',
|
||||||
'xxhash/0.8.2',
|
|
||||||
'zlib/1.3.1',
|
'zlib/1.3.1',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
test_requires = [
|
||||||
|
'doctest/2.4.11',
|
||||||
|
]
|
||||||
|
|
||||||
tool_requires = [
|
tool_requires = [
|
||||||
'protobuf/3.21.12',
|
'protobuf/3.21.12',
|
||||||
]
|
]
|
||||||
@@ -92,12 +94,13 @@ class Xrpl(ConanFile):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def set_version(self):
|
def set_version(self):
|
||||||
path = f'{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp'
|
if self.version is None:
|
||||||
regex = r'versionString\s?=\s?\"(.*)\"'
|
path = f'{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp'
|
||||||
with open(path, 'r') as file:
|
regex = r'versionString\s?=\s?\"(.*)\"'
|
||||||
matches = (re.search(regex, line) for line in file)
|
with open(path, encoding='utf-8') as file:
|
||||||
match = next(m for m in matches if m)
|
matches = (re.search(regex, line) for line in file)
|
||||||
self.version = match.group(1)
|
match = next(m for m in matches if m)
|
||||||
|
self.version = match.group(1)
|
||||||
|
|
||||||
def build_requirements(self):
|
def build_requirements(self):
|
||||||
# These provide build tools (protoc, grpc plugins) that run during build
|
# These provide build tools (protoc, grpc plugins) that run during build
|
||||||
@@ -111,24 +114,27 @@ class Xrpl(ConanFile):
|
|||||||
self.options['boost/*'].visibility = 'global'
|
self.options['boost/*'].visibility = 'global'
|
||||||
|
|
||||||
def requirements(self):
|
def requirements(self):
|
||||||
|
# Conan 2 requires transitive headers to be specified
|
||||||
|
transitive_headers_opt = {'transitive_headers': True} if conan_version.split('.')[0] == '2' else {}
|
||||||
# Force sqlite3 version to avoid conflicts with soci
|
# Force sqlite3 version to avoid conflicts with soci
|
||||||
self.requires('sqlite3/3.47.0', override=True)
|
self.requires('sqlite3/3.49.1', override=True)
|
||||||
# Force our custom snappy build for all dependencies
|
# Force our custom snappy build to avoid Conan CMakeDeps stdc++ heuristic bug
|
||||||
self.requires('snappy/1.1.10@xahaud/stable', override=True)
|
self.requires('snappy/1.1.10@xahaud/stable', override=True)
|
||||||
# Force boost version for all dependencies to avoid conflicts
|
# Force boost version for all dependencies to avoid conflicts
|
||||||
self.requires('boost/1.86.0', override=True)
|
self.requires('boost/1.86.0', force=True, **transitive_headers_opt)
|
||||||
|
self.requires('date/3.0.4', **transitive_headers_opt)
|
||||||
self.requires('lz4/1.10.0', force=True)
|
self.requires('lz4/1.10.0', force=True)
|
||||||
|
|
||||||
if self.options.with_wasmedge:
|
if self.options.with_wasmedge:
|
||||||
self.requires('wasmedge/0.11.2@xahaud/stable')
|
self.requires('wasmedge/0.11.2@xahaud/stable', **transitive_headers_opt)
|
||||||
if self.options.jemalloc:
|
if self.options.jemalloc:
|
||||||
self.requires('jemalloc/5.3.0')
|
self.requires('jemalloc/5.3.0', **transitive_headers_opt)
|
||||||
if self.options.rocksdb:
|
if self.options.rocksdb:
|
||||||
self.requires('rocksdb/6.29.5')
|
self.requires('rocksdb/10.0.1')
|
||||||
|
self.requires('xxhash/0.8.3', **transitive_headers_opt)
|
||||||
|
|
||||||
exports_sources = (
|
exports_sources = (
|
||||||
'CMakeLists.txt',
|
'CMakeLists.txt',
|
||||||
'bin/getRippledInfo',
|
|
||||||
'cfg/*',
|
'cfg/*',
|
||||||
'cmake/*',
|
'cmake/*',
|
||||||
'external/*',
|
'external/*',
|
||||||
@@ -179,7 +185,17 @@ class Xrpl(ConanFile):
|
|||||||
# `include/`, not `include/ripple/proto/`.
|
# `include/`, not `include/ripple/proto/`.
|
||||||
libxrpl.includedirs = ['include', 'include/ripple/proto']
|
libxrpl.includedirs = ['include', 'include/ripple/proto']
|
||||||
libxrpl.requires = [
|
libxrpl.requires = [
|
||||||
'boost::boost',
|
'boost::headers',
|
||||||
|
'boost::chrono',
|
||||||
|
'boost::container',
|
||||||
|
'boost::coroutine',
|
||||||
|
'boost::date_time',
|
||||||
|
'boost::filesystem',
|
||||||
|
'boost::json',
|
||||||
|
'boost::program_options',
|
||||||
|
'boost::regex',
|
||||||
|
'boost::system',
|
||||||
|
'boost::thread',
|
||||||
'date::date',
|
'date::date',
|
||||||
'grpc::grpc++',
|
'grpc::grpc++',
|
||||||
'libarchive::libarchive',
|
'libarchive::libarchive',
|
||||||
|
|||||||
6
docs/build/environment.md
vendored
6
docs/build/environment.md
vendored
@@ -5,7 +5,6 @@ platforms: Linux, macOS, or Windows.
|
|||||||
|
|
||||||
[BUILD.md]: ../../BUILD.md
|
[BUILD.md]: ../../BUILD.md
|
||||||
|
|
||||||
|
|
||||||
## Linux
|
## Linux
|
||||||
|
|
||||||
Package ecosystems vary across Linux distributions,
|
Package ecosystems vary across Linux distributions,
|
||||||
@@ -23,7 +22,7 @@ direction.
|
|||||||
|
|
||||||
```
|
```
|
||||||
apt update
|
apt update
|
||||||
apt install --yes curl git libssl-dev python3.10-dev python3-pip make g++-11 libprotobuf-dev protobuf-compiler
|
apt install --yes curl git libssl-dev pipx python3.10-dev python3-pip make g++-11 libprotobuf-dev protobuf-compiler
|
||||||
|
|
||||||
curl --location --remote-name \
|
curl --location --remote-name \
|
||||||
"https://github.com/Kitware/CMake/releases/download/v3.25.1/cmake-3.25.1.tar.gz"
|
"https://github.com/Kitware/CMake/releases/download/v3.25.1/cmake-3.25.1.tar.gz"
|
||||||
@@ -35,7 +34,8 @@ make --jobs $(nproc)
|
|||||||
make install
|
make install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
pip3 install 'conan<2'
|
pipx install 'conan<2'
|
||||||
|
pipx ensurepath
|
||||||
```
|
```
|
||||||
|
|
||||||
[1]: https://github.com/thejohnfreeman/rippled-docker/blob/master/ubuntu-22.04/install.sh
|
[1]: https://github.com/thejohnfreeman/rippled-docker/blob/master/ubuntu-22.04/install.sh
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
from conan import ConanFile, conan_version
|
|
||||||
from conan.tools.cmake import CMake, cmake_layout
|
|
||||||
|
|
||||||
class Example(ConanFile):
|
|
||||||
|
|
||||||
def set_name(self):
|
|
||||||
if self.name is None:
|
|
||||||
self.name = 'example'
|
|
||||||
|
|
||||||
def set_version(self):
|
|
||||||
if self.version is None:
|
|
||||||
self.version = '0.1.0'
|
|
||||||
|
|
||||||
license = 'ISC'
|
|
||||||
author = 'John Freeman <jfreeman08@gmail.com>'
|
|
||||||
|
|
||||||
settings = 'os', 'compiler', 'build_type', 'arch'
|
|
||||||
options = {'shared': [True, False], 'fPIC': [True, False]}
|
|
||||||
default_options = {
|
|
||||||
'shared': False,
|
|
||||||
'fPIC': True,
|
|
||||||
'xrpl:xrpld': False,
|
|
||||||
}
|
|
||||||
|
|
||||||
requires = ['xrpl/2.2.0-rc1@jfreeman/nodestore']
|
|
||||||
generators = ['CMakeDeps', 'CMakeToolchain']
|
|
||||||
|
|
||||||
exports_sources = [
|
|
||||||
'CMakeLists.txt',
|
|
||||||
'cmake/*',
|
|
||||||
'external/*',
|
|
||||||
'include/*',
|
|
||||||
'src/*',
|
|
||||||
]
|
|
||||||
|
|
||||||
# For out-of-source build.
|
|
||||||
# https://docs.conan.io/en/latest/reference/build_helpers/cmake.html#configure
|
|
||||||
no_copy_source = True
|
|
||||||
|
|
||||||
def layout(self):
|
|
||||||
cmake_layout(self)
|
|
||||||
|
|
||||||
def config_options(self):
|
|
||||||
if self.settings.os == 'Windows':
|
|
||||||
del self.options.fPIC
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
cmake = CMake(self)
|
|
||||||
cmake.configure(variables={'BUILD_TESTING': 'NO'})
|
|
||||||
cmake.build()
|
|
||||||
|
|
||||||
def package(self):
|
|
||||||
cmake = CMake(self)
|
|
||||||
cmake.install()
|
|
||||||
|
|
||||||
def package_info(self):
|
|
||||||
path = f'{self.package_folder}/share/{self.name}/cpp_info.py'
|
|
||||||
with open(path, 'r') as file:
|
|
||||||
exec(file.read(), {}, {'self': self.cpp_info})
|
|
||||||
13
external/README.md
vendored
13
external/README.md
vendored
@@ -2,11 +2,8 @@ The subdirectories in this directory contain either copies or Conan recipes
|
|||||||
of external libraries used by rippled.
|
of external libraries used by rippled.
|
||||||
The Conan recipes include patches we have not yet pushed upstream.
|
The Conan recipes include patches we have not yet pushed upstream.
|
||||||
|
|
||||||
| Folder | Upstream | Description |
|
| Folder | Upstream | Description |
|
||||||
|:----------------|:---------------------------------------------|:------------|
|
| :--------------- | :------------------------------------------------------------- | :------------------------------------------------------------------------------------------- |
|
||||||
| `antithesis-sdk`| [Project](https://github.com/antithesishq/antithesis-sdk-cpp/) | [Antithesis](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html) SDK for C++ |
|
| `antithesis-sdk` | [Project](https://github.com/antithesishq/antithesis-sdk-cpp/) | [Antithesis](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html) SDK for C++ |
|
||||||
| `ed25519-donna` | [Project](https://github.com/floodyberry/ed25519-donna) | [Ed25519](http://ed25519.cr.yp.to/) digital signatures |
|
| `ed25519-donna` | [Project](https://github.com/floodyberry/ed25519-donna) | [Ed25519](http://ed25519.cr.yp.to/) digital signatures |
|
||||||
| `rocksdb` | [Recipe](https://github.com/conan-io/conan-center-index/tree/master/recipes/rocksdb) | Fast key/value database. (Supports rotational disks better than NuDB.) |
|
| `secp256k1` | [Project](https://github.com/bitcoin-core/secp256k1) | ECDSA digital signatures using the **secp256k1** curve |
|
||||||
| `secp256k1` | [Project](https://github.com/bitcoin-core/secp256k1) | ECDSA digital signatures using the **secp256k1** curve |
|
|
||||||
| `snappy` | [Recipe](https://github.com/conan-io/conan-center-index/tree/master/recipes/snappy) | "Snappy" lossless compression algorithm. |
|
|
||||||
| `soci` | [Recipe](https://github.com/conan-io/conan-center-index/tree/master/recipes/soci) | Abstraction layer for database access. |
|
|
||||||
|
|||||||
2
external/antithesis-sdk/CMakeLists.txt
vendored
2
external/antithesis-sdk/CMakeLists.txt
vendored
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
|
||||||
# Note, version set explicitly by rippled project
|
# Note, version set explicitly by rippled project
|
||||||
project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX)
|
project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX)
|
||||||
|
|||||||
7
external/antithesis-sdk/README.md
vendored
7
external/antithesis-sdk/README.md
vendored
@@ -1,8 +1,9 @@
|
|||||||
# Antithesis C++ SDK
|
# Antithesis C++ SDK
|
||||||
|
|
||||||
This library provides methods for C++ programs to configure the [Antithesis](https://antithesis.com) platform. It contains three kinds of functionality:
|
This library provides methods for C++ programs to configure the [Antithesis](https://antithesis.com) platform. It contains three kinds of functionality:
|
||||||
* Assertion macros that allow you to define test properties about your software or workload.
|
|
||||||
* Randomness functions for requesting both structured and unstructured randomness from the Antithesis platform.
|
- Assertion macros that allow you to define test properties about your software or workload.
|
||||||
* Lifecycle functions that inform the Antithesis environment that particular test phases or milestones have been reached.
|
- Randomness functions for requesting both structured and unstructured randomness from the Antithesis platform.
|
||||||
|
- Lifecycle functions that inform the Antithesis environment that particular test phases or milestones have been reached.
|
||||||
|
|
||||||
For general usage guidance see the [Antithesis C++ SDK Documentation](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview/)
|
For general usage guidance see the [Antithesis C++ SDK Documentation](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview/)
|
||||||
|
|||||||
3
external/ed25519-donna/CMakeLists.txt
vendored
3
external/ed25519-donna/CMakeLists.txt
vendored
@@ -17,6 +17,9 @@ add_library(ed25519 STATIC
|
|||||||
)
|
)
|
||||||
add_library(ed25519::ed25519 ALIAS ed25519)
|
add_library(ed25519::ed25519 ALIAS ed25519)
|
||||||
target_link_libraries(ed25519 PUBLIC OpenSSL::SSL)
|
target_link_libraries(ed25519 PUBLIC OpenSSL::SSL)
|
||||||
|
if(NOT MSVC)
|
||||||
|
target_compile_options(ed25519 PRIVATE -Wno-implicit-fallthrough)
|
||||||
|
endif()
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
|||||||
97
external/ed25519-donna/README.md
vendored
97
external/ed25519-donna/README.md
vendored
@@ -1,12 +1,12 @@
|
|||||||
[ed25519](http://ed25519.cr.yp.to/) is an
|
[ed25519](http://ed25519.cr.yp.to/) is an
|
||||||
[Elliptic Curve Digital Signature Algortithm](http://en.wikipedia.org/wiki/Elliptic_Curve_DSA),
|
[Elliptic Curve Digital Signature Algortithm](http://en.wikipedia.org/wiki/Elliptic_Curve_DSA),
|
||||||
developed by [Dan Bernstein](http://cr.yp.to/djb.html),
|
developed by [Dan Bernstein](http://cr.yp.to/djb.html),
|
||||||
[Niels Duif](http://www.nielsduif.nl/),
|
[Niels Duif](http://www.nielsduif.nl/),
|
||||||
[Tanja Lange](http://hyperelliptic.org/tanja),
|
[Tanja Lange](http://hyperelliptic.org/tanja),
|
||||||
[Peter Schwabe](http://www.cryptojedi.org/users/peter/),
|
[Peter Schwabe](http://www.cryptojedi.org/users/peter/),
|
||||||
and [Bo-Yin Yang](http://www.iis.sinica.edu.tw/pages/byyang/).
|
and [Bo-Yin Yang](http://www.iis.sinica.edu.tw/pages/byyang/).
|
||||||
|
|
||||||
This project provides performant, portable 32-bit & 64-bit implementations. All implementations are
|
This project provides performant, portable 32-bit & 64-bit implementations. All implementations are
|
||||||
of course constant time in regard to secret data.
|
of course constant time in regard to secret data.
|
||||||
|
|
||||||
#### Performance
|
#### Performance
|
||||||
@@ -52,35 +52,35 @@ are made.
|
|||||||
|
|
||||||
#### Compilation
|
#### Compilation
|
||||||
|
|
||||||
No configuration is needed **if you are compiling against OpenSSL**.
|
No configuration is needed **if you are compiling against OpenSSL**.
|
||||||
|
|
||||||
##### Hash Options
|
##### Hash Options
|
||||||
|
|
||||||
If you are not compiling aginst OpenSSL, you will need a hash function.
|
If you are not compiling aginst OpenSSL, you will need a hash function.
|
||||||
|
|
||||||
To use a simple/**slow** implementation of SHA-512, use `-DED25519_REFHASH` when compiling `ed25519.c`.
|
To use a simple/**slow** implementation of SHA-512, use `-DED25519_REFHASH` when compiling `ed25519.c`.
|
||||||
This should never be used except to verify the code works when OpenSSL is not available.
|
This should never be used except to verify the code works when OpenSSL is not available.
|
||||||
|
|
||||||
To use a custom hash function, use `-DED25519_CUSTOMHASH` when compiling `ed25519.c` and put your
|
To use a custom hash function, use `-DED25519_CUSTOMHASH` when compiling `ed25519.c` and put your
|
||||||
custom hash implementation in ed25519-hash-custom.h. The hash must have a 512bit digest and implement
|
custom hash implementation in ed25519-hash-custom.h. The hash must have a 512bit digest and implement
|
||||||
|
|
||||||
struct ed25519_hash_context;
|
struct ed25519_hash_context;
|
||||||
|
|
||||||
void ed25519_hash_init(ed25519_hash_context *ctx);
|
void ed25519_hash_init(ed25519_hash_context *ctx);
|
||||||
void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen);
|
void ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen);
|
||||||
void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash);
|
void ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash);
|
||||||
void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen);
|
void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen);
|
||||||
|
|
||||||
##### Random Options
|
##### Random Options
|
||||||
|
|
||||||
If you are not compiling aginst OpenSSL, you will need a random function for batch verification.
|
If you are not compiling aginst OpenSSL, you will need a random function for batch verification.
|
||||||
|
|
||||||
To use a custom random function, use `-DED25519_CUSTOMRANDOM` when compiling `ed25519.c` and put your
|
To use a custom random function, use `-DED25519_CUSTOMRANDOM` when compiling `ed25519.c` and put your
|
||||||
custom hash implementation in ed25519-randombytes-custom.h. The random function must implement:
|
custom hash implementation in ed25519-randombytes-custom.h. The random function must implement:
|
||||||
|
|
||||||
void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len);
|
void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len);
|
||||||
|
|
||||||
Use `-DED25519_TEST` when compiling `ed25519.c` to use a deterministically seeded, non-thread safe CSPRNG
|
Use `-DED25519_TEST` when compiling `ed25519.c` to use a deterministically seeded, non-thread safe CSPRNG
|
||||||
variant of Bob Jenkins [ISAAC](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29)
|
variant of Bob Jenkins [ISAAC](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29)
|
||||||
|
|
||||||
##### Minor options
|
##### Minor options
|
||||||
@@ -91,80 +91,79 @@ Use `-DED25519_FORCE_32BIT` to force the use of 32 bit routines even when compil
|
|||||||
|
|
||||||
##### 32-bit
|
##### 32-bit
|
||||||
|
|
||||||
gcc ed25519.c -m32 -O3 -c
|
gcc ed25519.c -m32 -O3 -c
|
||||||
|
|
||||||
##### 64-bit
|
##### 64-bit
|
||||||
|
|
||||||
gcc ed25519.c -m64 -O3 -c
|
gcc ed25519.c -m64 -O3 -c
|
||||||
|
|
||||||
##### SSE2
|
##### SSE2
|
||||||
|
|
||||||
gcc ed25519.c -m32 -O3 -c -DED25519_SSE2 -msse2
|
gcc ed25519.c -m32 -O3 -c -DED25519_SSE2 -msse2
|
||||||
gcc ed25519.c -m64 -O3 -c -DED25519_SSE2
|
gcc ed25519.c -m64 -O3 -c -DED25519_SSE2
|
||||||
|
|
||||||
clang and icc are also supported
|
clang and icc are also supported
|
||||||
|
|
||||||
|
|
||||||
#### Usage
|
#### Usage
|
||||||
|
|
||||||
To use the code, link against `ed25519.o -mbits` and:
|
To use the code, link against `ed25519.o -mbits` and:
|
||||||
|
|
||||||
#include "ed25519.h"
|
#include "ed25519.h"
|
||||||
|
|
||||||
Add `-lssl -lcrypto` when using OpenSSL (Some systems don't need -lcrypto? It might be trial and error).
|
Add `-lssl -lcrypto` when using OpenSSL (Some systems don't need -lcrypto? It might be trial and error).
|
||||||
|
|
||||||
To generate a private key, simply generate 32 bytes from a secure
|
To generate a private key, simply generate 32 bytes from a secure
|
||||||
cryptographic source:
|
cryptographic source:
|
||||||
|
|
||||||
ed25519_secret_key sk;
|
ed25519_secret_key sk;
|
||||||
randombytes(sk, sizeof(ed25519_secret_key));
|
randombytes(sk, sizeof(ed25519_secret_key));
|
||||||
|
|
||||||
To generate a public key:
|
To generate a public key:
|
||||||
|
|
||||||
ed25519_public_key pk;
|
ed25519_public_key pk;
|
||||||
ed25519_publickey(sk, pk);
|
ed25519_publickey(sk, pk);
|
||||||
|
|
||||||
To sign a message:
|
To sign a message:
|
||||||
|
|
||||||
ed25519_signature sig;
|
ed25519_signature sig;
|
||||||
ed25519_sign(message, message_len, sk, pk, signature);
|
ed25519_sign(message, message_len, sk, pk, signature);
|
||||||
|
|
||||||
To verify a signature:
|
To verify a signature:
|
||||||
|
|
||||||
int valid = ed25519_sign_open(message, message_len, pk, signature) == 0;
|
int valid = ed25519_sign_open(message, message_len, pk, signature) == 0;
|
||||||
|
|
||||||
To batch verify signatures:
|
To batch verify signatures:
|
||||||
|
|
||||||
const unsigned char *mp[num] = {message1, message2..}
|
const unsigned char *mp[num] = {message1, message2..}
|
||||||
size_t ml[num] = {message_len1, message_len2..}
|
size_t ml[num] = {message_len1, message_len2..}
|
||||||
const unsigned char *pkp[num] = {pk1, pk2..}
|
const unsigned char *pkp[num] = {pk1, pk2..}
|
||||||
const unsigned char *sigp[num] = {signature1, signature2..}
|
const unsigned char *sigp[num] = {signature1, signature2..}
|
||||||
int valid[num]
|
int valid[num]
|
||||||
|
|
||||||
/* valid[i] will be set to 1 if the individual signature was valid, 0 otherwise */
|
/* valid[i] will be set to 1 if the individual signature was valid, 0 otherwise */
|
||||||
int all_valid = ed25519_sign_open_batch(mp, ml, pkp, sigp, num, valid) == 0;
|
int all_valid = ed25519_sign_open_batch(mp, ml, pkp, sigp, num, valid) == 0;
|
||||||
|
|
||||||
**Note**: Batch verification uses `ed25519_randombytes_unsafe`, implemented in
|
**Note**: Batch verification uses `ed25519_randombytes_unsafe`, implemented in
|
||||||
`ed25519-randombytes.h`, to generate random scalars for the verification code.
|
`ed25519-randombytes.h`, to generate random scalars for the verification code.
|
||||||
The default implementation now uses OpenSSLs `RAND_bytes`.
|
The default implementation now uses OpenSSLs `RAND_bytes`.
|
||||||
|
|
||||||
Unlike the [SUPERCOP](http://bench.cr.yp.to/supercop.html) version, signatures are
|
Unlike the [SUPERCOP](http://bench.cr.yp.to/supercop.html) version, signatures are
|
||||||
not appended to messages, and there is no need for padding in front of messages.
|
not appended to messages, and there is no need for padding in front of messages.
|
||||||
Additionally, the secret key does not contain a copy of the public key, so it is
|
Additionally, the secret key does not contain a copy of the public key, so it is
|
||||||
32 bytes instead of 64 bytes, and the public key must be provided to the signing
|
32 bytes instead of 64 bytes, and the public key must be provided to the signing
|
||||||
function.
|
function.
|
||||||
|
|
||||||
##### Curve25519
|
##### Curve25519
|
||||||
|
|
||||||
Curve25519 public keys can be generated thanks to
|
Curve25519 public keys can be generated thanks to
|
||||||
[Adam Langley](http://www.imperialviolet.org/2013/05/10/fastercurve25519.html)
|
[Adam Langley](http://www.imperialviolet.org/2013/05/10/fastercurve25519.html)
|
||||||
leveraging Ed25519's precomputed basepoint scalar multiplication.
|
leveraging Ed25519's precomputed basepoint scalar multiplication.
|
||||||
|
|
||||||
curved25519_key sk, pk;
|
curved25519_key sk, pk;
|
||||||
randombytes(sk, sizeof(curved25519_key));
|
randombytes(sk, sizeof(curved25519_key));
|
||||||
curved25519_scalarmult_basepoint(pk, sk);
|
curved25519_scalarmult_basepoint(pk, sk);
|
||||||
|
|
||||||
Note the name is curved25519, a combination of curve and ed25519, to prevent
|
Note the name is curved25519, a combination of curve and ed25519, to prevent
|
||||||
name clashes. Performance is slightly faster than short message ed25519
|
name clashes. Performance is slightly faster than short message ed25519
|
||||||
signing due to both using the same code for the scalar multiply.
|
signing due to both using the same code for the scalar multiply.
|
||||||
|
|
||||||
@@ -180,4 +179,4 @@ with extreme values to ensure they function correctly. SSE2 is now supported.
|
|||||||
|
|
||||||
#### Papers
|
#### Papers
|
||||||
|
|
||||||
[Available on the Ed25519 website](http://ed25519.cr.yp.to/papers.html)
|
[Available on the Ed25519 website](http://ed25519.cr.yp.to/papers.html)
|
||||||
|
|||||||
99
external/ed25519-donna/fuzz/README.md
vendored
99
external/ed25519-donna/fuzz/README.md
vendored
@@ -1,78 +1,78 @@
|
|||||||
This code fuzzes ed25519-donna (and optionally ed25519-donna-sse2) against the ref10 implementations of
|
This code fuzzes ed25519-donna (and optionally ed25519-donna-sse2) against the ref10 implementations of
|
||||||
[curve25519](https://github.com/floodyberry/supercop/tree/master/crypto_scalarmult/curve25519/ref10) and
|
[curve25519](https://github.com/floodyberry/supercop/tree/master/crypto_scalarmult/curve25519/ref10) and
|
||||||
[ed25519](https://github.com/floodyberry/supercop/tree/master/crypto_sign/ed25519/ref10).
|
[ed25519](https://github.com/floodyberry/supercop/tree/master/crypto_sign/ed25519/ref10).
|
||||||
|
|
||||||
Curve25519 tests that generating a public key from a secret key
|
Curve25519 tests that generating a public key from a secret key
|
||||||
|
|
||||||
# Building
|
# Building
|
||||||
|
|
||||||
## *nix + PHP
|
## \*nix + PHP
|
||||||
|
|
||||||
`php build-nix.php (required parameters) (optional parameters)`
|
`php build-nix.php (required parameters) (optional parameters)`
|
||||||
|
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
|
||||||
* `--function=[curve25519,ed25519]`
|
- `--function=[curve25519,ed25519]`
|
||||||
* `--bits=[32,64]`
|
- `--bits=[32,64]`
|
||||||
|
|
||||||
Optional parameters:
|
Optional parameters:
|
||||||
|
|
||||||
* `--with-sse2`
|
- `--with-sse2`
|
||||||
|
|
||||||
Also fuzz against ed25519-donna-sse2
|
Also fuzz against ed25519-donna-sse2
|
||||||
* `--with-openssl`
|
|
||||||
|
|
||||||
Build with OpenSSL's SHA-512.
|
- `--with-openssl`
|
||||||
|
|
||||||
Default: Reference SHA-512 implementation (slow!)
|
Build with OpenSSL's SHA-512.
|
||||||
|
|
||||||
* `--compiler=[gcc,clang,icc]`
|
Default: Reference SHA-512 implementation (slow!)
|
||||||
|
|
||||||
Default: gcc
|
- `--compiler=[gcc,clang,icc]`
|
||||||
|
|
||||||
* `--no-asm`
|
Default: gcc
|
||||||
|
|
||||||
Do not use platform specific assembler
|
- `--no-asm`
|
||||||
|
|
||||||
|
Do not use platform specific assembler
|
||||||
|
|
||||||
example:
|
example:
|
||||||
|
|
||||||
php build-nix.php --bits=64 --function=ed25519 --with-sse2 --compiler=icc
|
php build-nix.php --bits=64 --function=ed25519 --with-sse2 --compiler=icc
|
||||||
|
|
||||||
## Windows
|
## Windows
|
||||||
|
|
||||||
Create a project with access to the ed25519 files.
|
Create a project with access to the ed25519 files.
|
||||||
|
|
||||||
If you are not using OpenSSL, add the `ED25519_REFHASH` define to the projects
|
If you are not using OpenSSL, add the `ED25519_REFHASH` define to the projects
|
||||||
"Properties/Preprocessor/Preprocessor Definitions" option
|
"Properties/Preprocessor/Preprocessor Definitions" option
|
||||||
|
|
||||||
Add the following files to the project:
|
Add the following files to the project:
|
||||||
|
|
||||||
* `fuzz/curve25519-ref10.c`
|
- `fuzz/curve25519-ref10.c`
|
||||||
* `fuzz/ed25519-ref10.c`
|
- `fuzz/ed25519-ref10.c`
|
||||||
* `fuzz/ed25519-donna.c`
|
- `fuzz/ed25519-donna.c`
|
||||||
* `fuzz/ed25519-donna-sse2.c` (optional)
|
- `fuzz/ed25519-donna-sse2.c` (optional)
|
||||||
* `fuzz-[curve25519/ed25519].c` (depending on which you want to fuzz)
|
- `fuzz-[curve25519/ed25519].c` (depending on which you want to fuzz)
|
||||||
|
|
||||||
If you are also fuzzing against ed25519-donna-sse2, add the `ED25519_SSE2` define for `fuzz-[curve25519/ed25519].c` under
|
If you are also fuzzing against ed25519-donna-sse2, add the `ED25519_SSE2` define for `fuzz-[curve25519/ed25519].c` under
|
||||||
its "Properties/Preprocessor/Preprocessor Definitions" option.
|
its "Properties/Preprocessor/Preprocessor Definitions" option.
|
||||||
|
|
||||||
# Running
|
# Running
|
||||||
|
|
||||||
If everything agrees, the program will only output occasional status dots (every 0x1000 passes)
|
If everything agrees, the program will only output occasional status dots (every 0x1000 passes)
|
||||||
and a 64bit progress count (every 0x20000 passes):
|
and a 64bit progress count (every 0x20000 passes):
|
||||||
|
|
||||||
fuzzing: ref10 curved25519 curved25519-sse2
|
fuzzing: ref10 curved25519 curved25519-sse2
|
||||||
|
|
||||||
................................ [0000000000020000]
|
................................ [0000000000020000]
|
||||||
................................ [0000000000040000]
|
................................ [0000000000040000]
|
||||||
................................ [0000000000060000]
|
................................ [0000000000060000]
|
||||||
................................ [0000000000080000]
|
................................ [0000000000080000]
|
||||||
................................ [00000000000a0000]
|
................................ [00000000000a0000]
|
||||||
................................ [00000000000c0000]
|
................................ [00000000000c0000]
|
||||||
|
|
||||||
If any of the implementations do not agree with the ref10 implementation, the program will dump
|
If any of the implementations do not agree with the ref10 implementation, the program will dump
|
||||||
the random data that was used, the data generated by the ref10 implementation, and diffs of the
|
the random data that was used, the data generated by the ref10 implementation, and diffs of the
|
||||||
ed25519-donna data against the ref10 data.
|
ed25519-donna data against the ref10 data.
|
||||||
|
|
||||||
## Example errors
|
## Example errors
|
||||||
@@ -83,21 +83,21 @@ These are example error dumps (with intentionally introduced errors).
|
|||||||
|
|
||||||
Random data:
|
Random data:
|
||||||
|
|
||||||
* sk, or Secret Key
|
- sk, or Secret Key
|
||||||
* m, or Message
|
- m, or Message
|
||||||
|
|
||||||
Generated data:
|
Generated data:
|
||||||
|
|
||||||
* pk, or Public Key
|
- pk, or Public Key
|
||||||
* sig, or Signature
|
- sig, or Signature
|
||||||
* valid, or if the signature of the message is valid with the public key
|
- valid, or if the signature of the message is valid with the public key
|
||||||
|
|
||||||
Dump:
|
Dump:
|
||||||
|
|
||||||
sk:
|
sk:
|
||||||
0x3b,0xb7,0x17,0x7a,0x66,0xdc,0xb7,0x9a,0x90,0x25,0x07,0x99,0x96,0xf3,0x92,0xef,
|
0x3b,0xb7,0x17,0x7a,0x66,0xdc,0xb7,0x9a,0x90,0x25,0x07,0x99,0x96,0xf3,0x92,0xef,
|
||||||
0x78,0xf8,0xad,0x6c,0x35,0x87,0x81,0x67,0x03,0xe6,0x95,0xba,0x06,0x18,0x7c,0x9c,
|
0x78,0xf8,0xad,0x6c,0x35,0x87,0x81,0x67,0x03,0xe6,0x95,0xba,0x06,0x18,0x7c,0x9c,
|
||||||
|
|
||||||
m:
|
m:
|
||||||
0x7c,0x8d,0x3d,0xe1,0x92,0xee,0x7a,0xb8,0x4d,0xc9,0xfb,0x02,0x34,0x1e,0x5a,0x91,
|
0x7c,0x8d,0x3d,0xe1,0x92,0xee,0x7a,0xb8,0x4d,0xc9,0xfb,0x02,0x34,0x1e,0x5a,0x91,
|
||||||
0xee,0x01,0xa6,0xb8,0xab,0x37,0x3f,0x3d,0x6d,0xa2,0x47,0xe3,0x27,0x93,0x7c,0xb7,
|
0xee,0x01,0xa6,0xb8,0xab,0x37,0x3f,0x3d,0x6d,0xa2,0x47,0xe3,0x27,0x93,0x7c,0xb7,
|
||||||
@@ -107,67 +107,66 @@ Dump:
|
|||||||
0x63,0x14,0xe0,0x81,0x52,0xec,0xcd,0xcf,0x70,0x54,0x7d,0xa3,0x49,0x8b,0xf0,0x89,
|
0x63,0x14,0xe0,0x81,0x52,0xec,0xcd,0xcf,0x70,0x54,0x7d,0xa3,0x49,0x8b,0xf0,0x89,
|
||||||
0x70,0x07,0x12,0x2a,0xd9,0xaa,0x16,0x01,0xb2,0x16,0x3a,0xbb,0xfc,0xfa,0x13,0x5b,
|
0x70,0x07,0x12,0x2a,0xd9,0xaa,0x16,0x01,0xb2,0x16,0x3a,0xbb,0xfc,0xfa,0x13,0x5b,
|
||||||
0x69,0x83,0x92,0x70,0x95,0x76,0xa0,0x8e,0x16,0x79,0xcc,0xaa,0xb5,0x7c,0xf8,0x7a,
|
0x69,0x83,0x92,0x70,0x95,0x76,0xa0,0x8e,0x16,0x79,0xcc,0xaa,0xb5,0x7c,0xf8,0x7a,
|
||||||
|
|
||||||
ref10:
|
ref10:
|
||||||
pk:
|
pk:
|
||||||
0x71,0xb0,0x5e,0x62,0x1b,0xe3,0xe7,0x36,0x91,0x8b,0xc0,0x13,0x36,0x0c,0xc9,0x04,
|
0x71,0xb0,0x5e,0x62,0x1b,0xe3,0xe7,0x36,0x91,0x8b,0xc0,0x13,0x36,0x0c,0xc9,0x04,
|
||||||
0x16,0xf5,0xff,0x48,0x0c,0x83,0x6b,0x88,0x53,0xa2,0xc6,0x0f,0xf7,0xac,0x42,0x04,
|
0x16,0xf5,0xff,0x48,0x0c,0x83,0x6b,0x88,0x53,0xa2,0xc6,0x0f,0xf7,0xac,0x42,0x04,
|
||||||
|
|
||||||
sig:
|
sig:
|
||||||
0x3e,0x05,0xc5,0x37,0x16,0x0b,0x29,0x30,0x89,0xa3,0xe7,0x83,0x08,0x16,0xdd,0x96,
|
0x3e,0x05,0xc5,0x37,0x16,0x0b,0x29,0x30,0x89,0xa3,0xe7,0x83,0x08,0x16,0xdd,0x96,
|
||||||
0x02,0xfa,0x0d,0x44,0x2c,0x43,0xaa,0x80,0x93,0x04,0x58,0x22,0x09,0xbf,0x11,0xa5,
|
0x02,0xfa,0x0d,0x44,0x2c,0x43,0xaa,0x80,0x93,0x04,0x58,0x22,0x09,0xbf,0x11,0xa5,
|
||||||
0xcc,0xa5,0x3c,0x9f,0xa0,0xa4,0x64,0x5a,0x4a,0xdb,0x20,0xfb,0xc7,0x9b,0xfd,0x3f,
|
0xcc,0xa5,0x3c,0x9f,0xa0,0xa4,0x64,0x5a,0x4a,0xdb,0x20,0xfb,0xc7,0x9b,0xfd,0x3f,
|
||||||
0x08,0xae,0xc4,0x3c,0x1e,0xd8,0xb6,0xb4,0xd2,0x6d,0x80,0x92,0xcb,0x71,0xf3,0x02,
|
0x08,0xae,0xc4,0x3c,0x1e,0xd8,0xb6,0xb4,0xd2,0x6d,0x80,0x92,0xcb,0x71,0xf3,0x02,
|
||||||
|
|
||||||
valid: yes
|
valid: yes
|
||||||
|
|
||||||
ed25519-donna:
|
ed25519-donna:
|
||||||
pk diff:
|
pk diff:
|
||||||
____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,
|
____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,
|
||||||
____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,
|
____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,
|
||||||
|
|
||||||
sig diff:
|
sig diff:
|
||||||
0x2c,0xb9,0x25,0x14,0xd0,0x94,0xeb,0xfe,0x46,0x02,0xc2,0xe8,0xa3,0xeb,0xbf,0xb5,
|
0x2c,0xb9,0x25,0x14,0xd0,0x94,0xeb,0xfe,0x46,0x02,0xc2,0xe8,0xa3,0xeb,0xbf,0xb5,
|
||||||
0x72,0x84,0xbf,0xc1,0x8a,0x32,0x30,0x99,0xf7,0x58,0xfe,0x06,0xa8,0xdc,0xdc,0xab,
|
0x72,0x84,0xbf,0xc1,0x8a,0x32,0x30,0x99,0xf7,0x58,0xfe,0x06,0xa8,0xdc,0xdc,0xab,
|
||||||
0xb5,0x57,0x03,0x33,0x87,0xce,0x54,0x55,0x6a,0x69,0x8a,0xc4,0xb7,0x2a,0xed,0x97,
|
0xb5,0x57,0x03,0x33,0x87,0xce,0x54,0x55,0x6a,0x69,0x8a,0xc4,0xb7,0x2a,0xed,0x97,
|
||||||
0xb4,0x68,0xe7,0x52,0x7a,0x07,0x55,0x3b,0xa2,0x94,0xd6,0x5e,0xa1,0x61,0x80,0x08,
|
0xb4,0x68,0xe7,0x52,0x7a,0x07,0x55,0x3b,0xa2,0x94,0xd6,0x5e,0xa1,0x61,0x80,0x08,
|
||||||
|
|
||||||
valid: no
|
valid: no
|
||||||
|
|
||||||
In this case, the generated public key matches, but the generated signature is completely
|
In this case, the generated public key matches, but the generated signature is completely
|
||||||
different and does not validate.
|
different and does not validate.
|
||||||
|
|
||||||
### Curve25519
|
### Curve25519
|
||||||
|
|
||||||
Random data:
|
Random data:
|
||||||
|
|
||||||
* sk, or Secret Key
|
- sk, or Secret Key
|
||||||
|
|
||||||
Generated data:
|
Generated data:
|
||||||
|
|
||||||
* pk, or Public Key
|
- pk, or Public Key
|
||||||
|
|
||||||
Dump:
|
Dump:
|
||||||
|
|
||||||
sk:
|
sk:
|
||||||
0x44,0xec,0x0b,0x0e,0xa2,0x0e,0x9c,0x5b,0x8c,0xce,0x7b,0x1d,0x68,0xae,0x0f,0x9e,
|
0x44,0xec,0x0b,0x0e,0xa2,0x0e,0x9c,0x5b,0x8c,0xce,0x7b,0x1d,0x68,0xae,0x0f,0x9e,
|
||||||
0x81,0xe2,0x04,0x76,0xda,0x87,0xa4,0x9e,0xc9,0x4f,0x3b,0xf9,0xc3,0x89,0x63,0x70,
|
0x81,0xe2,0x04,0x76,0xda,0x87,0xa4,0x9e,0xc9,0x4f,0x3b,0xf9,0xc3,0x89,0x63,0x70,
|
||||||
|
|
||||||
|
|
||||||
ref10:
|
ref10:
|
||||||
0x24,0x55,0x55,0xc0,0xf9,0x80,0xaf,0x02,0x43,0xee,0x8c,0x7f,0xc1,0xad,0x90,0x95,
|
0x24,0x55,0x55,0xc0,0xf9,0x80,0xaf,0x02,0x43,0xee,0x8c,0x7f,0xc1,0xad,0x90,0x95,
|
||||||
0x57,0x91,0x14,0x2e,0xf2,0x14,0x22,0x80,0xdd,0x4e,0x3c,0x85,0x71,0x84,0x8c,0x62,
|
0x57,0x91,0x14,0x2e,0xf2,0x14,0x22,0x80,0xdd,0x4e,0x3c,0x85,0x71,0x84,0x8c,0x62,
|
||||||
|
|
||||||
|
|
||||||
curved25519 diff:
|
curved25519 diff:
|
||||||
0x12,0xd1,0x61,0x2b,0x16,0xb3,0xd8,0x29,0xf8,0xa3,0xba,0x70,0x4e,0x49,0x4f,0x43,
|
0x12,0xd1,0x61,0x2b,0x16,0xb3,0xd8,0x29,0xf8,0xa3,0xba,0x70,0x4e,0x49,0x4f,0x43,
|
||||||
0xa1,0x3c,0x6b,0x42,0x11,0x61,0xcc,0x30,0x87,0x73,0x46,0xfb,0x85,0xc7,0x9a,0x35,
|
0xa1,0x3c,0x6b,0x42,0x11,0x61,0xcc,0x30,0x87,0x73,0x46,0xfb,0x85,0xc7,0x9a,0x35,
|
||||||
|
|
||||||
|
|
||||||
curved25519-sse2 diff:
|
curved25519-sse2 diff:
|
||||||
____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,
|
____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,
|
||||||
____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,
|
____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,____,
|
||||||
|
|
||||||
|
In this case, curved25519 is totally wrong, while curved25519-sse2 matches the reference
|
||||||
In this case, curved25519 is totally wrong, while curved25519-sse2 matches the reference
|
implementation.
|
||||||
implementation.
|
|
||||||
|
|||||||
10
external/nudb/conandata.yml
vendored
10
external/nudb/conandata.yml
vendored
@@ -1,10 +0,0 @@
|
|||||||
sources:
|
|
||||||
"2.0.8":
|
|
||||||
url: "https://github.com/CPPAlliance/NuDB/archive/2.0.8.tar.gz"
|
|
||||||
sha256: "9b71903d8ba111cd893ab064b9a8b6ac4124ed8bd6b4f67250205bc43c7f13a8"
|
|
||||||
patches:
|
|
||||||
"2.0.8":
|
|
||||||
- patch_file: "patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch"
|
|
||||||
patch_description: "Fix build for MSVC by including stdexcept"
|
|
||||||
patch_type: "portability"
|
|
||||||
patch_source: "https://github.com/cppalliance/NuDB/pull/100/files"
|
|
||||||
72
external/nudb/conanfile.py
vendored
72
external/nudb/conanfile.py
vendored
@@ -1,72 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from conan import ConanFile
|
|
||||||
from conan.tools.build import check_min_cppstd
|
|
||||||
from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get
|
|
||||||
from conan.tools.layout import basic_layout
|
|
||||||
|
|
||||||
required_conan_version = ">=1.52.0"
|
|
||||||
|
|
||||||
|
|
||||||
class NudbConan(ConanFile):
|
|
||||||
name = "nudb"
|
|
||||||
description = "A fast key/value insert-only database for SSD drives in C++11"
|
|
||||||
license = "BSL-1.0"
|
|
||||||
url = "https://github.com/conan-io/conan-center-index"
|
|
||||||
homepage = "https://github.com/CPPAlliance/NuDB"
|
|
||||||
topics = ("header-only", "KVS", "insert-only")
|
|
||||||
|
|
||||||
package_type = "header-library"
|
|
||||||
settings = "os", "arch", "compiler", "build_type"
|
|
||||||
no_copy_source = True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _min_cppstd(self):
|
|
||||||
return 11
|
|
||||||
|
|
||||||
def export_sources(self):
|
|
||||||
export_conandata_patches(self)
|
|
||||||
|
|
||||||
def layout(self):
|
|
||||||
basic_layout(self, src_folder="src")
|
|
||||||
|
|
||||||
def requirements(self):
|
|
||||||
self.requires("boost/1.83.0")
|
|
||||||
|
|
||||||
def package_id(self):
|
|
||||||
self.info.clear()
|
|
||||||
|
|
||||||
def validate(self):
|
|
||||||
if self.settings.compiler.cppstd:
|
|
||||||
check_min_cppstd(self, self._min_cppstd)
|
|
||||||
|
|
||||||
def source(self):
|
|
||||||
get(self, **self.conan_data["sources"][self.version], strip_root=True)
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
apply_conandata_patches(self)
|
|
||||||
|
|
||||||
def package(self):
|
|
||||||
copy(self, "LICENSE*",
|
|
||||||
dst=os.path.join(self.package_folder, "licenses"),
|
|
||||||
src=self.source_folder)
|
|
||||||
copy(self, "*",
|
|
||||||
dst=os.path.join(self.package_folder, "include"),
|
|
||||||
src=os.path.join(self.source_folder, "include"))
|
|
||||||
|
|
||||||
def package_info(self):
|
|
||||||
self.cpp_info.bindirs = []
|
|
||||||
self.cpp_info.libdirs = []
|
|
||||||
|
|
||||||
self.cpp_info.set_property("cmake_target_name", "NuDB")
|
|
||||||
self.cpp_info.set_property("cmake_target_aliases", ["NuDB::nudb"])
|
|
||||||
self.cpp_info.set_property("cmake_find_mode", "both")
|
|
||||||
|
|
||||||
self.cpp_info.components["core"].set_property("cmake_target_name", "nudb")
|
|
||||||
self.cpp_info.components["core"].names["cmake_find_package"] = "nudb"
|
|
||||||
self.cpp_info.components["core"].names["cmake_find_package_multi"] = "nudb"
|
|
||||||
self.cpp_info.components["core"].requires = ["boost::thread", "boost::system"]
|
|
||||||
|
|
||||||
# TODO: to remove in conan v2 once cmake_find_package_* generators removed
|
|
||||||
self.cpp_info.names["cmake_find_package"] = "NuDB"
|
|
||||||
self.cpp_info.names["cmake_find_package_multi"] = "NuDB"
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
diff --git a/include/nudb/detail/stream.hpp b/include/nudb/detail/stream.hpp
|
|
||||||
index 6c07bf1..e0ce8ed 100644
|
|
||||||
--- a/include/nudb/detail/stream.hpp
|
|
||||||
+++ b/include/nudb/detail/stream.hpp
|
|
||||||
@@ -14,6 +14,7 @@
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
|
||||||
+#include <stdexcept>
|
|
||||||
|
|
||||||
namespace nudb {
|
|
||||||
namespace detail {
|
|
||||||
diff --git a/include/nudb/impl/context.ipp b/include/nudb/impl/context.ipp
|
|
||||||
index beb7058..ffde0b3 100644
|
|
||||||
--- a/include/nudb/impl/context.ipp
|
|
||||||
+++ b/include/nudb/impl/context.ipp
|
|
||||||
@@ -9,6 +9,7 @@
|
|
||||||
#define NUDB_IMPL_CONTEXT_IPP
|
|
||||||
|
|
||||||
#include <nudb/detail/store_base.hpp>
|
|
||||||
+#include <stdexcept>
|
|
||||||
|
|
||||||
namespace nudb {
|
|
||||||
|
|
||||||
27
external/rocksdb/conandata.yml
vendored
27
external/rocksdb/conandata.yml
vendored
@@ -1,27 +0,0 @@
|
|||||||
sources:
|
|
||||||
"6.29.5":
|
|
||||||
url: "https://github.com/facebook/rocksdb/archive/refs/tags/v6.29.5.tar.gz"
|
|
||||||
sha256: "ddbf84791f0980c0bbce3902feb93a2c7006f6f53bfd798926143e31d4d756f0"
|
|
||||||
"6.27.3":
|
|
||||||
url: "https://github.com/facebook/rocksdb/archive/refs/tags/v6.27.3.tar.gz"
|
|
||||||
sha256: "ee29901749b9132692b26f0a6c1d693f47d1a9ed8e3771e60556afe80282bf58"
|
|
||||||
"6.20.3":
|
|
||||||
url: "https://github.com/facebook/rocksdb/archive/refs/tags/v6.20.3.tar.gz"
|
|
||||||
sha256: "c6502c7aae641b7e20fafa6c2b92273d935d2b7b2707135ebd9a67b092169dca"
|
|
||||||
"8.8.1":
|
|
||||||
url: "https://github.com/facebook/rocksdb/archive/refs/tags/v8.8.1.tar.gz"
|
|
||||||
sha256: "056c7e21ad8ae36b026ac3b94b9d6e0fcc60e1d937fc80330921e4181be5c36e"
|
|
||||||
patches:
|
|
||||||
"6.29.5":
|
|
||||||
- patch_file: "patches/6.29.5-0001-add-include-cstdint-for-gcc-13.patch"
|
|
||||||
patch_description: "Fix build with gcc 13 by including cstdint"
|
|
||||||
patch_type: "portability"
|
|
||||||
patch_source: "https://github.com/facebook/rocksdb/pull/11118"
|
|
||||||
- patch_file: "patches/6.29.5-0002-exclude-thirdparty.patch"
|
|
||||||
patch_description: "Do not include thirdparty.inc"
|
|
||||||
patch_type: "portability"
|
|
||||||
"6.27.3":
|
|
||||||
- patch_file: "patches/6.27.3-0001-add-include-cstdint-for-gcc-13.patch"
|
|
||||||
patch_description: "Fix build with gcc 13 by including cstdint"
|
|
||||||
patch_type: "portability"
|
|
||||||
patch_source: "https://github.com/facebook/rocksdb/pull/11118"
|
|
||||||
233
external/rocksdb/conanfile.py
vendored
233
external/rocksdb/conanfile.py
vendored
@@ -1,233 +0,0 @@
|
|||||||
import os
|
|
||||||
import glob
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
from conan import ConanFile
|
|
||||||
from conan.errors import ConanInvalidConfiguration
|
|
||||||
from conan.tools.build import check_min_cppstd
|
|
||||||
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
|
|
||||||
from conan.tools.files import apply_conandata_patches, collect_libs, copy, export_conandata_patches, get, rm, rmdir
|
|
||||||
from conan.tools.microsoft import check_min_vs, is_msvc, is_msvc_static_runtime
|
|
||||||
from conan.tools.scm import Version
|
|
||||||
|
|
||||||
required_conan_version = ">=1.53.0"
|
|
||||||
|
|
||||||
|
|
||||||
class RocksDBConan(ConanFile):
|
|
||||||
name = "rocksdb"
|
|
||||||
homepage = "https://github.com/facebook/rocksdb"
|
|
||||||
license = ("GPL-2.0-only", "Apache-2.0")
|
|
||||||
url = "https://github.com/conan-io/conan-center-index"
|
|
||||||
description = "A library that provides an embeddable, persistent key-value store for fast storage"
|
|
||||||
topics = ("database", "leveldb", "facebook", "key-value")
|
|
||||||
package_type = "library"
|
|
||||||
settings = "os", "arch", "compiler", "build_type"
|
|
||||||
options = {
|
|
||||||
"shared": [True, False],
|
|
||||||
"fPIC": [True, False],
|
|
||||||
"lite": [True, False],
|
|
||||||
"with_gflags": [True, False],
|
|
||||||
"with_snappy": [True, False],
|
|
||||||
"with_lz4": [True, False],
|
|
||||||
"with_zlib": [True, False],
|
|
||||||
"with_zstd": [True, False],
|
|
||||||
"with_tbb": [True, False],
|
|
||||||
"with_jemalloc": [True, False],
|
|
||||||
"enable_sse": [False, "sse42", "avx2"],
|
|
||||||
"use_rtti": [True, False],
|
|
||||||
}
|
|
||||||
default_options = {
|
|
||||||
"shared": False,
|
|
||||||
"fPIC": True,
|
|
||||||
"lite": False,
|
|
||||||
"with_snappy": False,
|
|
||||||
"with_lz4": False,
|
|
||||||
"with_zlib": False,
|
|
||||||
"with_zstd": False,
|
|
||||||
"with_gflags": False,
|
|
||||||
"with_tbb": False,
|
|
||||||
"with_jemalloc": False,
|
|
||||||
"enable_sse": False,
|
|
||||||
"use_rtti": False,
|
|
||||||
}
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _min_cppstd(self):
|
|
||||||
return "11" if Version(self.version) < "8.8.1" else "17"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def _compilers_minimum_version(self):
|
|
||||||
return {} if self._min_cppstd == "11" else {
|
|
||||||
"apple-clang": "10",
|
|
||||||
"clang": "7",
|
|
||||||
"gcc": "7",
|
|
||||||
"msvc": "191",
|
|
||||||
"Visual Studio": "15",
|
|
||||||
}
|
|
||||||
|
|
||||||
def export_sources(self):
|
|
||||||
export_conandata_patches(self)
|
|
||||||
|
|
||||||
def config_options(self):
|
|
||||||
if self.settings.os == "Windows":
|
|
||||||
del self.options.fPIC
|
|
||||||
if self.settings.arch != "x86_64":
|
|
||||||
del self.options.with_tbb
|
|
||||||
if self.settings.build_type == "Debug":
|
|
||||||
self.options.use_rtti = True # Rtti are used in asserts for debug mode...
|
|
||||||
|
|
||||||
def configure(self):
|
|
||||||
if self.options.shared:
|
|
||||||
self.options.rm_safe("fPIC")
|
|
||||||
|
|
||||||
def layout(self):
|
|
||||||
cmake_layout(self, src_folder="src")
|
|
||||||
|
|
||||||
def requirements(self):
|
|
||||||
if self.options.with_gflags:
|
|
||||||
self.requires("gflags/2.2.2")
|
|
||||||
if self.options.with_snappy:
|
|
||||||
self.requires("snappy/1.1.10")
|
|
||||||
if self.options.with_lz4:
|
|
||||||
self.requires("lz4/1.10.0")
|
|
||||||
if self.options.with_zlib:
|
|
||||||
self.requires("zlib/[>=1.2.11 <2]")
|
|
||||||
if self.options.with_zstd:
|
|
||||||
self.requires("zstd/1.5.6")
|
|
||||||
if self.options.get_safe("with_tbb"):
|
|
||||||
self.requires("onetbb/2021.12.0")
|
|
||||||
if self.options.with_jemalloc:
|
|
||||||
self.requires("jemalloc/5.3.0")
|
|
||||||
|
|
||||||
def validate(self):
|
|
||||||
if self.settings.compiler.get_safe("cppstd"):
|
|
||||||
check_min_cppstd(self, self._min_cppstd)
|
|
||||||
|
|
||||||
minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False)
|
|
||||||
if minimum_version and Version(self.settings.compiler.version) < minimum_version:
|
|
||||||
raise ConanInvalidConfiguration(
|
|
||||||
f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support."
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.settings.arch not in ["x86_64", "ppc64le", "ppc64", "mips64", "armv8"]:
|
|
||||||
raise ConanInvalidConfiguration("Rocksdb requires 64 bits")
|
|
||||||
|
|
||||||
check_min_vs(self, "191")
|
|
||||||
|
|
||||||
if self.version == "6.20.3" and \
|
|
||||||
self.settings.os == "Linux" and \
|
|
||||||
self.settings.compiler == "gcc" and \
|
|
||||||
Version(self.settings.compiler.version) < "5":
|
|
||||||
raise ConanInvalidConfiguration("Rocksdb 6.20.3 is not compilable with gcc <5.") # See https://github.com/facebook/rocksdb/issues/3522
|
|
||||||
|
|
||||||
def source(self):
|
|
||||||
get(self, **self.conan_data["sources"][self.version], strip_root=True)
|
|
||||||
|
|
||||||
def generate(self):
|
|
||||||
tc = CMakeToolchain(self)
|
|
||||||
tc.variables["FAIL_ON_WARNINGS"] = False
|
|
||||||
tc.variables["WITH_TESTS"] = False
|
|
||||||
tc.variables["WITH_TOOLS"] = False
|
|
||||||
tc.variables["WITH_CORE_TOOLS"] = False
|
|
||||||
tc.variables["WITH_BENCHMARK_TOOLS"] = False
|
|
||||||
tc.variables["WITH_FOLLY_DISTRIBUTED_MUTEX"] = False
|
|
||||||
if is_msvc(self):
|
|
||||||
tc.variables["WITH_MD_LIBRARY"] = not is_msvc_static_runtime(self)
|
|
||||||
tc.variables["ROCKSDB_INSTALL_ON_WINDOWS"] = self.settings.os == "Windows"
|
|
||||||
tc.variables["ROCKSDB_LITE"] = self.options.lite
|
|
||||||
tc.variables["WITH_GFLAGS"] = self.options.with_gflags
|
|
||||||
tc.variables["WITH_SNAPPY"] = self.options.with_snappy
|
|
||||||
tc.variables["WITH_LZ4"] = self.options.with_lz4
|
|
||||||
tc.variables["WITH_ZLIB"] = self.options.with_zlib
|
|
||||||
tc.variables["WITH_ZSTD"] = self.options.with_zstd
|
|
||||||
tc.variables["WITH_TBB"] = self.options.get_safe("with_tbb", False)
|
|
||||||
tc.variables["WITH_JEMALLOC"] = self.options.with_jemalloc
|
|
||||||
tc.variables["ROCKSDB_BUILD_SHARED"] = self.options.shared
|
|
||||||
tc.variables["ROCKSDB_LIBRARY_EXPORTS"] = self.settings.os == "Windows" and self.options.shared
|
|
||||||
tc.variables["ROCKSDB_DLL" ] = self.settings.os == "Windows" and self.options.shared
|
|
||||||
tc.variables["USE_RTTI"] = self.options.use_rtti
|
|
||||||
if not bool(self.options.enable_sse):
|
|
||||||
tc.variables["PORTABLE"] = True
|
|
||||||
tc.variables["FORCE_SSE42"] = False
|
|
||||||
elif self.options.enable_sse == "sse42":
|
|
||||||
tc.variables["PORTABLE"] = True
|
|
||||||
tc.variables["FORCE_SSE42"] = True
|
|
||||||
elif self.options.enable_sse == "avx2":
|
|
||||||
tc.variables["PORTABLE"] = False
|
|
||||||
tc.variables["FORCE_SSE42"] = False
|
|
||||||
# not available yet in CCI
|
|
||||||
tc.variables["WITH_NUMA"] = False
|
|
||||||
tc.generate()
|
|
||||||
|
|
||||||
deps = CMakeDeps(self)
|
|
||||||
if self.options.with_jemalloc:
|
|
||||||
deps.set_property("jemalloc", "cmake_file_name", "JeMalloc")
|
|
||||||
deps.set_property("jemalloc", "cmake_target_name", "JeMalloc::JeMalloc")
|
|
||||||
deps.generate()
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
apply_conandata_patches(self)
|
|
||||||
cmake = CMake(self)
|
|
||||||
cmake.configure()
|
|
||||||
cmake.build()
|
|
||||||
|
|
||||||
def _remove_static_libraries(self):
|
|
||||||
rm(self, "rocksdb.lib", os.path.join(self.package_folder, "lib"))
|
|
||||||
for lib in glob.glob(os.path.join(self.package_folder, "lib", "*.a")):
|
|
||||||
if not lib.endswith(".dll.a"):
|
|
||||||
os.remove(lib)
|
|
||||||
|
|
||||||
def _remove_cpp_headers(self):
|
|
||||||
for path in glob.glob(os.path.join(self.package_folder, "include", "rocksdb", "*")):
|
|
||||||
if path != os.path.join(self.package_folder, "include", "rocksdb", "c.h"):
|
|
||||||
if os.path.isfile(path):
|
|
||||||
os.remove(path)
|
|
||||||
else:
|
|
||||||
shutil.rmtree(path)
|
|
||||||
|
|
||||||
def package(self):
|
|
||||||
copy(self, "COPYING", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
|
|
||||||
copy(self, "LICENSE*", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
|
|
||||||
cmake = CMake(self)
|
|
||||||
cmake.install()
|
|
||||||
if self.options.shared:
|
|
||||||
self._remove_static_libraries()
|
|
||||||
self._remove_cpp_headers() # Force stable ABI for shared libraries
|
|
||||||
rmdir(self, os.path.join(self.package_folder, "lib", "cmake"))
|
|
||||||
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
|
|
||||||
|
|
||||||
def package_info(self):
|
|
||||||
cmake_target = "rocksdb-shared" if self.options.shared else "rocksdb"
|
|
||||||
self.cpp_info.set_property("cmake_file_name", "RocksDB")
|
|
||||||
self.cpp_info.set_property("cmake_target_name", f"RocksDB::{cmake_target}")
|
|
||||||
# TODO: back to global scope in conan v2 once cmake_find_package* generators removed
|
|
||||||
self.cpp_info.components["librocksdb"].libs = collect_libs(self)
|
|
||||||
if self.settings.os == "Windows":
|
|
||||||
self.cpp_info.components["librocksdb"].system_libs = ["shlwapi", "rpcrt4"]
|
|
||||||
if self.options.shared:
|
|
||||||
self.cpp_info.components["librocksdb"].defines = ["ROCKSDB_DLL"]
|
|
||||||
elif self.settings.os in ["Linux", "FreeBSD"]:
|
|
||||||
self.cpp_info.components["librocksdb"].system_libs = ["pthread", "m"]
|
|
||||||
if self.options.lite:
|
|
||||||
self.cpp_info.components["librocksdb"].defines.append("ROCKSDB_LITE")
|
|
||||||
|
|
||||||
# TODO: to remove in conan v2 once cmake_find_package* generators removed
|
|
||||||
self.cpp_info.names["cmake_find_package"] = "RocksDB"
|
|
||||||
self.cpp_info.names["cmake_find_package_multi"] = "RocksDB"
|
|
||||||
self.cpp_info.components["librocksdb"].names["cmake_find_package"] = cmake_target
|
|
||||||
self.cpp_info.components["librocksdb"].names["cmake_find_package_multi"] = cmake_target
|
|
||||||
self.cpp_info.components["librocksdb"].set_property("cmake_target_name", f"RocksDB::{cmake_target}")
|
|
||||||
if self.options.with_gflags:
|
|
||||||
self.cpp_info.components["librocksdb"].requires.append("gflags::gflags")
|
|
||||||
if self.options.with_snappy:
|
|
||||||
self.cpp_info.components["librocksdb"].requires.append("snappy::snappy")
|
|
||||||
if self.options.with_lz4:
|
|
||||||
self.cpp_info.components["librocksdb"].requires.append("lz4::lz4")
|
|
||||||
if self.options.with_zlib:
|
|
||||||
self.cpp_info.components["librocksdb"].requires.append("zlib::zlib")
|
|
||||||
if self.options.with_zstd:
|
|
||||||
self.cpp_info.components["librocksdb"].requires.append("zstd::zstd")
|
|
||||||
if self.options.get_safe("with_tbb"):
|
|
||||||
self.cpp_info.components["librocksdb"].requires.append("onetbb::onetbb")
|
|
||||||
if self.options.with_jemalloc:
|
|
||||||
self.cpp_info.components["librocksdb"].requires.append("jemalloc::jemalloc")
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
--- a/include/rocksdb/utilities/checkpoint.h
|
|
||||||
+++ b/include/rocksdb/utilities/checkpoint.h
|
|
||||||
@@ -8,6 +8,7 @@
|
|
||||||
#pragma once
|
|
||||||
#ifndef ROCKSDB_LITE
|
|
||||||
|
|
||||||
+#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include "rocksdb/status.h"
|
|
||||||
--- a/table/block_based/data_block_hash_index.h
|
|
||||||
+++ b/table/block_based/data_block_hash_index.h
|
|
||||||
@@ -5,6 +5,7 @@
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
+#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
--- a/util/string_util.h
|
|
||||||
+++ b/util/string_util.h
|
|
||||||
@@ -6,6 +6,7 @@
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
+#include <cstdint>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
|
||||||
index ec59d4491..35577c998 100644
|
|
||||||
--- a/CMakeLists.txt
|
|
||||||
+++ b/CMakeLists.txt
|
|
||||||
@@ -101 +100,0 @@ if(MSVC)
|
|
||||||
- option(WITH_GFLAGS "build with GFlags" OFF)
|
|
||||||
@@ -103,2 +102,2 @@ if(MSVC)
|
|
||||||
- include(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty.inc)
|
|
||||||
-else()
|
|
||||||
+endif()
|
|
||||||
+
|
|
||||||
@@ -117 +116 @@ else()
|
|
||||||
- if(MINGW)
|
|
||||||
+ if(MINGW OR MSVC)
|
|
||||||
@@ -183 +181,0 @@ else()
|
|
||||||
-endif()
|
|
||||||
144
external/secp256k1/CHANGELOG.md
vendored
144
external/secp256k1/CHANGELOG.md
vendored
@@ -8,153 +8,189 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
## [0.6.0] - 2024-11-04
|
## [0.6.0] - 2024-11-04
|
||||||
|
|
||||||
#### Added
|
#### Added
|
||||||
- New module `musig` implements the MuSig2 multisignature scheme according to the [BIP 327 specification](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). See:
|
|
||||||
- Header file `include/secp256k1_musig.h` which defines the new API.
|
- New module `musig` implements the MuSig2 multisignature scheme according to the [BIP 327 specification](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). See:
|
||||||
- Document `doc/musig.md` for further notes on API usage.
|
- Header file `include/secp256k1_musig.h` which defines the new API.
|
||||||
- Usage example `examples/musig.c`.
|
- Document `doc/musig.md` for further notes on API usage.
|
||||||
- New CMake variable `SECP256K1_APPEND_LDFLAGS` for appending linker flags to the build command.
|
- Usage example `examples/musig.c`.
|
||||||
|
- New CMake variable `SECP256K1_APPEND_LDFLAGS` for appending linker flags to the build command.
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
- API functions now use a significantly more robust method to clear secrets from the stack before returning. However, secret clearing remains a best-effort security measure and cannot guarantee complete removal.
|
|
||||||
- Any type `secp256k1_foo` can now be forward-declared using `typedef struct secp256k1_foo secp256k1_foo;` (or also `struct secp256k1_foo;` in C++).
|
- API functions now use a significantly more robust method to clear secrets from the stack before returning. However, secret clearing remains a best-effort security measure and cannot guarantee complete removal.
|
||||||
- Organized CMake build artifacts into dedicated directories (`bin/` for executables, `lib/` for libraries) to improve build output structure and Windows shared library compatibility.
|
- Any type `secp256k1_foo` can now be forward-declared using `typedef struct secp256k1_foo secp256k1_foo;` (or also `struct secp256k1_foo;` in C++).
|
||||||
|
- Organized CMake build artifacts into dedicated directories (`bin/` for executables, `lib/` for libraries) to improve build output structure and Windows shared library compatibility.
|
||||||
|
|
||||||
#### Removed
|
#### Removed
|
||||||
- Removed the `secp256k1_scratch_space` struct and its associated functions `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` because the scratch space was unused in the API.
|
|
||||||
|
- Removed the `secp256k1_scratch_space` struct and its associated functions `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` because the scratch space was unused in the API.
|
||||||
|
|
||||||
#### ABI Compatibility
|
#### ABI Compatibility
|
||||||
|
|
||||||
The symbols `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` were removed.
|
The symbols `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` were removed.
|
||||||
Otherwise, the library maintains backward compatibility with versions 0.3.x through 0.5.x.
|
Otherwise, the library maintains backward compatibility with versions 0.3.x through 0.5.x.
|
||||||
|
|
||||||
## [0.5.1] - 2024-08-01
|
## [0.5.1] - 2024-08-01
|
||||||
|
|
||||||
#### Added
|
#### Added
|
||||||
- Added usage example for an ElligatorSwift key exchange.
|
|
||||||
|
- Added usage example for an ElligatorSwift key exchange.
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
- The default size of the precomputed table for signing was changed from 22 KiB to 86 KiB. The size can be changed with the configure option `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake).
|
|
||||||
- "auto" is no longer an accepted value for the `--with-ecmult-window` and `--with-ecmult-gen-kb` configure options (this also applies to `SECP256K1_ECMULT_WINDOW_SIZE` and `SECP256K1_ECMULT_GEN_KB` in CMake). To achieve the same configuration as previously provided by the "auto" value, omit setting the configure option explicitly.
|
- The default size of the precomputed table for signing was changed from 22 KiB to 86 KiB. The size can be changed with the configure option `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake).
|
||||||
|
- "auto" is no longer an accepted value for the `--with-ecmult-window` and `--with-ecmult-gen-kb` configure options (this also applies to `SECP256K1_ECMULT_WINDOW_SIZE` and `SECP256K1_ECMULT_GEN_KB` in CMake). To achieve the same configuration as previously provided by the "auto" value, omit setting the configure option explicitly.
|
||||||
|
|
||||||
#### Fixed
|
#### Fixed
|
||||||
- Fixed compilation when the extrakeys module is disabled.
|
|
||||||
|
- Fixed compilation when the extrakeys module is disabled.
|
||||||
|
|
||||||
#### ABI Compatibility
|
#### ABI Compatibility
|
||||||
|
|
||||||
The ABI is backward compatible with versions 0.5.0, 0.4.x and 0.3.x.
|
The ABI is backward compatible with versions 0.5.0, 0.4.x and 0.3.x.
|
||||||
|
|
||||||
## [0.5.0] - 2024-05-06
|
## [0.5.0] - 2024-05-06
|
||||||
|
|
||||||
#### Added
|
#### Added
|
||||||
- New function `secp256k1_ec_pubkey_sort` that sorts public keys using lexicographic (of compressed serialization) order.
|
|
||||||
|
- New function `secp256k1_ec_pubkey_sort` that sorts public keys using lexicographic (of compressed serialization) order.
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
- The implementation of the point multiplication algorithm used for signing and public key generation was changed, resulting in improved performance for those operations.
|
|
||||||
- The related configure option `--ecmult-gen-precision` was replaced with `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake).
|
- The implementation of the point multiplication algorithm used for signing and public key generation was changed, resulting in improved performance for those operations.
|
||||||
- This changes the supported precomputed table sizes for these operations. The new supported sizes are 2 KiB, 22 KiB, or 86 KiB (while the old supported sizes were 32 KiB, 64 KiB, or 512 KiB).
|
- The related configure option `--ecmult-gen-precision` was replaced with `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake).
|
||||||
|
- This changes the supported precomputed table sizes for these operations. The new supported sizes are 2 KiB, 22 KiB, or 86 KiB (while the old supported sizes were 32 KiB, 64 KiB, or 512 KiB).
|
||||||
|
|
||||||
#### ABI Compatibility
|
#### ABI Compatibility
|
||||||
|
|
||||||
The ABI is backward compatible with versions 0.4.x and 0.3.x.
|
The ABI is backward compatible with versions 0.4.x and 0.3.x.
|
||||||
|
|
||||||
## [0.4.1] - 2023-12-21
|
## [0.4.1] - 2023-12-21
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
- The point multiplication algorithm used for ECDH operations (module `ecdh`) was replaced with a slightly faster one.
|
|
||||||
- Optional handwritten x86_64 assembly for field operations was removed because modern C compilers are able to output more efficient assembly. This change results in a significant speedup of some library functions when handwritten x86_64 assembly is enabled (`--with-asm=x86_64` in GNU Autotools, `-DSECP256K1_ASM=x86_64` in CMake), which is the default on x86_64. Benchmarks with GCC 10.5.0 show a 10% speedup for `secp256k1_ecdsa_verify` and `secp256k1_schnorrsig_verify`.
|
- The point multiplication algorithm used for ECDH operations (module `ecdh`) was replaced with a slightly faster one.
|
||||||
|
- Optional handwritten x86_64 assembly for field operations was removed because modern C compilers are able to output more efficient assembly. This change results in a significant speedup of some library functions when handwritten x86_64 assembly is enabled (`--with-asm=x86_64` in GNU Autotools, `-DSECP256K1_ASM=x86_64` in CMake), which is the default on x86_64. Benchmarks with GCC 10.5.0 show a 10% speedup for `secp256k1_ecdsa_verify` and `secp256k1_schnorrsig_verify`.
|
||||||
|
|
||||||
#### ABI Compatibility
|
#### ABI Compatibility
|
||||||
|
|
||||||
The ABI is backward compatible with versions 0.4.0 and 0.3.x.
|
The ABI is backward compatible with versions 0.4.0 and 0.3.x.
|
||||||
|
|
||||||
## [0.4.0] - 2023-09-04
|
## [0.4.0] - 2023-09-04
|
||||||
|
|
||||||
#### Added
|
#### Added
|
||||||
- New module `ellswift` implements ElligatorSwift encoding for public keys and x-only Diffie-Hellman key exchange for them.
|
|
||||||
ElligatorSwift permits representing secp256k1 public keys as 64-byte arrays which cannot be distinguished from uniformly random. See:
|
- New module `ellswift` implements ElligatorSwift encoding for public keys and x-only Diffie-Hellman key exchange for them.
|
||||||
- Header file `include/secp256k1_ellswift.h` which defines the new API.
|
ElligatorSwift permits representing secp256k1 public keys as 64-byte arrays which cannot be distinguished from uniformly random. See:
|
||||||
- Document `doc/ellswift.md` which explains the mathematical background of the scheme.
|
- Header file `include/secp256k1_ellswift.h` which defines the new API.
|
||||||
- The [paper](https://eprint.iacr.org/2022/759) on which the scheme is based.
|
- Document `doc/ellswift.md` which explains the mathematical background of the scheme.
|
||||||
- We now test the library with unreleased development snapshots of GCC and Clang. This gives us an early chance to catch miscompilations and constant-time issues introduced by the compiler (such as those that led to the previous two releases).
|
- The [paper](https://eprint.iacr.org/2022/759) on which the scheme is based.
|
||||||
|
- We now test the library with unreleased development snapshots of GCC and Clang. This gives us an early chance to catch miscompilations and constant-time issues introduced by the compiler (such as those that led to the previous two releases).
|
||||||
|
|
||||||
#### Fixed
|
#### Fixed
|
||||||
- Fixed symbol visibility in Windows DLL builds, where three internal library symbols were wrongly exported.
|
|
||||||
|
- Fixed symbol visibility in Windows DLL builds, where three internal library symbols were wrongly exported.
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
- When consuming libsecp256k1 as a static library on Windows, the user must now define the `SECP256K1_STATIC` macro before including `secp256k1.h`.
|
|
||||||
|
- When consuming libsecp256k1 as a static library on Windows, the user must now define the `SECP256K1_STATIC` macro before including `secp256k1.h`.
|
||||||
|
|
||||||
#### ABI Compatibility
|
#### ABI Compatibility
|
||||||
|
|
||||||
This release is backward compatible with the ABI of 0.3.0, 0.3.1, and 0.3.2. Symbol visibility is now believed to be handled properly on supported platforms and is now considered to be part of the ABI. Please report any improperly exported symbols as a bug.
|
This release is backward compatible with the ABI of 0.3.0, 0.3.1, and 0.3.2. Symbol visibility is now believed to be handled properly on supported platforms and is now considered to be part of the ABI. Please report any improperly exported symbols as a bug.
|
||||||
|
|
||||||
## [0.3.2] - 2023-05-13
|
## [0.3.2] - 2023-05-13
|
||||||
|
|
||||||
We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`.
|
We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`.
|
||||||
|
|
||||||
#### Security
|
#### Security
|
||||||
- Module `ecdh`: Fix "constant-timeness" issue with GCC 13.1 (and potentially future versions of GCC) that could leave applications using libsecp256k1's ECDH module vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow during ECDH computations when libsecp256k1 is compiled with GCC 13.1.
|
|
||||||
|
- Module `ecdh`: Fix "constant-timeness" issue with GCC 13.1 (and potentially future versions of GCC) that could leave applications using libsecp256k1's ECDH module vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow during ECDH computations when libsecp256k1 is compiled with GCC 13.1.
|
||||||
|
|
||||||
#### Fixed
|
#### Fixed
|
||||||
- Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far.
|
|
||||||
|
- Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far.
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
- Various improvements and changes to CMake builds. CMake builds remain experimental.
|
|
||||||
- Made API versioning consistent with GNU Autotools builds.
|
- Various improvements and changes to CMake builds. CMake builds remain experimental.
|
||||||
- Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library.
|
- Made API versioning consistent with GNU Autotools builds.
|
||||||
- Added `SECP256K1_INSTALL` variable for the controlling whether to install the build artefacts.
|
- Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library.
|
||||||
- Renamed asm build option `arm` to `arm32`. Use `--with-asm=arm32` instead of `--with-asm=arm` (GNU Autotools), and `-DSECP256K1_ASM=arm32` instead of `-DSECP256K1_ASM=arm` (CMake).
|
- Added `SECP256K1_INSTALL` variable for the controlling whether to install the build artefacts.
|
||||||
|
- Renamed asm build option `arm` to `arm32`. Use `--with-asm=arm32` instead of `--with-asm=arm` (GNU Autotools), and `-DSECP256K1_ASM=arm32` instead of `-DSECP256K1_ASM=arm` (CMake).
|
||||||
|
|
||||||
#### ABI Compatibility
|
#### ABI Compatibility
|
||||||
|
|
||||||
The ABI is compatible with versions 0.3.0 and 0.3.1.
|
The ABI is compatible with versions 0.3.0 and 0.3.1.
|
||||||
|
|
||||||
## [0.3.1] - 2023-04-10
|
## [0.3.1] - 2023-04-10
|
||||||
|
|
||||||
We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`.
|
We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`.
|
||||||
|
|
||||||
#### Security
|
#### Security
|
||||||
- Fix "constant-timeness" issue with Clang >=14 that could leave applications using libsecp256k1 vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow and secret-dependent memory accesses in conditional moves of memory objects when libsecp256k1 is compiled with Clang >=14.
|
|
||||||
|
- Fix "constant-timeness" issue with Clang >=14 that could leave applications using libsecp256k1 vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow and secret-dependent memory accesses in conditional moves of memory objects when libsecp256k1 is compiled with Clang >=14.
|
||||||
|
|
||||||
#### Added
|
#### Added
|
||||||
- Added tests against [Project Wycheproof's](https://github.com/google/wycheproof/) set of ECDSA test vectors (Bitcoin "low-S" variant), a fixed set of test cases designed to trigger various edge cases.
|
|
||||||
|
- Added tests against [Project Wycheproof's](https://github.com/google/wycheproof/) set of ECDSA test vectors (Bitcoin "low-S" variant), a fixed set of test cases designed to trigger various edge cases.
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
- Increased minimum required CMake version to 3.13. CMake builds remain experimental.
|
|
||||||
|
- Increased minimum required CMake version to 3.13. CMake builds remain experimental.
|
||||||
|
|
||||||
#### ABI Compatibility
|
#### ABI Compatibility
|
||||||
|
|
||||||
The ABI is compatible with version 0.3.0.
|
The ABI is compatible with version 0.3.0.
|
||||||
|
|
||||||
## [0.3.0] - 2023-03-08
|
## [0.3.0] - 2023-03-08
|
||||||
|
|
||||||
#### Added
|
#### Added
|
||||||
- Added experimental support for CMake builds. Traditional GNU Autotools builds (`./configure` and `make`) remain fully supported.
|
|
||||||
- Usage examples: Added a recommended method for securely clearing sensitive data, e.g., secret keys, from memory.
|
- Added experimental support for CMake builds. Traditional GNU Autotools builds (`./configure` and `make`) remain fully supported.
|
||||||
- Tests: Added a new test binary `noverify_tests`. This binary runs the tests without some additional checks present in the ordinary `tests` binary and is thereby closer to production binaries. The `noverify_tests` binary is automatically run as part of the `make check` target.
|
- Usage examples: Added a recommended method for securely clearing sensitive data, e.g., secret keys, from memory.
|
||||||
|
- Tests: Added a new test binary `noverify_tests`. This binary runs the tests without some additional checks present in the ordinary `tests` binary and is thereby closer to production binaries. The `noverify_tests` binary is automatically run as part of the `make check` target.
|
||||||
|
|
||||||
#### Fixed
|
#### Fixed
|
||||||
- Fixed declarations of API variables for MSVC (`__declspec(dllimport)`). This fixes MSVC builds of programs which link against a libsecp256k1 DLL dynamically and use API variables (and not only API functions). Unfortunately, the MSVC linker now will emit warning `LNK4217` when trying to link against libsecp256k1 statically. Pass `/ignore:4217` to the linker to suppress this warning.
|
|
||||||
|
- Fixed declarations of API variables for MSVC (`__declspec(dllimport)`). This fixes MSVC builds of programs which link against a libsecp256k1 DLL dynamically and use API variables (and not only API functions). Unfortunately, the MSVC linker now will emit warning `LNK4217` when trying to link against libsecp256k1 statically. Pass `/ignore:4217` to the linker to suppress this warning.
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
- Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.)
|
|
||||||
- Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization.
|
- Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.)
|
||||||
|
- Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization.
|
||||||
|
|
||||||
#### Removed
|
#### Removed
|
||||||
- Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` or `cmake` to set configuration options (see `./configure --help` or `cmake -LH`). If you cannot or do not want to use one of the supported build systems, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags).
|
|
||||||
|
- Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` or `cmake` to set configuration options (see `./configure --help` or `cmake -LH`). If you cannot or do not want to use one of the supported build systems, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags).
|
||||||
|
|
||||||
#### ABI Compatibility
|
#### ABI Compatibility
|
||||||
Due to changes in the API regarding `secp256k1_context_static` described above, the ABI is *not* compatible with previous versions.
|
|
||||||
|
Due to changes in the API regarding `secp256k1_context_static` described above, the ABI is _not_ compatible with previous versions.
|
||||||
|
|
||||||
## [0.2.0] - 2022-12-12
|
## [0.2.0] - 2022-12-12
|
||||||
|
|
||||||
#### Added
|
#### Added
|
||||||
- Added usage examples for common use cases in a new `examples/` directory.
|
|
||||||
- Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`.
|
- Added usage examples for common use cases in a new `examples/` directory.
|
||||||
- Added support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms.
|
- Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`.
|
||||||
|
- Added support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms.
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
- Enabled modules `schnorrsig`, `extrakeys` and `ecdh` by default in `./configure`.
|
|
||||||
- The `secp256k1_nonce_function_rfc6979` nonce function, used by default by `secp256k1_ecdsa_sign`, now reduces the message hash modulo the group order to match the specification. This only affects improper use of ECDSA signing API.
|
- Enabled modules `schnorrsig`, `extrakeys` and `ecdh` by default in `./configure`.
|
||||||
|
- The `secp256k1_nonce_function_rfc6979` nonce function, used by default by `secp256k1_ecdsa_sign`, now reduces the message hash modulo the group order to match the specification. This only affects improper use of ECDSA signing API.
|
||||||
|
|
||||||
#### Deprecated
|
#### Deprecated
|
||||||
- Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead.
|
|
||||||
- Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`.
|
- Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead.
|
||||||
- Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`.
|
- Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`.
|
||||||
|
- Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`.
|
||||||
|
|
||||||
#### ABI Compatibility
|
#### ABI Compatibility
|
||||||
|
|
||||||
Since this is the first release, we do not compare application binary interfaces.
|
Since this is the first release, we do not compare application binary interfaces.
|
||||||
However, there are earlier unreleased versions of libsecp256k1 that are *not* ABI compatible with this version.
|
However, there are earlier unreleased versions of libsecp256k1 that are _not_ ABI compatible with this version.
|
||||||
|
|
||||||
## [0.1.0] - 2013-03-05 to 2021-12-25
|
## [0.1.0] - 2013-03-05 to 2021-12-25
|
||||||
|
|
||||||
|
|||||||
6
external/secp256k1/CMakePresets.json
vendored
6
external/secp256k1/CMakePresets.json
vendored
@@ -1,5 +1,9 @@
|
|||||||
{
|
{
|
||||||
"cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0},
|
"cmakeMinimumRequired": {
|
||||||
|
"major": 3,
|
||||||
|
"minor": 21,
|
||||||
|
"patch": 0
|
||||||
|
},
|
||||||
"version": 3,
|
"version": 3,
|
||||||
"configurePresets": [
|
"configurePresets": [
|
||||||
{
|
{
|
||||||
|
|||||||
74
external/secp256k1/CONTRIBUTING.md
vendored
74
external/secp256k1/CONTRIBUTING.md
vendored
@@ -12,15 +12,15 @@ The libsecp256k1 project welcomes contributions in the form of new functionality
|
|||||||
It is the responsibility of the contributors to convince the maintainers that the proposed functionality is within the project's scope, high-quality and maintainable.
|
It is the responsibility of the contributors to convince the maintainers that the proposed functionality is within the project's scope, high-quality and maintainable.
|
||||||
Contributors are recommended to provide the following in addition to the new code:
|
Contributors are recommended to provide the following in addition to the new code:
|
||||||
|
|
||||||
* **Specification:**
|
- **Specification:**
|
||||||
A specification can help significantly in reviewing the new code as it provides documentation and context.
|
A specification can help significantly in reviewing the new code as it provides documentation and context.
|
||||||
It may justify various design decisions, give a motivation and outline security goals.
|
It may justify various design decisions, give a motivation and outline security goals.
|
||||||
If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code.
|
If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code.
|
||||||
* **Security Arguments:**
|
- **Security Arguments:**
|
||||||
In addition to a defining the security goals, it should be argued that the new functionality meets these goals.
|
In addition to a defining the security goals, it should be argued that the new functionality meets these goals.
|
||||||
Depending on the nature of the new functionality, a wide range of security arguments are acceptable, ranging from being "obviously secure" to rigorous proofs of security.
|
Depending on the nature of the new functionality, a wide range of security arguments are acceptable, ranging from being "obviously secure" to rigorous proofs of security.
|
||||||
* **Relevance Arguments:**
|
- **Relevance Arguments:**
|
||||||
The relevance of the new functionality for the Bitcoin ecosystem should be argued by outlining clear use cases.
|
The relevance of the new functionality for the Bitcoin ecosystem should be argued by outlining clear use cases.
|
||||||
|
|
||||||
These are not the only factors taken into account when considering to add new functionality.
|
These are not the only factors taken into account when considering to add new functionality.
|
||||||
The proposed new libsecp256k1 code must be of high quality, including API documentation and tests, as well as featuring a misuse-resistant API design.
|
The proposed new libsecp256k1 code must be of high quality, including API documentation and tests, as well as featuring a misuse-resistant API design.
|
||||||
@@ -44,36 +44,36 @@ The Contributor Workflow & Peer Review in libsecp256k1 are similar to Bitcoin Co
|
|||||||
|
|
||||||
In addition, libsecp256k1 tries to maintain the following coding conventions:
|
In addition, libsecp256k1 tries to maintain the following coding conventions:
|
||||||
|
|
||||||
* No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `secp256k1_context_create` or `secp256k1_scratch_space_create`, for example). Moreover, it should be possible to use the library without any heap allocations.
|
- No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `secp256k1_context_create` or `secp256k1_scratch_space_create`, for example). Moreover, it should be possible to use the library without any heap allocations.
|
||||||
* The tests should cover all lines and branches of the library (see [Test coverage](#coverage)).
|
- The tests should cover all lines and branches of the library (see [Test coverage](#coverage)).
|
||||||
* Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)).
|
- Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)).
|
||||||
* Local variables containing secret data should be cleared explicitly to try to delete secrets from memory.
|
- Local variables containing secret data should be cleared explicitly to try to delete secrets from memory.
|
||||||
* Use `secp256k1_memcmp_var` instead of `memcmp` (see [#823](https://github.com/bitcoin-core/secp256k1/issues/823)).
|
- Use `secp256k1_memcmp_var` instead of `memcmp` (see [#823](https://github.com/bitcoin-core/secp256k1/issues/823)).
|
||||||
* As a rule of thumb, the default values for configuration options should target standard desktop machines and align with Bitcoin Core's defaults, and the tests should mostly exercise the default configuration (see [#1549](https://github.com/bitcoin-core/secp256k1/issues/1549#issuecomment-2200559257)).
|
- As a rule of thumb, the default values for configuration options should target standard desktop machines and align with Bitcoin Core's defaults, and the tests should mostly exercise the default configuration (see [#1549](https://github.com/bitcoin-core/secp256k1/issues/1549#issuecomment-2200559257)).
|
||||||
|
|
||||||
#### Style conventions
|
#### Style conventions
|
||||||
|
|
||||||
* Commits should be atomic and diffs should be easy to read. For this reason, do not mix any formatting fixes or code moves with actual code changes. Make sure each individual commit is hygienic: that it builds successfully on its own without warnings, errors, regressions, or test failures.
|
- Commits should be atomic and diffs should be easy to read. For this reason, do not mix any formatting fixes or code moves with actual code changes. Make sure each individual commit is hygienic: that it builds successfully on its own without warnings, errors, regressions, or test failures.
|
||||||
* New code should adhere to the style of existing, in particular surrounding, code. Other than that, we do not enforce strict rules for code formatting.
|
- New code should adhere to the style of existing, in particular surrounding, code. Other than that, we do not enforce strict rules for code formatting.
|
||||||
* The code conforms to C89. Most notably, that means that only `/* ... */` comments are allowed (no `//` line comments). Moreover, any declarations in a `{ ... }` block (e.g., a function) must appear at the beginning of the block before any statements. When you would like to declare a variable in the middle of a block, you can open a new block:
|
- The code conforms to C89. Most notably, that means that only `/* ... */` comments are allowed (no `//` line comments). Moreover, any declarations in a `{ ... }` block (e.g., a function) must appear at the beginning of the block before any statements. When you would like to declare a variable in the middle of a block, you can open a new block:
|
||||||
```C
|
```C
|
||||||
void secp256k_foo(void) {
|
void secp256k_foo(void) {
|
||||||
unsigned int x; /* declaration */
|
unsigned int x; /* declaration */
|
||||||
int y = 2*x; /* declaration */
|
int y = 2*x; /* declaration */
|
||||||
x = 17; /* statement */
|
x = 17; /* statement */
|
||||||
{
|
{
|
||||||
int a, b; /* declaration */
|
int a, b; /* declaration */
|
||||||
a = x + y; /* statement */
|
a = x + y; /* statement */
|
||||||
secp256k_bar(x, &b); /* statement */
|
secp256k_bar(x, &b); /* statement */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
* Use `unsigned int` instead of just `unsigned`.
|
- Use `unsigned int` instead of just `unsigned`.
|
||||||
* Use `void *ptr` instead of `void* ptr`.
|
- Use `void *ptr` instead of `void* ptr`.
|
||||||
* Arguments of the publicly-facing API must have a specific order defined in [include/secp256k1.h](include/secp256k1.h).
|
- Arguments of the publicly-facing API must have a specific order defined in [include/secp256k1.h](include/secp256k1.h).
|
||||||
* User-facing comment lines in headers should be limited to 80 chars if possible.
|
- User-facing comment lines in headers should be limited to 80 chars if possible.
|
||||||
* All identifiers in file scope should start with `secp256k1_`.
|
- All identifiers in file scope should start with `secp256k1_`.
|
||||||
* Avoid trailing whitespace.
|
- Avoid trailing whitespace.
|
||||||
|
|
||||||
### Tests
|
### Tests
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ To create a HTML report with coloured and annotated source code:
|
|||||||
#### Exhaustive tests
|
#### Exhaustive tests
|
||||||
|
|
||||||
There are tests of several functions in which a small group replaces secp256k1.
|
There are tests of several functions in which a small group replaces secp256k1.
|
||||||
These tests are *exhaustive* since they provide all elements and scalars of the small group as input arguments (see [src/tests_exhaustive.c](src/tests_exhaustive.c)).
|
These tests are _exhaustive_ since they provide all elements and scalars of the small group as input arguments (see [src/tests_exhaustive.c](src/tests_exhaustive.c)).
|
||||||
|
|
||||||
### Benchmarks
|
### Benchmarks
|
||||||
|
|
||||||
|
|||||||
130
external/secp256k1/README.md
vendored
130
external/secp256k1/README.md
vendored
@@ -1,5 +1,4 @@
|
|||||||
libsecp256k1
|
# libsecp256k1
|
||||||
============
|
|
||||||
|
|
||||||

|

|
||||||
[](https://web.libera.chat/#secp256k1)
|
[](https://web.libera.chat/#secp256k1)
|
||||||
@@ -9,60 +8,59 @@ High-performance high-assurance C library for digital signatures and other crypt
|
|||||||
This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose.
|
This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose.
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
* secp256k1 ECDSA signing/verification and key generation.
|
|
||||||
* Additive and multiplicative tweaking of secret/public keys.
|
|
||||||
* Serialization/parsing of secret keys, public keys, signatures.
|
|
||||||
* Constant time, constant memory access signing and public key generation.
|
|
||||||
* Derandomized ECDSA (via RFC6979 or with a caller provided function.)
|
|
||||||
* Very efficient implementation.
|
|
||||||
* Suitable for embedded systems.
|
|
||||||
* No runtime dependencies.
|
|
||||||
* Optional module for public key recovery.
|
|
||||||
* Optional module for ECDH key exchange.
|
|
||||||
* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
|
||||||
* Optional module for ElligatorSwift key exchange according to [BIP-324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki).
|
|
||||||
* Optional module for MuSig2 Schnorr multi-signatures according to [BIP-327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki).
|
|
||||||
|
|
||||||
Implementation details
|
- secp256k1 ECDSA signing/verification and key generation.
|
||||||
----------------------
|
- Additive and multiplicative tweaking of secret/public keys.
|
||||||
|
- Serialization/parsing of secret keys, public keys, signatures.
|
||||||
|
- Constant time, constant memory access signing and public key generation.
|
||||||
|
- Derandomized ECDSA (via RFC6979 or with a caller provided function.)
|
||||||
|
- Very efficient implementation.
|
||||||
|
- Suitable for embedded systems.
|
||||||
|
- No runtime dependencies.
|
||||||
|
- Optional module for public key recovery.
|
||||||
|
- Optional module for ECDH key exchange.
|
||||||
|
- Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||||
|
- Optional module for ElligatorSwift key exchange according to [BIP-324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki).
|
||||||
|
- Optional module for MuSig2 Schnorr multi-signatures according to [BIP-327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki).
|
||||||
|
|
||||||
* General
|
## Implementation details
|
||||||
* No runtime heap allocation.
|
|
||||||
* Extensive testing infrastructure.
|
|
||||||
* Structured to facilitate review and analysis.
|
|
||||||
* Intended to be portable to any system with a C89 compiler and uint64_t support.
|
|
||||||
* No use of floating types.
|
|
||||||
* Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
|
|
||||||
* Field operations
|
|
||||||
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
|
|
||||||
* Using 5 52-bit limbs
|
|
||||||
* Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan).
|
|
||||||
* This is an experimental feature that has not received enough scrutiny to satisfy the standard of quality of this library but is made available for testing and review by the community.
|
|
||||||
* Scalar operations
|
|
||||||
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
|
|
||||||
* Using 4 64-bit limbs (relying on __int128 support in the compiler).
|
|
||||||
* Using 8 32-bit limbs.
|
|
||||||
* Modular inverses (both field elements and scalars) based on [safegcd](https://gcd.cr.yp.to/index.html) with some modifications, and a variable-time variant (by Peter Dettman).
|
|
||||||
* Group operations
|
|
||||||
* Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7).
|
|
||||||
* Use addition between points in Jacobian and affine coordinates where possible.
|
|
||||||
* Use a unified addition/doubling formula where necessary to avoid data-dependent branches.
|
|
||||||
* Point/x comparison without a field inversion by comparison in the Jacobian coordinate space.
|
|
||||||
* Point multiplication for verification (a*P + b*G).
|
|
||||||
* Use wNAF notation for point multiplicands.
|
|
||||||
* Use a much larger window for multiples of G, using precomputed multiples.
|
|
||||||
* Use Shamir's trick to do the multiplication with the public key and the generator simultaneously.
|
|
||||||
* Use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
|
|
||||||
* Point multiplication for signing
|
|
||||||
* Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.
|
|
||||||
* Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains)
|
|
||||||
* Access the table with branch-free conditional moves so memory access is uniform.
|
|
||||||
* No data-dependent branches
|
|
||||||
* Optional runtime blinding which attempts to frustrate differential power analysis.
|
|
||||||
* The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally.
|
|
||||||
|
|
||||||
Building with Autotools
|
- General
|
||||||
-----------------------
|
- No runtime heap allocation.
|
||||||
|
- Extensive testing infrastructure.
|
||||||
|
- Structured to facilitate review and analysis.
|
||||||
|
- Intended to be portable to any system with a C89 compiler and uint64_t support.
|
||||||
|
- No use of floating types.
|
||||||
|
- Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
|
||||||
|
- Field operations
|
||||||
|
- Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
|
||||||
|
- Using 5 52-bit limbs
|
||||||
|
- Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan).
|
||||||
|
- This is an experimental feature that has not received enough scrutiny to satisfy the standard of quality of this library but is made available for testing and review by the community.
|
||||||
|
- Scalar operations
|
||||||
|
- Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
|
||||||
|
- Using 4 64-bit limbs (relying on \_\_int128 support in the compiler).
|
||||||
|
- Using 8 32-bit limbs.
|
||||||
|
- Modular inverses (both field elements and scalars) based on [safegcd](https://gcd.cr.yp.to/index.html) with some modifications, and a variable-time variant (by Peter Dettman).
|
||||||
|
- Group operations
|
||||||
|
- Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7).
|
||||||
|
- Use addition between points in Jacobian and affine coordinates where possible.
|
||||||
|
- Use a unified addition/doubling formula where necessary to avoid data-dependent branches.
|
||||||
|
- Point/x comparison without a field inversion by comparison in the Jacobian coordinate space.
|
||||||
|
- Point multiplication for verification (a*P + b*G).
|
||||||
|
- Use wNAF notation for point multiplicands.
|
||||||
|
- Use a much larger window for multiples of G, using precomputed multiples.
|
||||||
|
- Use Shamir's trick to do the multiplication with the public key and the generator simultaneously.
|
||||||
|
- Use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
|
||||||
|
- Point multiplication for signing
|
||||||
|
- Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.
|
||||||
|
- Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains)
|
||||||
|
- Access the table with branch-free conditional moves so memory access is uniform.
|
||||||
|
- No data-dependent branches
|
||||||
|
- Optional runtime blinding which attempts to frustrate differential power analysis.
|
||||||
|
- The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally.
|
||||||
|
|
||||||
|
## Building with Autotools
|
||||||
|
|
||||||
$ ./autogen.sh
|
$ ./autogen.sh
|
||||||
$ ./configure
|
$ ./configure
|
||||||
@@ -72,8 +70,7 @@ Building with Autotools
|
|||||||
|
|
||||||
To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags.
|
To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags.
|
||||||
|
|
||||||
Building with CMake (experimental)
|
## Building with CMake (experimental)
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree.
|
To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree.
|
||||||
|
|
||||||
@@ -109,18 +106,19 @@ In "Developer Command Prompt for VS 2022":
|
|||||||
>cmake -G "Visual Studio 17 2022" -A x64 -S . -B build
|
>cmake -G "Visual Studio 17 2022" -A x64 -S . -B build
|
||||||
>cmake --build build --config RelWithDebInfo
|
>cmake --build build --config RelWithDebInfo
|
||||||
|
|
||||||
Usage examples
|
## Usage examples
|
||||||
-----------
|
|
||||||
Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
|
Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
|
||||||
* [ECDSA example](examples/ecdsa.c)
|
|
||||||
* [Schnorr signatures example](examples/schnorr.c)
|
- [ECDSA example](examples/ecdsa.c)
|
||||||
* [Deriving a shared secret (ECDH) example](examples/ecdh.c)
|
- [Schnorr signatures example](examples/schnorr.c)
|
||||||
* [ElligatorSwift key exchange example](examples/ellswift.c)
|
- [Deriving a shared secret (ECDH) example](examples/ecdh.c)
|
||||||
|
- [ElligatorSwift key exchange example](examples/ellswift.c)
|
||||||
|
|
||||||
To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
|
To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
|
||||||
|
|
||||||
Benchmark
|
## Benchmark
|
||||||
------------
|
|
||||||
If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1 functions will be present in the root directory after the build.
|
If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1 functions will be present in the root directory after the build.
|
||||||
|
|
||||||
To print the benchmark result to the command line:
|
To print the benchmark result to the command line:
|
||||||
@@ -131,12 +129,10 @@ To create a CSV file for the benchmark result :
|
|||||||
|
|
||||||
$ ./bench_name | sed '2d;s/ \{1,\}//g' > bench_name.csv
|
$ ./bench_name | sed '2d;s/ \{1,\}//g' > bench_name.csv
|
||||||
|
|
||||||
Reporting a vulnerability
|
## Reporting a vulnerability
|
||||||
------------
|
|
||||||
|
|
||||||
See [SECURITY.md](SECURITY.md)
|
See [SECURITY.md](SECURITY.md)
|
||||||
|
|
||||||
Contributing to libsecp256k1
|
## Contributing to libsecp256k1
|
||||||
------------
|
|
||||||
|
|
||||||
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||||
|
|||||||
10
external/secp256k1/SECURITY.md
vendored
10
external/secp256k1/SECURITY.md
vendored
@@ -6,10 +6,10 @@ To report security issues send an email to secp256k1-security@bitcoincore.org (n
|
|||||||
|
|
||||||
The following keys may be used to communicate sensitive information to developers:
|
The following keys may be used to communicate sensitive information to developers:
|
||||||
|
|
||||||
| Name | Fingerprint |
|
| Name | Fingerprint |
|
||||||
|------|-------------|
|
| ------------- | ------------------------------------------------- |
|
||||||
| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 |
|
| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 |
|
||||||
| Jonas Nick | 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366 |
|
| Jonas Nick | 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366 |
|
||||||
| Tim Ruffing | 09E0 3F87 1092 E40E 106E 902B 33BC 86AB 80FF 5516 |
|
| Tim Ruffing | 09E0 3F87 1092 E40E 106E 902B 33BC 86AB 80FF 5516 |
|
||||||
|
|
||||||
You can import a key by running the following command with that individual’s fingerprint: `gpg --keyserver hkps://keys.openpgp.org --recv-keys "<fingerprint>"` Ensure that you put quotes around fingerprints containing spaces.
|
You can import a key by running the following command with that individual’s fingerprint: `gpg --keyserver hkps://keys.openpgp.org --recv-keys "<fingerprint>"` Ensure that you put quotes around fingerprints containing spaces.
|
||||||
|
|||||||
410
external/secp256k1/doc/ellswift.md
vendored
410
external/secp256k1/doc/ellswift.md
vendored
@@ -5,17 +5,17 @@ construction in the
|
|||||||
["SwiftEC: Shallue–van de Woestijne Indifferentiable Function To Elliptic Curves"](https://eprint.iacr.org/2022/759)
|
["SwiftEC: Shallue–van de Woestijne Indifferentiable Function To Elliptic Curves"](https://eprint.iacr.org/2022/759)
|
||||||
paper by Jorge Chávez-Saab, Francisco Rodríguez-Henríquez, and Mehdi Tibouchi.
|
paper by Jorge Chávez-Saab, Francisco Rodríguez-Henríquez, and Mehdi Tibouchi.
|
||||||
|
|
||||||
* [1. Introduction](#1-introduction)
|
- [1. Introduction](#1-introduction)
|
||||||
* [2. The decoding function](#2-the-decoding-function)
|
- [2. The decoding function](#2-the-decoding-function)
|
||||||
+ [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1)
|
- [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1)
|
||||||
* [3. The encoding function](#3-the-encoding-function)
|
- [3. The encoding function](#3-the-encoding-function)
|
||||||
+ [3.1 Switching to *v, w* coordinates](#31-switching-to-v-w-coordinates)
|
- [3.1 Switching to _v, w_ coordinates](#31-switching-to-v-w-coordinates)
|
||||||
+ [3.2 Avoiding computing all inverses](#32-avoiding-computing-all-inverses)
|
- [3.2 Avoiding computing all inverses](#32-avoiding-computing-all-inverses)
|
||||||
+ [3.3 Finding the inverse](#33-finding-the-inverse)
|
- [3.3 Finding the inverse](#33-finding-the-inverse)
|
||||||
+ [3.4 Dealing with special cases](#34-dealing-with-special-cases)
|
- [3.4 Dealing with special cases](#34-dealing-with-special-cases)
|
||||||
+ [3.5 Encoding for `secp256k1`](#35-encoding-for-secp256k1)
|
- [3.5 Encoding for `secp256k1`](#35-encoding-for-secp256k1)
|
||||||
* [4. Encoding and decoding full *(x, y)* coordinates](#4-encoding-and-decoding-full-x-y-coordinates)
|
- [4. Encoding and decoding full _(x, y)_ coordinates](#4-encoding-and-decoding-full-x-y-coordinates)
|
||||||
+ [4.1 Full *(x, y)* coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1)
|
- [4.1 Full _(x, y)_ coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1)
|
||||||
|
|
||||||
## 1. Introduction
|
## 1. Introduction
|
||||||
|
|
||||||
@@ -34,13 +34,14 @@ are taken modulo $p$), and then evaluating $F_u(t)$, which for every $u$ and $t$
|
|||||||
x-coordinate on the curve. The functions $F_u$ will be defined in [Section 2](#2-the-decoding-function).
|
x-coordinate on the curve. The functions $F_u$ will be defined in [Section 2](#2-the-decoding-function).
|
||||||
|
|
||||||
**Encoding** a given $x$ coordinate is conceptually done as follows:
|
**Encoding** a given $x$ coordinate is conceptually done as follows:
|
||||||
* Loop:
|
|
||||||
* Pick a uniformly random field element $u.$
|
|
||||||
* Compute the set $L = F_u^{-1}(x)$ of $t$ values for which $F_u(t) = x$, which may have up to *8* elements.
|
|
||||||
* With probability $1 - \dfrac{\\#L}{8}$, restart the loop.
|
|
||||||
* Select a uniformly random $t \in L$ and return $(u, t).$
|
|
||||||
|
|
||||||
This is the *ElligatorSwift* algorithm, here given for just x-coordinates. An extension to full
|
- Loop:
|
||||||
|
- Pick a uniformly random field element $u.$
|
||||||
|
- Compute the set $L = F_u^{-1}(x)$ of $t$ values for which $F_u(t) = x$, which may have up to _8_ elements.
|
||||||
|
- With probability $1 - \dfrac{\\#L}{8}$, restart the loop.
|
||||||
|
- Select a uniformly random $t \in L$ and return $(u, t).$
|
||||||
|
|
||||||
|
This is the _ElligatorSwift_ algorithm, here given for just x-coordinates. An extension to full
|
||||||
$(x, y)$ points will be given in [Section 4](#4-encoding-and-decoding-full-x-y-coordinates).
|
$(x, y)$ points will be given in [Section 4](#4-encoding-and-decoding-full-x-y-coordinates).
|
||||||
The algorithm finds a uniformly random $(u, t)$ among (almost all) those
|
The algorithm finds a uniformly random $(u, t)$ among (almost all) those
|
||||||
for which $F_u(t) = x.$ Section 3.2 in the paper proves that the number of such encodings for
|
for which $F_u(t) = x.$ Section 3.2 in the paper proves that the number of such encodings for
|
||||||
@@ -50,37 +51,40 @@ almost all x-coordinates on the curve (all but at most 39) is close to two times
|
|||||||
## 2. The decoding function
|
## 2. The decoding function
|
||||||
|
|
||||||
First some definitions:
|
First some definitions:
|
||||||
* $\mathbb{F}$ is the finite field of size $q$, of characteristic 5 or more, and $q \equiv 1 \mod 3.$
|
|
||||||
* For `secp256k1`, $q = 2^{256} - 2^{32} - 977$, which satisfies that requirement.
|
- $\mathbb{F}$ is the finite field of size $q$, of characteristic 5 or more, and $q \equiv 1 \mod 3.$
|
||||||
* Let $E$ be the elliptic curve of points $(x, y) \in \mathbb{F}^2$ for which $y^2 = x^3 + ax + b$, with $a$ and $b$
|
- For `secp256k1`, $q = 2^{256} - 2^{32} - 977$, which satisfies that requirement.
|
||||||
|
- Let $E$ be the elliptic curve of points $(x, y) \in \mathbb{F}^2$ for which $y^2 = x^3 + ax + b$, with $a$ and $b$
|
||||||
public constants, for which $\Delta_E = -16(4a^3 + 27b^2)$ is a square, and at least one of $(-b \pm \sqrt{-3 \Delta_E} / 36)/2$ is a square.
|
public constants, for which $\Delta_E = -16(4a^3 + 27b^2)$ is a square, and at least one of $(-b \pm \sqrt{-3 \Delta_E} / 36)/2$ is a square.
|
||||||
This implies that the order of $E$ is either odd, or a multiple of *4*.
|
This implies that the order of $E$ is either odd, or a multiple of _4_.
|
||||||
If $a=0$, this condition is always fulfilled.
|
If $a=0$, this condition is always fulfilled.
|
||||||
* For `secp256k1`, $a=0$ and $b=7.$
|
- For `secp256k1`, $a=0$ and $b=7.$
|
||||||
* Let the function $g(x) = x^3 + ax + b$, so the $E$ curve equation is also $y^2 = g(x).$
|
- Let the function $g(x) = x^3 + ax + b$, so the $E$ curve equation is also $y^2 = g(x).$
|
||||||
* Let the function $h(x) = 3x^3 + 4a.$
|
- Let the function $h(x) = 3x^3 + 4a.$
|
||||||
* Define $V$ as the set of solutions $(x_1, x_2, x_3, z)$ to $z^2 = g(x_1)g(x_2)g(x_3).$
|
- Define $V$ as the set of solutions $(x_1, x_2, x_3, z)$ to $z^2 = g(x_1)g(x_2)g(x_3).$
|
||||||
* Define $S_u$ as the set of solutions $(X, Y)$ to $X^2 + h(u)Y^2 = -g(u)$ and $Y \neq 0.$
|
- Define $S_u$ as the set of solutions $(X, Y)$ to $X^2 + h(u)Y^2 = -g(u)$ and $Y \neq 0.$
|
||||||
* $P_u$ is a function from $\mathbb{F}$ to $S_u$ that will be defined below.
|
- $P_u$ is a function from $\mathbb{F}$ to $S_u$ that will be defined below.
|
||||||
* $\psi_u$ is a function from $S_u$ to $V$ that will be defined below.
|
- $\psi_u$ is a function from $S_u$ to $V$ that will be defined below.
|
||||||
|
|
||||||
**Note**: In the paper:
|
**Note**: In the paper:
|
||||||
* $F_u$ corresponds to $F_{0,u}$ there.
|
|
||||||
* $P_u(t)$ is called $P$ there.
|
- $F_u$ corresponds to $F_{0,u}$ there.
|
||||||
* All $S_u$ sets together correspond to $S$ there.
|
- $P_u(t)$ is called $P$ there.
|
||||||
* All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there.
|
- All $S_u$ sets together correspond to $S$ there.
|
||||||
|
- All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there.
|
||||||
|
|
||||||
Note that for $V$, the left hand side of the equation $z^2$ is square, and thus the right
|
Note that for $V$, the left hand side of the equation $z^2$ is square, and thus the right
|
||||||
hand must also be square. As multiplying non-squares results in a square in $\mathbb{F}$,
|
hand must also be square. As multiplying non-squares results in a square in $\mathbb{F}$,
|
||||||
out of the three right-hand side factors an even number must be non-squares.
|
out of the three right-hand side factors an even number must be non-squares.
|
||||||
This implies that exactly *1* or exactly *3* out of
|
This implies that exactly _1_ or exactly _3_ out of
|
||||||
$\\{g(x_1), g(x_2), g(x_3)\\}$ must be square, and thus that for any $(x_1,x_2,x_3,z) \in V$,
|
$\\{g(x_1), g(x_2), g(x_3)\\}$ must be square, and thus that for any $(x_1,x_2,x_3,z) \in V$,
|
||||||
at least one of $\\{x_1, x_2, x_3\\}$ must be a valid x-coordinate on $E.$ There is one exception
|
at least one of $\\{x_1, x_2, x_3\\}$ must be a valid x-coordinate on $E.$ There is one exception
|
||||||
to this, namely when $z=0$, but even then one of the three values is a valid x-coordinate.
|
to this, namely when $z=0$, but even then one of the three values is a valid x-coordinate.
|
||||||
|
|
||||||
**Define** the decoding function $F_u(t)$ as:
|
**Define** the decoding function $F_u(t)$ as:
|
||||||
* Let $(x_1, x_2, x_3, z) = \psi_u(P_u(t)).$
|
|
||||||
* Return the first element $x$ of $(x_3, x_2, x_1)$ which is a valid x-coordinate on $E$ (i.e., $g(x)$ is square).
|
- Let $(x_1, x_2, x_3, z) = \psi_u(P_u(t)).$
|
||||||
|
- Return the first element $x$ of $(x_3, x_2, x_1)$ which is a valid x-coordinate on $E$ (i.e., $g(x)$ is square).
|
||||||
|
|
||||||
$P_u(t) = (X(u, t), Y(u, t))$, where:
|
$P_u(t) = (X(u, t), Y(u, t))$, where:
|
||||||
|
|
||||||
@@ -98,12 +102,13 @@ Y(u, t) & = & \left\\{\begin{array}{ll}
|
|||||||
$$
|
$$
|
||||||
|
|
||||||
$P_u(t)$ is defined:
|
$P_u(t)$ is defined:
|
||||||
* For $a=0$, unless:
|
|
||||||
* $u = 0$ or $t = 0$ (division by zero)
|
- For $a=0$, unless:
|
||||||
* $g(u) = -t^2$ (would give $Y=0$).
|
- $u = 0$ or $t = 0$ (division by zero)
|
||||||
* For $a \neq 0$, unless:
|
- $g(u) = -t^2$ (would give $Y=0$).
|
||||||
* $X_0(u) = 0$ or $h(u)t^2 = -1$ (division by zero)
|
- For $a \neq 0$, unless:
|
||||||
* $Y_0(u) (1 - h(u)t^2) = 2X_0(u)t$ (would give $Y=0$).
|
- $X_0(u) = 0$ or $h(u)t^2 = -1$ (division by zero)
|
||||||
|
- $Y_0(u) (1 - h(u)t^2) = 2X_0(u)t$ (would give $Y=0$).
|
||||||
|
|
||||||
The functions $X_0(u)$ and $Y_0(u)$ are defined in Appendix A of the paper, and depend on various properties of $E.$
|
The functions $X_0(u)$ and $Y_0(u)$ are defined in Appendix A of the paper, and depend on various properties of $E.$
|
||||||
|
|
||||||
@@ -123,20 +128,22 @@ $$
|
|||||||
Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is:
|
Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is:
|
||||||
|
|
||||||
**Define** $F_u(t)$ as:
|
**Define** $F_u(t)$ as:
|
||||||
* Let $X = \dfrac{u^3 + b - t^2}{2t}.$
|
|
||||||
* Let $Y = \dfrac{X + t}{u\sqrt{-3}}.$
|
- Let $X = \dfrac{u^3 + b - t^2}{2t}.$
|
||||||
* Return the first $x$ in $(u + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u}{2}, \dfrac{X}{2Y} - \dfrac{u}{2})$ for which $g(x)$ is square.
|
- Let $Y = \dfrac{X + t}{u\sqrt{-3}}.$
|
||||||
|
- Return the first $x$ in $(u + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u}{2}, \dfrac{X}{2Y} - \dfrac{u}{2})$ for which $g(x)$ is square.
|
||||||
|
|
||||||
To make sure that every input decodes to a valid x-coordinate, we remap the inputs in case
|
To make sure that every input decodes to a valid x-coordinate, we remap the inputs in case
|
||||||
$P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$):
|
$P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$):
|
||||||
|
|
||||||
**Define** $F_u(t)$ as:
|
**Define** $F_u(t)$ as:
|
||||||
* Let $u'=u$ if $u \neq 0$; $1$ otherwise (guaranteeing $u' \neq 0$).
|
|
||||||
* Let $t'=t$ if $t \neq 0$; $1$ otherwise (guaranteeing $t' \neq 0$).
|
- Let $u'=u$ if $u \neq 0$; $1$ otherwise (guaranteeing $u' \neq 0$).
|
||||||
* Let $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$).
|
- Let $t'=t$ if $t \neq 0$; $1$ otherwise (guaranteeing $t' \neq 0$).
|
||||||
* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
|
- Let $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$).
|
||||||
* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
|
- Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
|
||||||
* Return the first $x$ in $(u' + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u'}{2}, \dfrac{X}{2Y} - \dfrac{u'}{2})$ for which $x^3 + b$ is square.
|
- Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
|
||||||
|
- Return the first $x$ in $(u' + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u'}{2}, \dfrac{X}{2Y} - \dfrac{u'}{2})$ for which $x^3 + b$ is square.
|
||||||
|
|
||||||
The choices here are not strictly necessary. Just returning a fixed constant in any of the undefined cases would suffice,
|
The choices here are not strictly necessary. Just returning a fixed constant in any of the undefined cases would suffice,
|
||||||
but the approach here is simple enough and gives fairly uniform output even in these cases.
|
but the approach here is simple enough and gives fairly uniform output even in these cases.
|
||||||
@@ -150,10 +157,11 @@ in `secp256k1_ellswift_xswiftec_var` (which outputs the actual x-coordinate).
|
|||||||
## 3. The encoding function
|
## 3. The encoding function
|
||||||
|
|
||||||
To implement $F_u^{-1}(x)$, the function to find the set of inverses $t$ for which $F_u(t) = x$, we have to reverse the process:
|
To implement $F_u^{-1}(x)$, the function to find the set of inverses $t$ for which $F_u(t) = x$, we have to reverse the process:
|
||||||
* Find all the $(X, Y) \in S_u$ that could have given rise to $x$, through the $x_1$, $x_2$, or $x_3$ formulas in $\psi_u.$
|
|
||||||
* Map those $(X, Y)$ solutions to $t$ values using $P_u^{-1}(X, Y).$
|
- Find all the $(X, Y) \in S_u$ that could have given rise to $x$, through the $x_1$, $x_2$, or $x_3$ formulas in $\psi_u.$
|
||||||
* For each of the found $t$ values, verify that $F_u(t) = x.$
|
- Map those $(X, Y)$ solutions to $t$ values using $P_u^{-1}(X, Y).$
|
||||||
* Return the remaining $t$ values.
|
- For each of the found $t$ values, verify that $F_u(t) = x.$
|
||||||
|
- Return the remaining $t$ values.
|
||||||
|
|
||||||
The function $P_u^{-1}$, which finds $t$ given $(X, Y) \in S_u$, is significantly simpler than $P_u:$
|
The function $P_u^{-1}$, which finds $t$ given $(X, Y) \in S_u$, is significantly simpler than $P_u:$
|
||||||
|
|
||||||
@@ -185,13 +193,14 @@ precedence over both. Because of this, the $g(-u-x)$ being square test for $x_1$
|
|||||||
values round-trip back to the input $x$ correctly. This is the reason for choosing the $(x_3, x_2, x_1)$ precedence order in the decoder;
|
values round-trip back to the input $x$ correctly. This is the reason for choosing the $(x_3, x_2, x_1)$ precedence order in the decoder;
|
||||||
any order which does not place $x_3$ first requires more complicated round-trip checks in the encoder.
|
any order which does not place $x_3$ first requires more complicated round-trip checks in the encoder.
|
||||||
|
|
||||||
### 3.1 Switching to *v, w* coordinates
|
### 3.1 Switching to _v, w_ coordinates
|
||||||
|
|
||||||
Before working out the formulas for all this, we switch to different variables for $S_u.$ Let $v = (X/Y - u)/2$, and
|
Before working out the formulas for all this, we switch to different variables for $S_u.$ Let $v = (X/Y - u)/2$, and
|
||||||
$w = 2Y.$ Or in the other direction, $X = w(u/2 + v)$ and $Y = w/2:$
|
$w = 2Y.$ Or in the other direction, $X = w(u/2 + v)$ and $Y = w/2:$
|
||||||
* $S_u'$ becomes the set of $(v, w)$ for which $w^2 (u^2 + uv + v^2 + a) = -g(u)$ and $w \neq 0.$
|
|
||||||
* For $a=0$ curves, $P_u^{-1}$ can be stated for $(v,w)$ as $P_u^{'-1}(v, w) = w\left(\frac{\sqrt{-3}-1}{2}u - v\right).$
|
- $S_u'$ becomes the set of $(v, w)$ for which $w^2 (u^2 + uv + v^2 + a) = -g(u)$ and $w \neq 0.$
|
||||||
* $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where
|
- For $a=0$ curves, $P_u^{-1}$ can be stated for $(v,w)$ as $P_u^{'-1}(v, w) = w\left(\frac{\sqrt{-3}-1}{2}u - v\right).$
|
||||||
|
- $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\begin{array}{lcl}
|
\begin{array}{lcl}
|
||||||
@@ -204,34 +213,37 @@ $$
|
|||||||
|
|
||||||
We can now write the expressions for finding $(v, w)$ given $x$ explicitly, by solving each of the $\\{x_1, x_2, x_3\\}$
|
We can now write the expressions for finding $(v, w)$ given $x$ explicitly, by solving each of the $\\{x_1, x_2, x_3\\}$
|
||||||
expressions for $v$ or $w$, and using the $S_u'$ equation to find the other variable:
|
expressions for $v$ or $w$, and using the $S_u'$ equation to find the other variable:
|
||||||
* Assuming $x = x_1$, we find $v = x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
|
|
||||||
* Assuming $x = x_2$, we find $v = -u-x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
|
- Assuming $x = x_1$, we find $v = x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
|
||||||
* Assuming $x = x_3$, we find $w = \pm\sqrt{x-u}$ and $v = -u/2 \pm \sqrt{-w^2(4g(u) + w^2h(u))}/(2w^2)$ (four solutions).
|
- Assuming $x = x_2$, we find $v = -u-x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
|
||||||
|
- Assuming $x = x_3$, we find $w = \pm\sqrt{x-u}$ and $v = -u/2 \pm \sqrt{-w^2(4g(u) + w^2h(u))}/(2w^2)$ (four solutions).
|
||||||
|
|
||||||
### 3.2 Avoiding computing all inverses
|
### 3.2 Avoiding computing all inverses
|
||||||
|
|
||||||
The *ElligatorSwift* algorithm as stated in Section 1 requires the computation of $L = F_u^{-1}(x)$ (the
|
The _ElligatorSwift_ algorithm as stated in Section 1 requires the computation of $L = F_u^{-1}(x)$ (the
|
||||||
set of all $t$ such that $(u, t)$ decode to $x$) in full. This is unnecessary.
|
set of all $t$ such that $(u, t)$ decode to $x$) in full. This is unnecessary.
|
||||||
|
|
||||||
Observe that the procedure of restarting with probability $(1 - \frac{\\#L}{8})$ and otherwise returning a
|
Observe that the procedure of restarting with probability $(1 - \frac{\\#L}{8})$ and otherwise returning a
|
||||||
uniformly random element from $L$ is actually equivalent to always padding $L$ with $\bot$ values up to length 8,
|
uniformly random element from $L$ is actually equivalent to always padding $L$ with $\bot$ values up to length 8,
|
||||||
picking a uniformly random element from that, restarting whenever $\bot$ is picked:
|
picking a uniformly random element from that, restarting whenever $\bot$ is picked:
|
||||||
|
|
||||||
**Define** *ElligatorSwift(x)* as:
|
**Define** _ElligatorSwift(x)_ as:
|
||||||
* Loop:
|
|
||||||
* Pick a uniformly random field element $u.$
|
- Loop:
|
||||||
* Compute the set $L = F_u^{-1}(x).$
|
- Pick a uniformly random field element $u.$
|
||||||
* Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$
|
- Compute the set $L = F_u^{-1}(x).$
|
||||||
* Select a uniformly random $t \in T.$
|
- Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$
|
||||||
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
- Select a uniformly random $t \in T.$
|
||||||
|
- If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
||||||
|
|
||||||
Now notice that the order of elements in $T$ does not matter, as all we do is pick a uniformly
|
Now notice that the order of elements in $T$ does not matter, as all we do is pick a uniformly
|
||||||
random element in it, so we do not need to have all $\bot$ values at the end.
|
random element in it, so we do not need to have all $\bot$ values at the end.
|
||||||
As we have 8 distinct formulas for finding $(v, w)$ (taking the variants due to $\pm$ into account),
|
As we have 8 distinct formulas for finding $(v, w)$ (taking the variants due to $\pm$ into account),
|
||||||
we can associate every index in $T$ with exactly one of those formulas, making sure that:
|
we can associate every index in $T$ with exactly one of those formulas, making sure that:
|
||||||
* Formulas that yield no solutions (due to division by zero or non-existing square roots) or invalid solutions are made to return $\bot.$
|
|
||||||
* For the $x_1$ and $x_2$ cases, if $g(-u-x)$ is a square, $\bot$ is returned instead (the round-trip check).
|
- Formulas that yield no solutions (due to division by zero or non-existing square roots) or invalid solutions are made to return $\bot.$
|
||||||
* In case multiple formulas would return the same non- $\bot$ result, all but one of those must be turned into $\bot$ to avoid biasing those.
|
- For the $x_1$ and $x_2$ cases, if $g(-u-x)$ is a square, $\bot$ is returned instead (the round-trip check).
|
||||||
|
- In case multiple formulas would return the same non- $\bot$ result, all but one of those must be turned into $\bot$ to avoid biasing those.
|
||||||
|
|
||||||
The last condition above only occurs with negligible probability for cryptographically-sized curves, but is interesting
|
The last condition above only occurs with negligible probability for cryptographically-sized curves, but is interesting
|
||||||
to take into account as it allows exhaustive testing in small groups. See [Section 3.4](#34-dealing-with-special-cases)
|
to take into account as it allows exhaustive testing in small groups. See [Section 3.4](#34-dealing-with-special-cases)
|
||||||
@@ -240,12 +252,13 @@ for an analysis of all the negligible cases.
|
|||||||
If we define $T = (G_{0,u}(x), G_{1,u}(x), \ldots, G_{7,u}(x))$, with each $G_{i,u}$ matching one of the formulas,
|
If we define $T = (G_{0,u}(x), G_{1,u}(x), \ldots, G_{7,u}(x))$, with each $G_{i,u}$ matching one of the formulas,
|
||||||
the loop can be simplified to only compute one of the inverses instead of all of them:
|
the loop can be simplified to only compute one of the inverses instead of all of them:
|
||||||
|
|
||||||
**Define** *ElligatorSwift(x)* as:
|
**Define** _ElligatorSwift(x)_ as:
|
||||||
* Loop:
|
|
||||||
* Pick a uniformly random field element $u.$
|
- Loop:
|
||||||
* Pick a uniformly random integer $c$ in $[0,8).$
|
- Pick a uniformly random field element $u.$
|
||||||
* Let $t = G_{c,u}(x).$
|
- Pick a uniformly random integer $c$ in $[0,8).$
|
||||||
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
- Let $t = G_{c,u}(x).$
|
||||||
|
- If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
||||||
|
|
||||||
This is implemented in `secp256k1_ellswift_xelligatorswift_var`.
|
This is implemented in `secp256k1_ellswift_xelligatorswift_var`.
|
||||||
|
|
||||||
@@ -256,18 +269,19 @@ Those are then repeated as $c=4$ through $c=7$ for the other sign of $w$ (noting
|
|||||||
Ignoring the negligible cases, we get:
|
Ignoring the negligible cases, we get:
|
||||||
|
|
||||||
**Define** $G_{c,u}(x)$ as:
|
**Define** $G_{c,u}(x)$ as:
|
||||||
* If $c \in \\{0, 1, 4, 5\\}$ (for $x_1$ and $x_2$ formulas):
|
|
||||||
* If $g(-u-x)$ is square, return $\bot$ (as $x_3$ would be valid and take precedence).
|
- If $c \in \\{0, 1, 4, 5\\}$ (for $x_1$ and $x_2$ formulas):
|
||||||
* If $c \in \\{0, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula)
|
- If $g(-u-x)$ is square, return $\bot$ (as $x_3$ would be valid and take precedence).
|
||||||
* Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows).
|
- If $c \in \\{0, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula)
|
||||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas):
|
- Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows).
|
||||||
* Let $s = x-u.$
|
- Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas):
|
||||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}.$
|
- Let $s = x-u.$
|
||||||
* Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise.
|
- Let $r = \sqrt{-s(4g(u) + sh(u))}.$
|
||||||
* Let $w = \sqrt{s}.$
|
- Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise.
|
||||||
* Depending on $c:$
|
- Let $w = \sqrt{s}.$
|
||||||
* If $c \in \\{0, 1, 2, 3\\}:$ return $P_u^{'-1}(v, w).$
|
- Depending on $c:$
|
||||||
* If $c \in \\{4, 5, 6, 7\\}:$ return $P_u^{'-1}(v, -w).$
|
- If $c \in \\{0, 1, 2, 3\\}:$ return $P_u^{'-1}(v, w).$
|
||||||
|
- If $c \in \\{4, 5, 6, 7\\}:$ return $P_u^{'-1}(v, -w).$
|
||||||
|
|
||||||
Whenever a square root of a non-square is taken, $\bot$ is returned; for both square roots this happens with roughly
|
Whenever a square root of a non-square is taken, $\bot$ is returned; for both square roots this happens with roughly
|
||||||
50% on random inputs. Similarly, when a division by 0 would occur, $\bot$ is returned as well; this will only happen
|
50% on random inputs. Similarly, when a division by 0 would occur, $\bot$ is returned as well; this will only happen
|
||||||
@@ -284,20 +298,21 @@ transformation. Furthermore, that transformation has no effect on $s$ in the fir
|
|||||||
as $u^2 + ux + x^2 + a = u^2 + u(-u-x) + (-u-x)^2 + a.$ Thus we can extract it out and move it down:
|
as $u^2 + ux + x^2 + a = u^2 + u(-u-x) + (-u-x)^2 + a.$ Thus we can extract it out and move it down:
|
||||||
|
|
||||||
**Define** $G_{c,u}(x)$ as:
|
**Define** $G_{c,u}(x)$ as:
|
||||||
* If $c \in \\{0, 1, 4, 5\\}:$
|
|
||||||
* If $g(-u-x)$ is square, return $\bot.$
|
- If $c \in \\{0, 1, 4, 5\\}:$
|
||||||
* Let $s = -g(u)/(u^2 + ux + x^2 + a).$
|
- If $g(-u-x)$ is square, return $\bot.$
|
||||||
* Let $v = x.$
|
- Let $s = -g(u)/(u^2 + ux + x^2 + a).$
|
||||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
- Let $v = x.$
|
||||||
* Let $s = x-u.$
|
- Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
||||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}.$
|
- Let $s = x-u.$
|
||||||
* Let $v = (r/s - u)/2.$
|
- Let $r = \sqrt{-s(4g(u) + sh(u))}.$
|
||||||
* Let $w = \sqrt{s}.$
|
- Let $v = (r/s - u)/2.$
|
||||||
* Depending on $c:$
|
- Let $w = \sqrt{s}.$
|
||||||
* If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$
|
- Depending on $c:$
|
||||||
* If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w).$
|
- If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$
|
||||||
* If $c \in \\{4, 6\\}:$ return $P_u^{'-1}(v, -w).$
|
- If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w).$
|
||||||
* If $c \in \\{5, 7\\}:$ return $P_u^{'-1}(-u-v, -w).$
|
- If $c \in \\{4, 6\\}:$ return $P_u^{'-1}(v, -w).$
|
||||||
|
- If $c \in \\{5, 7\\}:$ return $P_u^{'-1}(-u-v, -w).$
|
||||||
|
|
||||||
This shows there will always be exactly 0, 4, or 8 $t$ values for a given $(u, x)$ input.
|
This shows there will always be exactly 0, 4, or 8 $t$ values for a given $(u, x)$ input.
|
||||||
There can be 0, 1, or 2 $(v, w)$ pairs before invoking $P_u^{'-1}$, and each results in 4 distinct $t$ values.
|
There can be 0, 1, or 2 $(v, w)$ pairs before invoking $P_u^{'-1}$, and each results in 4 distinct $t$ values.
|
||||||
@@ -310,58 +325,60 @@ we analyse them here. They generally fall into two categories: cases in which th
|
|||||||
do not decode back to $x$ (or at least cannot guarantee that they do), and cases in which the encoder might produce the same
|
do not decode back to $x$ (or at least cannot guarantee that they do), and cases in which the encoder might produce the same
|
||||||
$t$ value for multiple $c$ inputs (thereby biasing that encoding):
|
$t$ value for multiple $c$ inputs (thereby biasing that encoding):
|
||||||
|
|
||||||
* In the branch for $x_1$ and $x_2$ (where $c \in \\{0, 1, 4, 5\\}$):
|
- In the branch for $x_1$ and $x_2$ (where $c \in \\{0, 1, 4, 5\\}$):
|
||||||
* When $g(u) = 0$, we would have $s=w=Y=0$, which is not on $S_u.$ This is only possible on even-ordered curves.
|
- When $g(u) = 0$, we would have $s=w=Y=0$, which is not on $S_u.$ This is only possible on even-ordered curves.
|
||||||
Excluding this also removes the one condition under which the simplified check for $x_3$ on the curve
|
Excluding this also removes the one condition under which the simplified check for $x_3$ on the curve
|
||||||
fails (namely when $g(x_1)=g(x_2)=0$ but $g(x_3)$ is not square).
|
fails (namely when $g(x_1)=g(x_2)=0$ but $g(x_3)$ is not square).
|
||||||
This does exclude some valid encodings: when both $g(u)=0$ and $u^2+ux+x^2+a=0$ (also implying $g(x)=0$),
|
This does exclude some valid encodings: when both $g(u)=0$ and $u^2+ux+x^2+a=0$ (also implying $g(x)=0$),
|
||||||
the $S_u'$ equation degenerates to $0 = 0$, and many valid $t$ values may exist. Yet, these cannot be targeted uniformly by the
|
the $S_u'$ equation degenerates to $0 = 0$, and many valid $t$ values may exist. Yet, these cannot be targeted uniformly by the
|
||||||
encoder anyway as there will generally be more than 8.
|
encoder anyway as there will generally be more than 8.
|
||||||
* When $g(x) = 0$, the same $t$ would be produced as in the $x_3$ branch (where $c \in \\{2, 3, 6, 7\\}$) which we give precedence
|
- When $g(x) = 0$, the same $t$ would be produced as in the $x_3$ branch (where $c \in \\{2, 3, 6, 7\\}$) which we give precedence
|
||||||
as it can deal with $g(u)=0$.
|
as it can deal with $g(u)=0$.
|
||||||
This is again only possible on even-ordered curves.
|
This is again only possible on even-ordered curves.
|
||||||
* In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$):
|
- In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$):
|
||||||
* When $s=0$, a division by zero would occur.
|
- When $s=0$, a division by zero would occur.
|
||||||
* When $v = -u-v$ and $c \in \\{3, 7\\}$, the same $t$ would be returned as in the $c \in \\{2, 6\\}$ cases.
|
- When $v = -u-v$ and $c \in \\{3, 7\\}$, the same $t$ would be returned as in the $c \in \\{2, 6\\}$ cases.
|
||||||
It is equivalent to checking whether $r=0$.
|
It is equivalent to checking whether $r=0$.
|
||||||
This cannot occur in the $x_1$ or $x_2$ branches, as it would trigger the $g(-u-x)$ is square condition.
|
This cannot occur in the $x_1$ or $x_2$ branches, as it would trigger the $g(-u-x)$ is square condition.
|
||||||
A similar concern for $w = -w$ does not exist, as $w=0$ is already impossible in both branches: in the first
|
A similar concern for $w = -w$ does not exist, as $w=0$ is already impossible in both branches: in the first
|
||||||
it requires $g(u)=0$ which is already outlawed on even-ordered curves and impossible on others; in the second it would trigger division by zero.
|
it requires $g(u)=0$ which is already outlawed on even-ordered curves and impossible on others; in the second it would trigger division by zero.
|
||||||
* Curve-specific special cases also exist that need to be rejected, because they result in $(u,t)$ which is invalid to the decoder, or because of division by zero in the encoder:
|
- Curve-specific special cases also exist that need to be rejected, because they result in $(u,t)$ which is invalid to the decoder, or because of division by zero in the encoder:
|
||||||
* For $a=0$ curves, when $u=0$ or when $t=0$. The latter can only be reached by the encoder when $g(u)=0$, which requires an even-ordered curve.
|
- For $a=0$ curves, when $u=0$ or when $t=0$. The latter can only be reached by the encoder when $g(u)=0$, which requires an even-ordered curve.
|
||||||
* For $a \neq 0$ curves, when $X_0(u)=0$, when $h(u)t^2 = -1$, or when $w(u + 2v) = 2X_0(u)$ while also either $w \neq 2Y_0(u)$ or $h(u)=0$.
|
- For $a \neq 0$ curves, when $X_0(u)=0$, when $h(u)t^2 = -1$, or when $w(u + 2v) = 2X_0(u)$ while also either $w \neq 2Y_0(u)$ or $h(u)=0$.
|
||||||
|
|
||||||
**Define** a version of $G_{c,u}(x)$ which deals with all these cases:
|
**Define** a version of $G_{c,u}(x)$ which deals with all these cases:
|
||||||
* If $a=0$ and $u=0$, return $\bot.$
|
|
||||||
* If $a \neq 0$ and $X_0(u)=0$, return $\bot.$
|
- If $a=0$ and $u=0$, return $\bot.$
|
||||||
* If $c \in \\{0, 1, 4, 5\\}:$
|
- If $a \neq 0$ and $X_0(u)=0$, return $\bot.$
|
||||||
* If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
|
- If $c \in \\{0, 1, 4, 5\\}:$
|
||||||
* If $g(-u-x)$ is square, return $\bot.$
|
- If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
|
||||||
* Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
|
- If $g(-u-x)$ is square, return $\bot.$
|
||||||
* Let $v = x.$
|
- Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
|
||||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
- Let $v = x.$
|
||||||
* Let $s = x-u.$
|
- Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
||||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
|
- Let $s = x-u.$
|
||||||
* If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
|
- Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
|
||||||
* If $s = 0$, return $\bot.$
|
- If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
|
||||||
* Let $v = (r/s - u)/2.$
|
- If $s = 0$, return $\bot.$
|
||||||
* Let $w = \sqrt{s}$; return $\bot$ if not square.
|
- Let $v = (r/s - u)/2.$
|
||||||
* If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$
|
- Let $w = \sqrt{s}$; return $\bot$ if not square.
|
||||||
* Depending on $c:$
|
- If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$
|
||||||
* If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$
|
- Depending on $c:$
|
||||||
* If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$
|
- If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$
|
||||||
* If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$
|
- If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$
|
||||||
* If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$
|
- If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$
|
||||||
* If $a=0$ and $t=0$, return $\bot$ (even curves only).
|
- If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$
|
||||||
* If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$
|
- If $a=0$ and $t=0$, return $\bot$ (even curves only).
|
||||||
* Return $t.$
|
- If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$
|
||||||
|
- Return $t.$
|
||||||
|
|
||||||
Given any $u$, using this algorithm over all $x$ and $c$ values, every $t$ value will be reached exactly once,
|
Given any $u$, using this algorithm over all $x$ and $c$ values, every $t$ value will be reached exactly once,
|
||||||
for an $x$ for which $F_u(t) = x$ holds, except for these cases that will not be reached:
|
for an $x$ for which $F_u(t) = x$ holds, except for these cases that will not be reached:
|
||||||
* All cases where $P_u(t)$ is not defined:
|
|
||||||
* For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$
|
- All cases where $P_u(t)$ is not defined:
|
||||||
* For $a \neq 0$ curves, when $h(u)t^2 = -1$, $X_0(u) = 0$, or $Y_0(u) (1 - h(u) t^2) = 2X_0(u)t.$
|
- For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$
|
||||||
* When $g(u)=0$, the potentially many $t$ values that decode to an $x$ satisfying $g(x)=0$ using the $x_2$ formula. These were excluded by the $g(u)=0$ condition in the $c \in \\{0, 1, 4, 5\\}$ branch.
|
- For $a \neq 0$ curves, when $h(u)t^2 = -1$, $X_0(u) = 0$, or $Y_0(u) (1 - h(u) t^2) = 2X_0(u)t.$
|
||||||
|
- When $g(u)=0$, the potentially many $t$ values that decode to an $x$ satisfying $g(x)=0$ using the $x_2$ formula. These were excluded by the $g(u)=0$ condition in the $c \in \\{0, 1, 4, 5\\}$ branch.
|
||||||
|
|
||||||
These cases form a negligible subset of all $(u, t)$ for cryptographically sized curves.
|
These cases form a negligible subset of all $(u, t)$ for cryptographically sized curves.
|
||||||
|
|
||||||
@@ -370,40 +387,42 @@ These cases form a negligible subset of all $(u, t)$ for cryptographically sized
|
|||||||
Specialized for odd-ordered $a=0$ curves:
|
Specialized for odd-ordered $a=0$ curves:
|
||||||
|
|
||||||
**Define** $G_{c,u}(x)$ as:
|
**Define** $G_{c,u}(x)$ as:
|
||||||
* If $u=0$, return $\bot.$
|
|
||||||
* If $c \in \\{0, 1, 4, 5\\}:$
|
- If $u=0$, return $\bot.$
|
||||||
* If $(-u-x)^3 + b$ is square, return $\bot$
|
- If $c \in \\{0, 1, 4, 5\\}:$
|
||||||
* Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0).
|
- If $(-u-x)^3 + b$ is square, return $\bot$
|
||||||
* Let $v = x.$
|
- Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0).
|
||||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
- Let $v = x.$
|
||||||
* Let $s = x-u.$
|
- Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
||||||
* Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square.
|
- Let $s = x-u.$
|
||||||
* If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
|
- Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square.
|
||||||
* If $s = 0$, return $\bot.$
|
- If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
|
||||||
* Let $v = (r/s - u)/2.$
|
- If $s = 0$, return $\bot.$
|
||||||
* Let $w = \sqrt{s}$; return $\bot$ if not square.
|
- Let $v = (r/s - u)/2.$
|
||||||
* Depending on $c:$
|
- Let $w = \sqrt{s}$; return $\bot$ if not square.
|
||||||
* If $c \in \\{0, 2\\}:$ return $w(\frac{\sqrt{-3}-1}{2}u - v).$
|
- Depending on $c:$
|
||||||
* If $c \in \\{1, 3\\}:$ return $w(\frac{\sqrt{-3}+1}{2}u + v).$
|
- If $c \in \\{0, 2\\}:$ return $w(\frac{\sqrt{-3}-1}{2}u - v).$
|
||||||
* If $c \in \\{4, 6\\}:$ return $w(\frac{-\sqrt{-3}+1}{2}u + v).$
|
- If $c \in \\{1, 3\\}:$ return $w(\frac{\sqrt{-3}+1}{2}u + v).$
|
||||||
* If $c \in \\{5, 7\\}:$ return $w(\frac{-\sqrt{-3}-1}{2}u - v).$
|
- If $c \in \\{4, 6\\}:$ return $w(\frac{-\sqrt{-3}+1}{2}u + v).$
|
||||||
|
- If $c \in \\{5, 7\\}:$ return $w(\frac{-\sqrt{-3}-1}{2}u - v).$
|
||||||
|
|
||||||
This is implemented in `secp256k1_ellswift_xswiftec_inv_var`.
|
This is implemented in `secp256k1_ellswift_xswiftec_inv_var`.
|
||||||
|
|
||||||
And the x-only ElligatorSwift encoding algorithm is still:
|
And the x-only ElligatorSwift encoding algorithm is still:
|
||||||
|
|
||||||
**Define** *ElligatorSwift(x)* as:
|
**Define** _ElligatorSwift(x)_ as:
|
||||||
* Loop:
|
|
||||||
* Pick a uniformly random field element $u.$
|
- Loop:
|
||||||
* Pick a uniformly random integer $c$ in $[0,8).$
|
- Pick a uniformly random field element $u.$
|
||||||
* Let $t = G_{c,u}(x).$
|
- Pick a uniformly random integer $c$ in $[0,8).$
|
||||||
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
- Let $t = G_{c,u}(x).$
|
||||||
|
- If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
||||||
|
|
||||||
Note that this logic does not take the remapped $u=0$, $t=0$, and $g(u) = -t^2$ cases into account; it just avoids them.
|
Note that this logic does not take the remapped $u=0$, $t=0$, and $g(u) = -t^2$ cases into account; it just avoids them.
|
||||||
While it is not impossible to make the encoder target them, this would increase the maximum number of $t$ values for a given $(u, x)$
|
While it is not impossible to make the encoder target them, this would increase the maximum number of $t$ values for a given $(u, x)$
|
||||||
combination beyond 8, and thereby slow down the ElligatorSwift loop proportionally, for a negligible gain in uniformity.
|
combination beyond 8, and thereby slow down the ElligatorSwift loop proportionally, for a negligible gain in uniformity.
|
||||||
|
|
||||||
## 4. Encoding and decoding full *(x, y)* coordinates
|
## 4. Encoding and decoding full _(x, y)_ coordinates
|
||||||
|
|
||||||
So far we have only addressed encoding and decoding x-coordinates, but in some cases an encoding
|
So far we have only addressed encoding and decoding x-coordinates, but in some cases an encoding
|
||||||
for full points with $(x, y)$ coordinates is desirable. It is possible to encode this information
|
for full points with $(x, y)$ coordinates is desirable. It is possible to encode this information
|
||||||
@@ -422,30 +441,32 @@ four distinct $P_u^{'-1}$ calls in the definition of $G_{u,c}.$
|
|||||||
|
|
||||||
To encode the sign of $y$ in the sign of $Y:$
|
To encode the sign of $y$ in the sign of $Y:$
|
||||||
|
|
||||||
**Define** *Decode(u, t)* for full $(x, y)$ as:
|
**Define** _Decode(u, t)_ for full $(x, y)$ as:
|
||||||
* Let $(X, Y) = P_u(t).$
|
|
||||||
* Let $x$ be the first value in $(u + 4Y^2, \frac{-X}{2Y} - \frac{u}{2}, \frac{X}{2Y} - \frac{u}{2})$ for which $g(x)$ is square.
|
- Let $(X, Y) = P_u(t).$
|
||||||
* Let $y = \sqrt{g(x)}.$
|
- Let $x$ be the first value in $(u + 4Y^2, \frac{-X}{2Y} - \frac{u}{2}, \frac{X}{2Y} - \frac{u}{2})$ for which $g(x)$ is square.
|
||||||
* If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$
|
- Let $y = \sqrt{g(x)}.$
|
||||||
|
- If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$
|
||||||
|
|
||||||
And encoding would be done using a $G_{c,u}(x, y)$ function defined as:
|
And encoding would be done using a $G_{c,u}(x, y)$ function defined as:
|
||||||
|
|
||||||
**Define** $G_{c,u}(x, y)$ as:
|
**Define** $G_{c,u}(x, y)$ as:
|
||||||
* If $c \in \\{0, 1\\}:$
|
|
||||||
* If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
|
- If $c \in \\{0, 1\\}:$
|
||||||
* If $g(-u-x)$ is square, return $\bot.$
|
- If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
|
||||||
* Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
|
- If $g(-u-x)$ is square, return $\bot.$
|
||||||
* Let $v = x.$
|
- Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
|
||||||
* Otherwise, when $c \in \\{2, 3\\}:$
|
- Let $v = x.$
|
||||||
* Let $s = x-u.$
|
- Otherwise, when $c \in \\{2, 3\\}:$
|
||||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
|
- Let $s = x-u.$
|
||||||
* If $c = 3$ and $r = 0$, return $\bot.$
|
- Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
|
||||||
* Let $v = (r/s - u)/2.$
|
- If $c = 3$ and $r = 0$, return $\bot.$
|
||||||
* Let $w = \sqrt{s}$; return $\bot$ if not square.
|
- Let $v = (r/s - u)/2.$
|
||||||
* Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise.
|
- Let $w = \sqrt{s}$; return $\bot$ if not square.
|
||||||
* Depending on $c:$
|
- Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise.
|
||||||
* If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$
|
- Depending on $c:$
|
||||||
* If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$
|
- If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$
|
||||||
|
- If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$
|
||||||
|
|
||||||
Note that $c$ now only ranges $[0,4)$, as the sign of $w'$ is decided based on that of $y$, rather than on $c.$
|
Note that $c$ now only ranges $[0,4)$, as the sign of $w'$ is decided based on that of $y$, rather than on $c.$
|
||||||
This change makes some valid encodings unreachable: when $y = 0$ and $sign(Y) \neq sign(0)$.
|
This change makes some valid encodings unreachable: when $y = 0$ and $sign(Y) \neq sign(0)$.
|
||||||
@@ -454,22 +475,23 @@ In the above logic, $sign$ can be implemented in several ways, such as parity of
|
|||||||
of the input field element (for prime-sized fields) or the quadratic residuosity (for fields where
|
of the input field element (for prime-sized fields) or the quadratic residuosity (for fields where
|
||||||
$-1$ is not square). The choice does not matter, as long as it only takes on two possible values, and for $x \neq 0$ it holds that $sign(x) \neq sign(-x)$.
|
$-1$ is not square). The choice does not matter, as long as it only takes on two possible values, and for $x \neq 0$ it holds that $sign(x) \neq sign(-x)$.
|
||||||
|
|
||||||
### 4.1 Full *(x, y)* coordinates for `secp256k1`
|
### 4.1 Full _(x, y)_ coordinates for `secp256k1`
|
||||||
|
|
||||||
For $a=0$ curves, there is another option. Note that for those,
|
For $a=0$ curves, there is another option. Note that for those,
|
||||||
the $P_u(t)$ function translates negations of $t$ to negations of (both) $X$ and $Y.$ Thus, we can use $sign(t)$ to
|
the $P_u(t)$ function translates negations of $t$ to negations of (both) $X$ and $Y.$ Thus, we can use $sign(t)$ to
|
||||||
encode the y-coordinate directly. Combined with the earlier remapping to guarantee all inputs land on the curve, we get
|
encode the y-coordinate directly. Combined with the earlier remapping to guarantee all inputs land on the curve, we get
|
||||||
as decoder:
|
as decoder:
|
||||||
|
|
||||||
**Define** *Decode(u, t)* as:
|
**Define** _Decode(u, t)_ as:
|
||||||
* Let $u'=u$ if $u \neq 0$; $1$ otherwise.
|
|
||||||
* Let $t'=t$ if $t \neq 0$; $1$ otherwise.
|
- Let $u'=u$ if $u \neq 0$; $1$ otherwise.
|
||||||
* Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise.
|
- Let $t'=t$ if $t \neq 0$; $1$ otherwise.
|
||||||
* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
|
- Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise.
|
||||||
* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
|
- Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
|
||||||
* Let $x$ be the first element of $(u' + 4Y^2, \frac{-X}{2Y} - \frac{u'}{2}, \frac{X}{2Y} - \frac{u'}{2})$ for which $g(x)$ is square.
|
- Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
|
||||||
* Let $y = \sqrt{g(x)}.$
|
- Let $x$ be the first element of $(u' + 4Y^2, \frac{-X}{2Y} - \frac{u'}{2}, \frac{X}{2Y} - \frac{u'}{2})$ for which $g(x)$ is square.
|
||||||
* Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise.
|
- Let $y = \sqrt{g(x)}.$
|
||||||
|
- Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise.
|
||||||
|
|
||||||
This is implemented in `secp256k1_ellswift_swiftec_var`. The used $sign(x)$ function is the parity of $x$ when represented as in integer in $[0,q).$
|
This is implemented in `secp256k1_ellswift_swiftec_var`. The used $sign(x)$ function is the parity of $x$ when represented as in integer in $[0,q).$
|
||||||
|
|
||||||
|
|||||||
3
external/secp256k1/doc/musig.md
vendored
3
external/secp256k1/doc/musig.md
vendored
@@ -1,5 +1,4 @@
|
|||||||
Notes on the musig module API
|
# Notes on the musig module API
|
||||||
===========================
|
|
||||||
|
|
||||||
The following sections contain additional notes on the API of the musig module (`include/secp256k1_musig.h`).
|
The following sections contain additional notes on the API of the musig module (`include/secp256k1_musig.h`).
|
||||||
A usage example can be found in `examples/musig.c`.
|
A usage example can be found in `examples/musig.c`.
|
||||||
|
|||||||
40
external/secp256k1/doc/release-process.md
vendored
40
external/secp256k1/doc/release-process.md
vendored
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`.
|
This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`.
|
||||||
|
|
||||||
We distinguish between two types of releases: *regular* and *maintenance* releases.
|
We distinguish between two types of releases: _regular_ and _maintenance_ releases.
|
||||||
Regular releases are releases of a new major or minor version as well as patches of the most recent release.
|
Regular releases are releases of a new major or minor version as well as patches of the most recent release.
|
||||||
Maintenance releases, on the other hand, are required for patches of older releases.
|
Maintenance releases, on the other hand, are required for patches of older releases.
|
||||||
|
|
||||||
@@ -15,6 +15,7 @@ This process also assumes that there will be no minor releases for old major rel
|
|||||||
We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core.
|
We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core.
|
||||||
|
|
||||||
## Sanity checks
|
## Sanity checks
|
||||||
|
|
||||||
Perform these checks when reviewing the release PR (see below):
|
Perform these checks when reviewing the release PR (see below):
|
||||||
|
|
||||||
1. Ensure `make distcheck` doesn't fail.
|
1. Ensure `make distcheck` doesn't fail.
|
||||||
@@ -42,15 +43,15 @@ Perform these checks when reviewing the release PR (see below):
|
|||||||
## Regular release
|
## Regular release
|
||||||
|
|
||||||
1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that
|
1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that
|
||||||
* finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by
|
- finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by
|
||||||
* adding a section for the release (make sure that the version number is a link to a diff between the previous and new version),
|
- adding a section for the release (make sure that the version number is a link to a diff between the previous and new version),
|
||||||
* removing the `[Unreleased]` section header,
|
- removing the `[Unreleased]` section header,
|
||||||
* ensuring that the release notes are not missing entries (check the `needs-changelog` label on github), and
|
- ensuring that the release notes are not missing entries (check the `needs-changelog` label on github), and
|
||||||
* including an entry for `### ABI Compatibility` if it doesn't exist,
|
- including an entry for `### ABI Compatibility` if it doesn't exist,
|
||||||
* sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and,
|
- sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and,
|
||||||
* if this is not a patch release,
|
- if this is not a patch release,
|
||||||
* updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac`, and
|
- updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac`, and
|
||||||
* updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`.
|
- updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`.
|
||||||
2. Perform the [sanity checks](#sanity-checks) on the PR branch.
|
2. Perform the [sanity checks](#sanity-checks) on the PR branch.
|
||||||
3. After the PR is merged, tag the commit, and push the tag:
|
3. After the PR is merged, tag the commit, and push the tag:
|
||||||
```
|
```
|
||||||
@@ -59,11 +60,12 @@ Perform these checks when reviewing the release PR (see below):
|
|||||||
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
|
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
|
||||||
```
|
```
|
||||||
4. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that
|
4. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that
|
||||||
* sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`,
|
- sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`,
|
||||||
* increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and
|
- increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and
|
||||||
* adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md).
|
- adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md).
|
||||||
|
|
||||||
If other maintainers are not present to approve the PR, it can be merged without ACKs.
|
If other maintainers are not present to approve the PR, it can be merged without ACKs.
|
||||||
|
|
||||||
5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
|
5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
|
||||||
6. Send an announcement email to the bitcoin-dev mailing list.
|
6. Send an announcement email to the bitcoin-dev mailing list.
|
||||||
|
|
||||||
@@ -77,9 +79,9 @@ Note that bug fixes need to be backported only to releases for which no compatib
|
|||||||
git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR
|
git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR
|
||||||
```
|
```
|
||||||
2. Open a pull request to the `$MAJOR.$MINOR` branch that
|
2. Open a pull request to the `$MAJOR.$MINOR` branch that
|
||||||
* includes the bug fixes,
|
- includes the bug fixes,
|
||||||
* finalizes the release notes similar to a regular release,
|
- finalizes the release notes similar to a regular release,
|
||||||
* increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`
|
- increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`
|
||||||
and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`
|
and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`
|
||||||
(with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example).
|
(with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example).
|
||||||
3. Perform the [sanity checks](#sanity-checks) on the PR branch.
|
3. Perform the [sanity checks](#sanity-checks) on the PR branch.
|
||||||
@@ -89,6 +91,6 @@ Note that bug fixes need to be backported only to releases for which no compatib
|
|||||||
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH"
|
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH"
|
||||||
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
|
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
|
||||||
```
|
```
|
||||||
6. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
|
5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
|
||||||
7. Send an announcement email to the bitcoin-dev mailing list.
|
6. Send an announcement email to the bitcoin-dev mailing list.
|
||||||
8. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md).
|
7. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md).
|
||||||
|
|||||||
301
external/secp256k1/doc/safegcd_implementation.md
vendored
301
external/secp256k1/doc/safegcd_implementation.md
vendored
@@ -29,65 +29,67 @@ def gcd(f, g):
|
|||||||
return abs(f)
|
return abs(f)
|
||||||
```
|
```
|
||||||
|
|
||||||
It computes the greatest common divisor of an odd integer *f* and any integer *g*. Its inner loop
|
It computes the greatest common divisor of an odd integer _f_ and any integer _g_. Its inner loop
|
||||||
keeps rewriting the variables *f* and *g* alongside a state variable *δ* that starts at *1*, until
|
keeps rewriting the variables _f_ and _g_ alongside a state variable _δ_ that starts at _1_, until
|
||||||
*g=0* is reached. At that point, *|f|* gives the GCD. Each of the transitions in the loop is called a
|
_g=0_ is reached. At that point, _|f|_ gives the GCD. Each of the transitions in the loop is called a
|
||||||
"division step" (referred to as divstep in what follows).
|
"division step" (referred to as divstep in what follows).
|
||||||
|
|
||||||
For example, *gcd(21, 14)* would be computed as:
|
For example, _gcd(21, 14)_ would be computed as:
|
||||||
- Start with *δ=1 f=21 g=14*
|
|
||||||
- Take the third branch: *δ=2 f=21 g=7*
|
- Start with _δ=1 f=21 g=14_
|
||||||
- Take the first branch: *δ=-1 f=7 g=-7*
|
- Take the third branch: _δ=2 f=21 g=7_
|
||||||
- Take the second branch: *δ=0 f=7 g=0*
|
- Take the first branch: _δ=-1 f=7 g=-7_
|
||||||
- The answer *|f| = 7*.
|
- Take the second branch: _δ=0 f=7 g=0_
|
||||||
|
- The answer _|f| = 7_.
|
||||||
|
|
||||||
Why it works:
|
Why it works:
|
||||||
|
|
||||||
- Divsteps can be decomposed into two steps (see paragraph 8.2 in the paper):
|
- Divsteps can be decomposed into two steps (see paragraph 8.2 in the paper):
|
||||||
- (a) If *g* is odd, replace *(f,g)* with *(g,g-f)* or (f,g+f), resulting in an even *g*.
|
- (a) If _g_ is odd, replace _(f,g)_ with _(g,g-f)_ or (f,g+f), resulting in an even _g_.
|
||||||
- (b) Replace *(f,g)* with *(f,g/2)* (where *g* is guaranteed to be even).
|
- (b) Replace _(f,g)_ with _(f,g/2)_ (where _g_ is guaranteed to be even).
|
||||||
- Neither of those two operations change the GCD:
|
- Neither of those two operations change the GCD:
|
||||||
- For (a), assume *gcd(f,g)=c*, then it must be the case that *f=a c* and *g=b c* for some integers *a*
|
- For (a), assume _gcd(f,g)=c_, then it must be the case that _f=a c_ and _g=b c_ for some integers _a_
|
||||||
and *b*. As *(g,g-f)=(b c,(b-a)c)* and *(f,f+g)=(a c,(a+b)c)*, the result clearly still has
|
and _b_. As _(g,g-f)=(b c,(b-a)c)_ and _(f,f+g)=(a c,(a+b)c)_, the result clearly still has
|
||||||
common factor *c*. Reasoning in the other direction shows that no common factor can be added by
|
common factor _c_. Reasoning in the other direction shows that no common factor can be added by
|
||||||
doing so either.
|
doing so either.
|
||||||
- For (b), we know that *f* is odd, so *gcd(f,g)* clearly has no factor *2*, and we can remove
|
- For (b), we know that _f_ is odd, so _gcd(f,g)_ clearly has no factor _2_, and we can remove
|
||||||
it from *g*.
|
it from _g_.
|
||||||
- The algorithm will eventually converge to *g=0*. This is proven in the paper (see theorem G.3).
|
- The algorithm will eventually converge to _g=0_. This is proven in the paper (see theorem G.3).
|
||||||
- It follows that eventually we find a final value *f'* for which *gcd(f,g) = gcd(f',0)*. As the
|
- It follows that eventually we find a final value _f'_ for which _gcd(f,g) = gcd(f',0)_. As the
|
||||||
gcd of *f'* and *0* is *|f'|* by definition, that is our answer.
|
gcd of _f'_ and _0_ is _|f'|_ by definition, that is our answer.
|
||||||
|
|
||||||
Compared to more [traditional GCD algorithms](https://en.wikipedia.org/wiki/Euclidean_algorithm), this one has the property of only ever looking at
|
Compared to more [traditional GCD algorithms](https://en.wikipedia.org/wiki/Euclidean_algorithm), this one has the property of only ever looking at
|
||||||
the low-order bits of the variables to decide the next steps, and being easy to make
|
the low-order bits of the variables to decide the next steps, and being easy to make
|
||||||
constant-time (in more low-level languages than Python). The *δ* parameter is necessary to
|
constant-time (in more low-level languages than Python). The _δ_ parameter is necessary to
|
||||||
guide the algorithm towards shrinking the numbers' magnitudes without explicitly needing to look
|
guide the algorithm towards shrinking the numbers' magnitudes without explicitly needing to look
|
||||||
at high order bits.
|
at high order bits.
|
||||||
|
|
||||||
Properties that will become important later:
|
Properties that will become important later:
|
||||||
- Performing more divsteps than needed is not a problem, as *f* does not change anymore after *g=0*.
|
|
||||||
- Only even numbers are divided by *2*. This means that when reasoning about it algebraically we
|
|
||||||
do not need to worry about rounding.
|
|
||||||
- At every point during the algorithm's execution the next *N* steps only depend on the bottom *N*
|
|
||||||
bits of *f* and *g*, and on *δ*.
|
|
||||||
|
|
||||||
|
- Performing more divsteps than needed is not a problem, as _f_ does not change anymore after _g=0_.
|
||||||
|
- Only even numbers are divided by _2_. This means that when reasoning about it algebraically we
|
||||||
|
do not need to worry about rounding.
|
||||||
|
- At every point during the algorithm's execution the next _N_ steps only depend on the bottom _N_
|
||||||
|
bits of _f_ and _g_, and on _δ_.
|
||||||
|
|
||||||
## 2. From GCDs to modular inverses
|
## 2. From GCDs to modular inverses
|
||||||
|
|
||||||
We want an algorithm to compute the inverse *a* of *x* modulo *M*, i.e. the number a such that *a x=1
|
We want an algorithm to compute the inverse _a_ of _x_ modulo _M_, i.e. the number a such that _a x=1
|
||||||
mod M*. This inverse only exists if the GCD of *x* and *M* is *1*, but that is always the case if *M* is
|
mod M_. This inverse only exists if the GCD of _x_ and _M_ is _1_, but that is always the case if _M_ is
|
||||||
prime and *0 < x < M*. In what follows, assume that the modular inverse exists.
|
prime and _0 < x < M_. In what follows, assume that the modular inverse exists.
|
||||||
It turns out this inverse can be computed as a side effect of computing the GCD by keeping track
|
It turns out this inverse can be computed as a side effect of computing the GCD by keeping track
|
||||||
of how the internal variables can be written as linear combinations of the inputs at every step
|
of how the internal variables can be written as linear combinations of the inputs at every step
|
||||||
(see the [extended Euclidean algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm)).
|
(see the [extended Euclidean algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm)).
|
||||||
Since the GCD is *1*, such an algorithm will compute numbers *a* and *b* such that a x + b M = 1*.
|
Since the GCD is _1_, such an algorithm will compute numbers _a_ and _b_ such that a x + b M = 1*.
|
||||||
Taking that expression *mod M* gives *a x mod M = 1*, and we see that *a* is the modular inverse of *x
|
Taking that expression *mod M* gives *a x mod M = 1*, and we see that *a* is the modular inverse of *x
|
||||||
mod M*.
|
mod M\*.
|
||||||
|
|
||||||
A similar approach can be used to calculate modular inverses using the divsteps-based GCD
|
A similar approach can be used to calculate modular inverses using the divsteps-based GCD
|
||||||
algorithm shown above, if the modulus *M* is odd. To do so, compute *gcd(f=M,g=x)*, while keeping
|
algorithm shown above, if the modulus _M_ is odd. To do so, compute _gcd(f=M,g=x)_, while keeping
|
||||||
track of extra variables *d* and *e*, for which at every step *d = f/x (mod M)* and *e = g/x (mod M)*.
|
track of extra variables _d_ and _e_, for which at every step _d = f/x (mod M)_ and _e = g/x (mod M)_.
|
||||||
*f/x* here means the number which multiplied with *x* gives *f mod M*. As *f* and *g* are initialized to *M*
|
_f/x_ here means the number which multiplied with _x_ gives _f mod M_. As _f_ and _g_ are initialized to _M_
|
||||||
and *x* respectively, *d* and *e* just start off being *0* (*M/x mod M = 0/x mod M = 0*) and *1* (*x/x mod M
|
and _x_ respectively, _d_ and _e_ just start off being _0_ (_M/x mod M = 0/x mod M = 0_) and _1_ (_x/x mod M
|
||||||
= 1*).
|
= 1_).
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def div2(M, x):
|
def div2(M, x):
|
||||||
@@ -119,17 +121,16 @@ def modinv(M, x):
|
|||||||
return (d * f) % M
|
return (d * f) % M
|
||||||
```
|
```
|
||||||
|
|
||||||
Also note that this approach to track *d* and *e* throughout the computation to determine the inverse
|
Also note that this approach to track _d_ and _e_ throughout the computation to determine the inverse
|
||||||
is different from the paper. There (see paragraph 12.1 in the paper) a transition matrix for the
|
is different from the paper. There (see paragraph 12.1 in the paper) a transition matrix for the
|
||||||
entire computation is determined (see section 3 below) and the inverse is computed from that.
|
entire computation is determined (see section 3 below) and the inverse is computed from that.
|
||||||
The approach here avoids the need for 2x2 matrix multiplications of various sizes, and appears to
|
The approach here avoids the need for 2x2 matrix multiplications of various sizes, and appears to
|
||||||
be faster at the level of optimization we're able to do in C.
|
be faster at the level of optimization we're able to do in C.
|
||||||
|
|
||||||
|
|
||||||
## 3. Batching multiple divsteps
|
## 3. Batching multiple divsteps
|
||||||
|
|
||||||
Every divstep can be expressed as a matrix multiplication, applying a transition matrix *(1/2 t)*
|
Every divstep can be expressed as a matrix multiplication, applying a transition matrix _(1/2 t)_
|
||||||
to both vectors *[f, g]* and *[d, e]* (see paragraph 8.1 in the paper):
|
to both vectors _[f, g]_ and _[d, e]_ (see paragraph 8.1 in the paper):
|
||||||
|
|
||||||
```
|
```
|
||||||
t = [ u, v ]
|
t = [ u, v ]
|
||||||
@@ -142,15 +143,15 @@ to both vectors *[f, g]* and *[d, e]* (see paragraph 8.1 in the paper):
|
|||||||
[ out_e ] [ in_e ]
|
[ out_e ] [ in_e ]
|
||||||
```
|
```
|
||||||
|
|
||||||
where *(u, v, q, r)* is *(0, 2, -1, 1)*, *(2, 0, 1, 1)*, or *(2, 0, 0, 1)*, depending on which branch is
|
where _(u, v, q, r)_ is _(0, 2, -1, 1)_, _(2, 0, 1, 1)_, or _(2, 0, 0, 1)_, depending on which branch is
|
||||||
taken. As above, the resulting *f* and *g* are always integers.
|
taken. As above, the resulting _f_ and _g_ are always integers.
|
||||||
|
|
||||||
Performing multiple divsteps corresponds to a multiplication with the product of all the
|
Performing multiple divsteps corresponds to a multiplication with the product of all the
|
||||||
individual divsteps' transition matrices. As each transition matrix consists of integers
|
individual divsteps' transition matrices. As each transition matrix consists of integers
|
||||||
divided by *2*, the product of these matrices will consist of integers divided by *2<sup>N</sup>* (see also
|
divided by _2_, the product of these matrices will consist of integers divided by _2<sup>N</sup>_ (see also
|
||||||
theorem 9.2 in the paper). These divisions are expensive when updating *d* and *e*, so we delay
|
theorem 9.2 in the paper). These divisions are expensive when updating _d_ and _e_, so we delay
|
||||||
them: we compute the integer coefficients of the combined transition matrix scaled by *2<sup>N</sup>*, and
|
them: we compute the integer coefficients of the combined transition matrix scaled by _2<sup>N</sup>_, and
|
||||||
do one division by *2<sup>N</sup>* as a final step:
|
do one division by _2<sup>N</sup>_ as a final step:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def divsteps_n_matrix(delta, f, g):
|
def divsteps_n_matrix(delta, f, g):
|
||||||
@@ -166,13 +167,13 @@ def divsteps_n_matrix(delta, f, g):
|
|||||||
return delta, (u, v, q, r)
|
return delta, (u, v, q, r)
|
||||||
```
|
```
|
||||||
|
|
||||||
As the branches in the divsteps are completely determined by the bottom *N* bits of *f* and *g*, this
|
As the branches in the divsteps are completely determined by the bottom _N_ bits of _f_ and _g_, this
|
||||||
function to compute the transition matrix only needs to see those bottom bits. Furthermore all
|
function to compute the transition matrix only needs to see those bottom bits. Furthermore all
|
||||||
intermediate results and outputs fit in *(N+1)*-bit numbers (unsigned for *f* and *g*; signed for *u*, *v*,
|
intermediate results and outputs fit in _(N+1)_-bit numbers (unsigned for _f_ and _g_; signed for _u_, _v_,
|
||||||
*q*, and *r*) (see also paragraph 8.3 in the paper). This means that an implementation using 64-bit
|
_q_, and _r_) (see also paragraph 8.3 in the paper). This means that an implementation using 64-bit
|
||||||
integers could set *N=62* and compute the full transition matrix for 62 steps at once without any
|
integers could set _N=62_ and compute the full transition matrix for 62 steps at once without any
|
||||||
big integer arithmetic at all. This is the reason why this algorithm is efficient: it only needs
|
big integer arithmetic at all. This is the reason why this algorithm is efficient: it only needs
|
||||||
to update the full-size *f*, *g*, *d*, and *e* numbers once every *N* steps.
|
to update the full-size _f_, _g_, _d_, and _e_ numbers once every _N_ steps.
|
||||||
|
|
||||||
We still need functions to compute:
|
We still need functions to compute:
|
||||||
|
|
||||||
@@ -184,8 +185,8 @@ We still need functions to compute:
|
|||||||
[ out_e ] ( [ q, r ]) [ in_e ]
|
[ out_e ] ( [ q, r ]) [ in_e ]
|
||||||
```
|
```
|
||||||
|
|
||||||
Because the divsteps transformation only ever divides even numbers by two, the result of *t [f,g]* is always even. When *t* is a composition of *N* divsteps, it follows that the resulting *f*
|
Because the divsteps transformation only ever divides even numbers by two, the result of _t [f,g]_ is always even. When _t_ is a composition of _N_ divsteps, it follows that the resulting _f_
|
||||||
and *g* will be multiple of *2<sup>N</sup>*, and division by *2<sup>N</sup>* is simply shifting them down:
|
and _g_ will be multiple of _2<sup>N</sup>_, and division by _2<sup>N</sup>_ is simply shifting them down:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def update_fg(f, g, t):
|
def update_fg(f, g, t):
|
||||||
@@ -199,8 +200,8 @@ def update_fg(f, g, t):
|
|||||||
return cf >> N, cg >> N
|
return cf >> N, cg >> N
|
||||||
```
|
```
|
||||||
|
|
||||||
The same is not true for *d* and *e*, and we need an equivalent of the `div2` function for division by *2<sup>N</sup> mod M*.
|
The same is not true for _d_ and _e_, and we need an equivalent of the `div2` function for division by _2<sup>N</sup> mod M_.
|
||||||
This is easy if we have precomputed *1/M mod 2<sup>N</sup>* (which always exists for odd *M*):
|
This is easy if we have precomputed _1/M mod 2<sup>N</sup>_ (which always exists for odd _M_):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def div2n(M, Mi, x):
|
def div2n(M, Mi, x):
|
||||||
@@ -224,7 +225,7 @@ def update_de(d, e, t, M, Mi):
|
|||||||
return div2n(M, Mi, cd), div2n(M, Mi, ce)
|
return div2n(M, Mi, cd), div2n(M, Mi, ce)
|
||||||
```
|
```
|
||||||
|
|
||||||
With all of those, we can write a version of `modinv` that performs *N* divsteps at once:
|
With all of those, we can write a version of `modinv` that performs _N_ divsteps at once:
|
||||||
|
|
||||||
```python3
|
```python3
|
||||||
def modinv(M, Mi, x):
|
def modinv(M, Mi, x):
|
||||||
@@ -242,20 +243,19 @@ def modinv(M, Mi, x):
|
|||||||
return (d * f) % M
|
return (d * f) % M
|
||||||
```
|
```
|
||||||
|
|
||||||
This means that in practice we'll always perform a multiple of *N* divsteps. This is not a problem
|
This means that in practice we'll always perform a multiple of _N_ divsteps. This is not a problem
|
||||||
because once *g=0*, further divsteps do not affect *f*, *g*, *d*, or *e* anymore (only *δ* keeps
|
because once _g=0_, further divsteps do not affect _f_, _g_, _d_, or _e_ anymore (only _δ_ keeps
|
||||||
increasing). For variable time code such excess iterations will be mostly optimized away in later
|
increasing). For variable time code such excess iterations will be mostly optimized away in later
|
||||||
sections.
|
sections.
|
||||||
|
|
||||||
|
|
||||||
## 4. Avoiding modulus operations
|
## 4. Avoiding modulus operations
|
||||||
|
|
||||||
So far, there are two places where we compute a remainder of big numbers modulo *M*: at the end of
|
So far, there are two places where we compute a remainder of big numbers modulo _M_: at the end of
|
||||||
`div2n` in every `update_de`, and at the very end of `modinv` after potentially negating *d* due to the
|
`div2n` in every `update_de`, and at the very end of `modinv` after potentially negating _d_ due to the
|
||||||
sign of *f*. These are relatively expensive operations when done generically.
|
sign of _f_. These are relatively expensive operations when done generically.
|
||||||
|
|
||||||
To deal with the modulus operation in `div2n`, we simply stop requiring *d* and *e* to be in range
|
To deal with the modulus operation in `div2n`, we simply stop requiring _d_ and _e_ to be in range
|
||||||
*[0,M)* all the time. Let's start by inlining `div2n` into `update_de`, and dropping the modulus
|
_[0,M)_ all the time. Let's start by inlining `div2n` into `update_de`, and dropping the modulus
|
||||||
operation at the end:
|
operation at the end:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -272,15 +272,15 @@ def update_de(d, e, t, M, Mi):
|
|||||||
return cd >> N, ce >> N
|
return cd >> N, ce >> N
|
||||||
```
|
```
|
||||||
|
|
||||||
Let's look at bounds on the ranges of these numbers. It can be shown that *|u|+|v|* and *|q|+|r|*
|
Let's look at bounds on the ranges of these numbers. It can be shown that _|u|+|v|_ and _|q|+|r|_
|
||||||
never exceed *2<sup>N</sup>* (see paragraph 8.3 in the paper), and thus a multiplication with *t* will have
|
never exceed _2<sup>N</sup>_ (see paragraph 8.3 in the paper), and thus a multiplication with _t_ will have
|
||||||
outputs whose absolute values are at most *2<sup>N</sup>* times the maximum absolute input value. In case the
|
outputs whose absolute values are at most _2<sup>N</sup>_ times the maximum absolute input value. In case the
|
||||||
inputs *d* and *e* are in *(-M,M)*, which is certainly true for the initial values *d=0* and *e=1* assuming
|
inputs _d_ and _e_ are in _(-M,M)_, which is certainly true for the initial values _d=0_ and _e=1_ assuming
|
||||||
*M > 1*, the multiplication results in numbers in range *(-2<sup>N</sup>M,2<sup>N</sup>M)*. Subtracting less than *2<sup>N</sup>*
|
_M > 1_, the multiplication results in numbers in range _(-2<sup>N</sup>M,2<sup>N</sup>M)_. Subtracting less than _2<sup>N</sup>_
|
||||||
times *M* to cancel out *N* bits brings that up to *(-2<sup>N+1</sup>M,2<sup>N</sup>M)*, and
|
times _M_ to cancel out _N_ bits brings that up to _(-2<sup>N+1</sup>M,2<sup>N</sup>M)_, and
|
||||||
dividing by *2<sup>N</sup>* at the end takes it to *(-2M,M)*. Another application of `update_de` would take that
|
dividing by _2<sup>N</sup>_ at the end takes it to _(-2M,M)_. Another application of `update_de` would take that
|
||||||
to *(-3M,2M)*, and so forth. This progressive expansion of the variables' ranges can be
|
to _(-3M,2M)_, and so forth. This progressive expansion of the variables' ranges can be
|
||||||
counteracted by incrementing *d* and *e* by *M* whenever they're negative:
|
counteracted by incrementing _d_ and _e_ by _M_ whenever they're negative:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
...
|
...
|
||||||
@@ -293,12 +293,12 @@ counteracted by incrementing *d* and *e* by *M* whenever they're negative:
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
With inputs in *(-2M,M)*, they will first be shifted into range *(-M,M)*, which means that the
|
With inputs in _(-2M,M)_, they will first be shifted into range _(-M,M)_, which means that the
|
||||||
output will again be in *(-2M,M)*, and this remains the case regardless of how many `update_de`
|
output will again be in _(-2M,M)_, and this remains the case regardless of how many `update_de`
|
||||||
invocations there are. In what follows, we will try to make this more efficient.
|
invocations there are. In what follows, we will try to make this more efficient.
|
||||||
|
|
||||||
Note that increasing *d* by *M* is equal to incrementing *cd* by *u M* and *ce* by *q M*. Similarly,
|
Note that increasing _d_ by _M_ is equal to incrementing _cd_ by _u M_ and _ce_ by _q M_. Similarly,
|
||||||
increasing *e* by *M* is equal to incrementing *cd* by *v M* and *ce* by *r M*. So we could instead write:
|
increasing _e_ by _M_ is equal to incrementing _cd_ by _v M_ and _ce_ by _r M_. So we could instead write:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
...
|
...
|
||||||
@@ -318,10 +318,10 @@ increasing *e* by *M* is equal to incrementing *cd* by *v M* and *ce* by
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
Now note that we have two steps of corrections to *cd* and *ce* that add multiples of *M*: this
|
Now note that we have two steps of corrections to _cd_ and _ce_ that add multiples of _M_: this
|
||||||
increment, and the decrement that cancels out bottom bits. The second one depends on the first
|
increment, and the decrement that cancels out bottom bits. The second one depends on the first
|
||||||
one, but they can still be efficiently combined by only computing the bottom bits of *cd* and *ce*
|
one, but they can still be efficiently combined by only computing the bottom bits of _cd_ and _ce_
|
||||||
at first, and using that to compute the final *md*, *me* values:
|
at first, and using that to compute the final _md_, _me_ values:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def update_de(d, e, t, M, Mi):
|
def update_de(d, e, t, M, Mi):
|
||||||
@@ -346,8 +346,8 @@ def update_de(d, e, t, M, Mi):
|
|||||||
return cd >> N, ce >> N
|
return cd >> N, ce >> N
|
||||||
```
|
```
|
||||||
|
|
||||||
One last optimization: we can avoid the *md M* and *me M* multiplications in the bottom bits of *cd*
|
One last optimization: we can avoid the _md M_ and _me M_ multiplications in the bottom bits of _cd_
|
||||||
and *ce* by moving them to the *md* and *me* correction:
|
and _ce_ by moving them to the _md_ and _me_ correction:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
...
|
...
|
||||||
@@ -362,10 +362,10 @@ and *ce* by moving them to the *md* and *me* correction:
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
The resulting function takes *d* and *e* in range *(-2M,M)* as inputs, and outputs values in the same
|
The resulting function takes _d_ and _e_ in range _(-2M,M)_ as inputs, and outputs values in the same
|
||||||
range. That also means that the *d* value at the end of `modinv` will be in that range, while we want
|
range. That also means that the _d_ value at the end of `modinv` will be in that range, while we want
|
||||||
a result in *[0,M)*. To do that, we need a normalization function. It's easy to integrate the
|
a result in _[0,M)_. To do that, we need a normalization function. It's easy to integrate the
|
||||||
conditional negation of *d* (based on the sign of *f*) into it as well:
|
conditional negation of _d_ (based on the sign of _f_) into it as well:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def normalize(sign, v, M):
|
def normalize(sign, v, M):
|
||||||
@@ -391,22 +391,21 @@ And calling it in `modinv` is simply:
|
|||||||
return normalize(f, d, M)
|
return normalize(f, d, M)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## 5. Constant-time operation
|
## 5. Constant-time operation
|
||||||
|
|
||||||
The primary selling point of the algorithm is fast constant-time operation. What code flow still
|
The primary selling point of the algorithm is fast constant-time operation. What code flow still
|
||||||
depends on the input data so far?
|
depends on the input data so far?
|
||||||
|
|
||||||
- the number of iterations of the while *g ≠ 0* loop in `modinv`
|
- the number of iterations of the while _g ≠ 0_ loop in `modinv`
|
||||||
- the branches inside `divsteps_n_matrix`
|
- the branches inside `divsteps_n_matrix`
|
||||||
- the sign checks in `update_de`
|
- the sign checks in `update_de`
|
||||||
- the sign checks in `normalize`
|
- the sign checks in `normalize`
|
||||||
|
|
||||||
To make the while loop in `modinv` constant time it can be replaced with a constant number of
|
To make the while loop in `modinv` constant time it can be replaced with a constant number of
|
||||||
iterations. The paper proves (Theorem 11.2) that *741* divsteps are sufficient for any *256*-bit
|
iterations. The paper proves (Theorem 11.2) that _741_ divsteps are sufficient for any _256_-bit
|
||||||
inputs, and [safegcd-bounds](https://github.com/sipa/safegcd-bounds) shows that the slightly better bound *724* is
|
inputs, and [safegcd-bounds](https://github.com/sipa/safegcd-bounds) shows that the slightly better bound _724_ is
|
||||||
sufficient even. Given that every loop iteration performs *N* divsteps, it will run a total of
|
sufficient even. Given that every loop iteration performs _N_ divsteps, it will run a total of
|
||||||
*⌈724/N⌉* times.
|
_⌈724/N⌉_ times.
|
||||||
|
|
||||||
To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise
|
To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise
|
||||||
operations (and hope the C compiler isn't smart enough to turn them back into branches; see
|
operations (and hope the C compiler isn't smart enough to turn them back into branches; see
|
||||||
@@ -425,10 +424,10 @@ divstep can be written instead as (compare to the inner loop of `gcd` in section
|
|||||||
```
|
```
|
||||||
|
|
||||||
To convert the above to bitwise operations, we rely on a trick to negate conditionally: per the
|
To convert the above to bitwise operations, we rely on a trick to negate conditionally: per the
|
||||||
definition of negative numbers in two's complement, (*-v == ~v + 1*) holds for every number *v*. As
|
definition of negative numbers in two's complement, (_-v == ~v + 1_) holds for every number _v_. As
|
||||||
*-1* in two's complement is all *1* bits, bitflipping can be expressed as xor with *-1*. It follows
|
_-1_ in two's complement is all _1_ bits, bitflipping can be expressed as xor with _-1_. It follows
|
||||||
that *-v == (v ^ -1) - (-1)*. Thus, if we have a variable *c* that takes on values *0* or *-1*, then
|
that _-v == (v ^ -1) - (-1)_. Thus, if we have a variable _c_ that takes on values _0_ or _-1_, then
|
||||||
*(v ^ c) - c* is *v* if *c=0* and *-v* if *c=-1*.
|
_(v ^ c) - c_ is _v_ if _c=0_ and _-v_ if _c=-1_.
|
||||||
|
|
||||||
Using this we can write:
|
Using this we can write:
|
||||||
|
|
||||||
@@ -444,13 +443,13 @@ in constant-time form as:
|
|||||||
x = (f ^ c1) - c1
|
x = (f ^ c1) - c1
|
||||||
```
|
```
|
||||||
|
|
||||||
To use that trick, we need a helper mask variable *c1* that resolves the condition *δ>0* to *-1*
|
To use that trick, we need a helper mask variable _c1_ that resolves the condition _δ>0_ to _-1_
|
||||||
(if true) or *0* (if false). We compute *c1* using right shifting, which is equivalent to dividing by
|
(if true) or _0_ (if false). We compute _c1_ using right shifting, which is equivalent to dividing by
|
||||||
the specified power of *2* and rounding down (in Python, and also in C under the assumption of a typical two's complement system; see
|
the specified power of _2_ and rounding down (in Python, and also in C under the assumption of a typical two's complement system; see
|
||||||
`assumptions.h` for tests that this is the case). Right shifting by *63* thus maps all
|
`assumptions.h` for tests that this is the case). Right shifting by _63_ thus maps all
|
||||||
numbers in range *[-2<sup>63</sup>,0)* to *-1*, and numbers in range *[0,2<sup>63</sup>)* to *0*.
|
numbers in range _[-2<sup>63</sup>,0)_ to _-1_, and numbers in range _[0,2<sup>63</sup>)_ to _0_.
|
||||||
|
|
||||||
Using the facts that *x&0=0* and *x&(-1)=x* (on two's complement systems again), we can write:
|
Using the facts that _x&0=0_ and _x&(-1)=x_ (on two's complement systems again), we can write:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
if g & 1:
|
if g & 1:
|
||||||
@@ -498,8 +497,8 @@ becomes:
|
|||||||
```
|
```
|
||||||
|
|
||||||
It turns out that this can be implemented more efficiently by applying the substitution
|
It turns out that this can be implemented more efficiently by applying the substitution
|
||||||
*η=-δ*. In this representation, negating *δ* corresponds to negating *η*, and incrementing
|
_η=-δ_. In this representation, negating _δ_ corresponds to negating _η_, and incrementing
|
||||||
*δ* corresponds to decrementing *η*. This allows us to remove the negation in the *c1*
|
_δ_ corresponds to decrementing _η_. This allows us to remove the negation in the _c1_
|
||||||
computation:
|
computation:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -519,12 +518,12 @@ computation:
|
|||||||
g >>= 1
|
g >>= 1
|
||||||
```
|
```
|
||||||
|
|
||||||
A variant of divsteps with better worst-case performance can be used instead: starting *δ* at
|
A variant of divsteps with better worst-case performance can be used instead: starting _δ_ at
|
||||||
*1/2* instead of *1*. This reduces the worst case number of iterations to *590* for *256*-bit inputs
|
_1/2_ instead of _1_. This reduces the worst case number of iterations to _590_ for _256_-bit inputs
|
||||||
(which can be shown using convex hull analysis). In this case, the substitution *ζ=-(δ+1/2)*
|
(which can be shown using convex hull analysis). In this case, the substitution _ζ=-(δ+1/2)_
|
||||||
is used instead to keep the variable integral. Incrementing *δ* by *1* still translates to
|
is used instead to keep the variable integral. Incrementing _δ_ by _1_ still translates to
|
||||||
decrementing *ζ* by *1*, but negating *δ* now corresponds to going from *ζ* to *-(ζ+1)*, or
|
decrementing _ζ_ by _1_, but negating _δ_ now corresponds to going from _ζ_ to _-(ζ+1)_, or
|
||||||
*~ζ*. Doing that conditionally based on *c3* is simply:
|
_~ζ_. Doing that conditionally based on _c3_ is simply:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
...
|
...
|
||||||
@@ -534,13 +533,12 @@ decrementing *ζ* by *1*, but negating *δ* now corresponds to going fr
|
|||||||
```
|
```
|
||||||
|
|
||||||
By replacing the loop in `divsteps_n_matrix` with a variant of the divstep code above (extended to
|
By replacing the loop in `divsteps_n_matrix` with a variant of the divstep code above (extended to
|
||||||
also apply all *f* operations to *u*, *v* and all *g* operations to *q*, *r*), a constant-time version of
|
also apply all _f_ operations to _u_, _v_ and all _g_ operations to _q_, _r_), a constant-time version of
|
||||||
`divsteps_n_matrix` is obtained. The full code will be in section 7.
|
`divsteps_n_matrix` is obtained. The full code will be in section 7.
|
||||||
|
|
||||||
These bit fiddling tricks can also be used to make the conditional negations and additions in
|
These bit fiddling tricks can also be used to make the conditional negations and additions in
|
||||||
`update_de` and `normalize` constant-time.
|
`update_de` and `normalize` constant-time.
|
||||||
|
|
||||||
|
|
||||||
## 6. Variable-time optimizations
|
## 6. Variable-time optimizations
|
||||||
|
|
||||||
In section 5, we modified the `divsteps_n_matrix` function (and a few others) to be constant time.
|
In section 5, we modified the `divsteps_n_matrix` function (and a few others) to be constant time.
|
||||||
@@ -550,7 +548,7 @@ faster non-constant time `divsteps_n_matrix` function.
|
|||||||
|
|
||||||
To do so, first consider yet another way of writing the inner loop of divstep operations in
|
To do so, first consider yet another way of writing the inner loop of divstep operations in
|
||||||
`gcd` from section 1. This decomposition is also explained in the paper in section 8.2. We use
|
`gcd` from section 1. This decomposition is also explained in the paper in section 8.2. We use
|
||||||
the original version with initial *δ=1* and *η=-δ* here.
|
the original version with initial _δ=1_ and _η=-δ_ here.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
for _ in range(N):
|
for _ in range(N):
|
||||||
@@ -562,7 +560,7 @@ for _ in range(N):
|
|||||||
g >>= 1
|
g >>= 1
|
||||||
```
|
```
|
||||||
|
|
||||||
Whenever *g* is even, the loop only shifts *g* down and decreases *η*. When *g* ends in multiple zero
|
Whenever _g_ is even, the loop only shifts _g_ down and decreases _η_. When _g_ ends in multiple zero
|
||||||
bits, these iterations can be consolidated into one step. This requires counting the bottom zero
|
bits, these iterations can be consolidated into one step. This requires counting the bottom zero
|
||||||
bits efficiently, which is possible on most platforms; it is abstracted here as the function
|
bits efficiently, which is possible on most platforms; it is abstracted here as the function
|
||||||
`count_trailing_zeros`.
|
`count_trailing_zeros`.
|
||||||
@@ -595,20 +593,20 @@ while True:
|
|||||||
# g is even now, and the eta decrement and g shift will happen in the next loop.
|
# g is even now, and the eta decrement and g shift will happen in the next loop.
|
||||||
```
|
```
|
||||||
|
|
||||||
We can now remove multiple bottom *0* bits from *g* at once, but still need a full iteration whenever
|
We can now remove multiple bottom _0_ bits from _g_ at once, but still need a full iteration whenever
|
||||||
there is a bottom *1* bit. In what follows, we will get rid of multiple *1* bits simultaneously as
|
there is a bottom _1_ bit. In what follows, we will get rid of multiple _1_ bits simultaneously as
|
||||||
well.
|
well.
|
||||||
|
|
||||||
Observe that as long as *η ≥ 0*, the loop does not modify *f*. Instead, it cancels out bottom
|
Observe that as long as _η ≥ 0_, the loop does not modify _f_. Instead, it cancels out bottom
|
||||||
bits of *g* and shifts them out, and decreases *η* and *i* accordingly - interrupting only when *η*
|
bits of _g_ and shifts them out, and decreases _η_ and _i_ accordingly - interrupting only when _η_
|
||||||
becomes negative, or when *i* reaches *0*. Combined, this is equivalent to adding a multiple of *f* to
|
becomes negative, or when _i_ reaches _0_. Combined, this is equivalent to adding a multiple of _f_ to
|
||||||
*g* to cancel out multiple bottom bits, and then shifting them out.
|
_g_ to cancel out multiple bottom bits, and then shifting them out.
|
||||||
|
|
||||||
It is easy to find what that multiple is: we want a number *w* such that *g+w f* has a few bottom
|
It is easy to find what that multiple is: we want a number _w_ such that _g+w f_ has a few bottom
|
||||||
zero bits. If that number of bits is *L*, we want *g+w f mod 2<sup>L</sup> = 0*, or *w = -g/f mod 2<sup>L</sup>*. Since *f*
|
zero bits. If that number of bits is _L_, we want _g+w f mod 2<sup>L</sup> = 0_, or _w = -g/f mod 2<sup>L</sup>_. Since _f_
|
||||||
is odd, such a *w* exists for any *L*. *L* cannot be more than *i* steps (as we'd finish the loop before
|
is odd, such a _w_ exists for any _L_. _L_ cannot be more than _i_ steps (as we'd finish the loop before
|
||||||
doing more) or more than *η+1* steps (as we'd run `eta, f, g = -eta, g, -f` at that point), but
|
doing more) or more than _η+1_ steps (as we'd run `eta, f, g = -eta, g, -f` at that point), but
|
||||||
apart from that, we're only limited by the complexity of computing *w*.
|
apart from that, we're only limited by the complexity of computing _w_.
|
||||||
|
|
||||||
This code demonstrates how to cancel up to 4 bits per step:
|
This code demonstrates how to cancel up to 4 bits per step:
|
||||||
|
|
||||||
@@ -642,26 +640,25 @@ some can be found in Hacker's Delight second edition by Henry S. Warren, Jr. pag
|
|||||||
Here we need the negated modular inverse, which is a simple transformation of those:
|
Here we need the negated modular inverse, which is a simple transformation of those:
|
||||||
|
|
||||||
- Instead of a 3-bit table:
|
- Instead of a 3-bit table:
|
||||||
- *-f* or *f ^ 6*
|
- _-f_ or _f ^ 6_
|
||||||
- Instead of a 4-bit table:
|
- Instead of a 4-bit table:
|
||||||
- *1 - f(f + 1)*
|
- _1 - f(f + 1)_
|
||||||
- *-(f + (((f + 1) & 4) << 1))*
|
- _-(f + (((f + 1) & 4) << 1))_
|
||||||
- For larger tables the following technique can be used: if *w=-1/f mod 2<sup>L</sup>*, then *w(w f+2)* is
|
- For larger tables the following technique can be used: if _w=-1/f mod 2<sup>L</sup>_, then _w(w f+2)_ is
|
||||||
*-1/f mod 2<sup>2L</sup>*. This allows extending the previous formulas (or tables). In particular we
|
_-1/f mod 2<sup>2L</sup>_. This allows extending the previous formulas (or tables). In particular we
|
||||||
have this 6-bit function (based on the 3-bit function above):
|
have this 6-bit function (based on the 3-bit function above):
|
||||||
- *f(f<sup>2</sup> - 2)*
|
- _f(f<sup>2</sup> - 2)_
|
||||||
|
|
||||||
This loop, again extended to also handle *u*, *v*, *q*, and *r* alongside *f* and *g*, placed in
|
This loop, again extended to also handle _u_, _v_, _q_, and _r_ alongside _f_ and _g_, placed in
|
||||||
`divsteps_n_matrix`, gives a significantly faster, but non-constant time version.
|
`divsteps_n_matrix`, gives a significantly faster, but non-constant time version.
|
||||||
|
|
||||||
|
|
||||||
## 7. Final Python version
|
## 7. Final Python version
|
||||||
|
|
||||||
All together we need the following functions:
|
All together we need the following functions:
|
||||||
|
|
||||||
- A way to compute the transition matrix in constant time, using the `divsteps_n_matrix` function
|
- A way to compute the transition matrix in constant time, using the `divsteps_n_matrix` function
|
||||||
from section 2, but with its loop replaced by a variant of the constant-time divstep from
|
from section 2, but with its loop replaced by a variant of the constant-time divstep from
|
||||||
section 5, extended to handle *u*, *v*, *q*, *r*:
|
section 5, extended to handle _u_, _v_, _q_, _r_:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def divsteps_n_matrix(zeta, f, g):
|
def divsteps_n_matrix(zeta, f, g):
|
||||||
@@ -684,7 +681,7 @@ def divsteps_n_matrix(zeta, f, g):
|
|||||||
return zeta, (u, v, q, r)
|
return zeta, (u, v, q, r)
|
||||||
```
|
```
|
||||||
|
|
||||||
- The functions to update *f* and *g*, and *d* and *e*, from section 2 and section 4, with the constant-time
|
- The functions to update _f_ and _g_, and _d_ and _e_, from section 2 and section 4, with the constant-time
|
||||||
changes to `update_de` from section 5:
|
changes to `update_de` from section 5:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -723,7 +720,7 @@ def normalize(sign, v, M):
|
|||||||
return v
|
return v
|
||||||
```
|
```
|
||||||
|
|
||||||
- And finally the `modinv` function too, adapted to use *ζ* instead of *δ*, and using the fixed
|
- And finally the `modinv` function too, adapted to use _ζ_ instead of _δ_, and using the fixed
|
||||||
iteration count from section 5:
|
iteration count from section 5:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -772,20 +769,21 @@ def modinv_var(M, Mi, x):
|
|||||||
|
|
||||||
## 8. From GCDs to Jacobi symbol
|
## 8. From GCDs to Jacobi symbol
|
||||||
|
|
||||||
We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an
|
We can also use a similar approach to calculate Jacobi symbol _(x | M)_ by keeping track of an
|
||||||
extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we
|
extra variable _j_, for which at every step _(x | M) = j (g | f)_. As we update _f_ and _g_, we
|
||||||
make corresponding updates to *j* using
|
make corresponding updates to _j_ using
|
||||||
[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties):
|
[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties):
|
||||||
* *((g/2) | f)* is either *(g | f)* or *-(g | f)*, depending on the value of *f mod 8* (negating if it's *3* or *5*).
|
|
||||||
* *(f | g)* is either *(g | f)* or *-(g | f)*, depending on *f mod 4* and *g mod 4* (negating if both are *3*).
|
|
||||||
|
|
||||||
These updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied
|
- _((g/2) | f)_ is either _(g | f)_ or _-(g | f)_, depending on the value of _f mod 8_ (negating if it's _3_ or _5_).
|
||||||
very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this
|
- _(f | g)_ is either _(g | f)_ or _-(g | f)_, depending on _f mod 4_ and _g mod 4_ (negating if both are _3_).
|
||||||
|
|
||||||
|
These updates depend only on the values of _f_ and _g_ modulo _4_ or _8_, and can thus be applied
|
||||||
|
very quickly, as long as we keep track of a few additional bits of _f_ and _g_. Overall, this
|
||||||
calculation is slightly simpler than the one for the modular inverse because we no longer need to
|
calculation is slightly simpler than the one for the modular inverse because we no longer need to
|
||||||
keep track of *d* and *e*.
|
keep track of _d_ and _e_.
|
||||||
|
|
||||||
However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for
|
However, one difficulty of this approach is that the Jacobi symbol _(a | n)_ is only defined for
|
||||||
positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative
|
positive odd integers _n_, whereas in the original safegcd algorithm, _f, g_ can take negative
|
||||||
values. We resolve this by using the following modified steps:
|
values. We resolve this by using the following modified steps:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -799,15 +797,16 @@ values. We resolve this by using the following modified steps:
|
|||||||
```
|
```
|
||||||
|
|
||||||
The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4
|
The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4
|
||||||
and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm
|
and E.5 in the paper) preserves _gcd(f, g)_. However, there's no proof that the modified algorithm
|
||||||
will converge. The justification for posdivsteps is completely empirical: in practice, it appears
|
will converge. The justification for posdivsteps is completely empirical: in practice, it appears
|
||||||
that the vast majority of nonzero inputs converge to *f=g=gcd(f<sub>0</sub>, g<sub>0</sub>)* in a
|
that the vast majority of nonzero inputs converge to _f=g=gcd(f<sub>0</sub>, g<sub>0</sub>)_ in a
|
||||||
number of steps proportional to their logarithm.
|
number of steps proportional to their logarithm.
|
||||||
|
|
||||||
Note that:
|
Note that:
|
||||||
- We require inputs to satisfy *gcd(x, M) = 1*, as otherwise *f=1* is not reached.
|
|
||||||
- We require inputs *x &neq; 0*, because applying posdivstep with *g=0* has no effect.
|
- We require inputs to satisfy _gcd(x, M) = 1_, as otherwise _f=1_ is not reached.
|
||||||
- We need to update the termination condition from *g=0* to *f=1*.
|
- We require inputs _x &neq; 0_, because applying posdivstep with _g=0_ has no effect.
|
||||||
|
- We need to update the termination condition from _g=0_ to _f=1_.
|
||||||
|
|
||||||
We account for the possibility of nonconvergence by only performing a bounded number of
|
We account for the possibility of nonconvergence by only performing a bounded number of
|
||||||
posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not
|
posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not
|
||||||
@@ -815,5 +814,5 @@ yet been found.
|
|||||||
|
|
||||||
The optimizations in sections 3-7 above are described in the context of the original divsteps, but
|
The optimizations in sections 3-7 above are described in the context of the original divsteps, but
|
||||||
in the C implementation we also adapt most of them (not including "avoiding modulus operations",
|
in the C implementation we also adapt most of them (not including "avoiding modulus operations",
|
||||||
since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate
|
since it's not necessary to track _d, e_, and "constant-time operation", since we never calculate
|
||||||
Jacobi symbols for secret data) to the posdivsteps version.
|
Jacobi symbols for secret data) to the posdivsteps version.
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -2,9 +2,6 @@
|
|||||||
// Generated using generate_extern.sh
|
// Generated using generate_extern.sh
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#ifndef HOOK_EXTERN
|
#ifndef HOOK_EXTERN
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern int32_t __attribute__((noduplicate))
|
extern int32_t __attribute__((noduplicate))
|
||||||
_g(uint32_t guard_id, uint32_t maxiter);
|
_g(uint32_t guard_id, uint32_t maxiter);
|
||||||
@@ -339,8 +336,5 @@ prepare(
|
|||||||
uint32_t read_ptr,
|
uint32_t read_ptr,
|
||||||
uint32_t read_len);
|
uint32_t read_len);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#define HOOK_EXTERN
|
#define HOOK_EXTERN
|
||||||
#endif // HOOK_EXTERN
|
#endif // HOOK_EXTERN
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ ENUM_FILE="$SCRIPT_DIR/../include/xrpl/hook/Enum.h"
|
|||||||
echo '// For documentation please see: https://xrpl-hooks.readme.io/reference/'
|
echo '// For documentation please see: https://xrpl-hooks.readme.io/reference/'
|
||||||
echo '// Generated using generate_error.sh'
|
echo '// Generated using generate_error.sh'
|
||||||
echo '#ifndef HOOK_ERROR_CODES'
|
echo '#ifndef HOOK_ERROR_CODES'
|
||||||
sed -n '/enum class hook_return_code/,/};/p' "$ENUM_FILE" |
|
sed -n '/enum hook_return_code/,/};/p' "$ENUM_FILE" |
|
||||||
awk '
|
awk '
|
||||||
function ltrim(s) { sub(/^[[:space:]]+/, "", s); return s }
|
function ltrim(s) { sub(/^[[:space:]]+/, "", s); return s }
|
||||||
function rtrim(s) { sub(/[[:space:]]+$/, "", s); return s }
|
function rtrim(s) { sub(/[[:space:]]+$/, "", s); return s }
|
||||||
@@ -31,7 +31,7 @@ sed -n '/enum class hook_return_code/,/};/p' "$ENUM_FILE" |
|
|||||||
|
|
||||||
{
|
{
|
||||||
line = $0
|
line = $0
|
||||||
if (line ~ /enum[[:space:]]+class[[:space:]]+hook_return_code/)
|
if (line ~ /enum[[:space:]]+hook_return_code/)
|
||||||
next
|
next
|
||||||
if (line ~ /^[[:space:]]*\{/)
|
if (line ~ /^[[:space:]]*\{/)
|
||||||
next
|
next
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ APPLY_HOOK="$SCRIPT_DIR/../include/xrpl/hook/hook_api.macro"
|
|||||||
echo '// Generated using generate_extern.sh'
|
echo '// Generated using generate_extern.sh'
|
||||||
echo '#include <stdint.h>'
|
echo '#include <stdint.h>'
|
||||||
echo '#ifndef HOOK_EXTERN'
|
echo '#ifndef HOOK_EXTERN'
|
||||||
echo '#ifdef __cplusplus'
|
|
||||||
echo 'extern "C" {'
|
|
||||||
echo '#endif'
|
|
||||||
echo
|
echo
|
||||||
awk '
|
awk '
|
||||||
function trim(s) {
|
function trim(s) {
|
||||||
@@ -49,9 +46,6 @@ APPLY_HOOK="$SCRIPT_DIR/../include/xrpl/hook/hook_api.macro"
|
|||||||
}
|
}
|
||||||
' "$APPLY_HOOK"
|
' "$APPLY_HOOK"
|
||||||
|
|
||||||
echo '#ifdef __cplusplus'
|
|
||||||
echo '}'
|
|
||||||
echo '#endif'
|
|
||||||
echo '#define HOOK_EXTERN'
|
echo '#define HOOK_EXTERN'
|
||||||
echo '#endif // HOOK_EXTERN'
|
echo '#endif // HOOK_EXTERN'
|
||||||
} | (
|
} | (
|
||||||
|
|||||||
@@ -100,14 +100,14 @@ update_hook_array() {
|
|||||||
echo -e "${BLUE}==> Updating ${hook_name}...${NC}"
|
echo -e "${BLUE}==> Updating ${hook_name}...${NC}"
|
||||||
|
|
||||||
# Check if hook already exists
|
# Check if hook already exists
|
||||||
if grep -q "static const std::vector<uint8_t> ${hook_name} = {" "${XAHAU_H}"; then
|
if grep -q "static std::vector<uint8_t> const ${hook_name} = {" "${XAHAU_H}"; then
|
||||||
echo -e "${YELLOW} Replacing existing ${hook_name}${NC}"
|
echo -e "${YELLOW} Replacing existing ${hook_name}${NC}"
|
||||||
|
|
||||||
# Use awk to replace the array content
|
# Use awk to replace the array content
|
||||||
awk -v hook="${hook_name}" -v hex="${hex_array}" '
|
awk -v hook="${hook_name}" -v hex="${hex_array}" '
|
||||||
BEGIN { in_array=0 }
|
BEGIN { in_array=0 }
|
||||||
{
|
{
|
||||||
if ($0 ~ "static const std::vector<uint8_t> " hook " = {") {
|
if ($0 ~ "static std::vector<uint8_t> const " hook " = {") {
|
||||||
print $0
|
print $0
|
||||||
print hex
|
print hex
|
||||||
in_array=1
|
in_array=1
|
||||||
@@ -133,7 +133,7 @@ update_hook_array() {
|
|||||||
{
|
{
|
||||||
if ($0 ~ /#endif.*XAHAU_GENESIS_HOOKS/) {
|
if ($0 ~ /#endif.*XAHAU_GENESIS_HOOKS/) {
|
||||||
print ""
|
print ""
|
||||||
print "static const std::vector<uint8_t> " hook " = {"
|
print "static std::vector<uint8_t> const " hook " = {"
|
||||||
print hex
|
print hex
|
||||||
print "};"
|
print "};"
|
||||||
print ""
|
print ""
|
||||||
@@ -178,7 +178,7 @@ echo -e "${GREEN} Formatting completed${NC}"
|
|||||||
echo -e "${BLUE}==> Verifying changes...${NC}"
|
echo -e "${BLUE}==> Verifying changes...${NC}"
|
||||||
for hook_entry in "${HOOK_FILES[@]}"; do
|
for hook_entry in "${HOOK_FILES[@]}"; do
|
||||||
hook_name="${hook_entry%%:*}"
|
hook_name="${hook_entry%%:*}"
|
||||||
if grep -q "static const std::vector<uint8_t> ${hook_name} = {" "${XAHAU_H}"; then
|
if grep -q "static std::vector<uint8_t> const ${hook_name} = {" "${XAHAU_H}"; then
|
||||||
echo -e "${GREEN} ✓ ${hook_name} found in xahau.h${NC}"
|
echo -e "${GREEN} ✓ ${hook_name} found in xahau.h${NC}"
|
||||||
else
|
else
|
||||||
echo -e "${RED} ✗ ${hook_name} NOT found in xahau.h${NC}" >&2
|
echo -e "${RED} ✗ ${hook_name} NOT found in xahau.h${NC}" >&2
|
||||||
|
|||||||
@@ -45,8 +45,8 @@
|
|||||||
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "extern.h"
|
#include "extern.h"
|
||||||
#include "sfcodes.h"
|
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "sfcodes.h"
|
||||||
#include "tts.h"
|
#include "tts.h"
|
||||||
|
|
||||||
#include "ls_flags.h"
|
#include "ls_flags.h"
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ enum ltACCOUNT_ROOT {
|
|||||||
enum ltOFFER {
|
enum ltOFFER {
|
||||||
lsfPassive = 0x00010000,
|
lsfPassive = 0x00010000,
|
||||||
lsfSell = 0x00020000,
|
lsfSell = 0x00020000,
|
||||||
|
lsfHybrid = 0x00040000,
|
||||||
};
|
};
|
||||||
enum ltRIPPLE_STATE {
|
enum ltRIPPLE_STATE {
|
||||||
lsfLowReserve = 0x00010000,
|
lsfLowReserve = 0x00010000,
|
||||||
@@ -71,5 +72,8 @@ enum ltMPTOKEN {
|
|||||||
enum ltCREDENTIAL {
|
enum ltCREDENTIAL {
|
||||||
lsfAccepted = 0x00010000,
|
lsfAccepted = 0x00010000,
|
||||||
};
|
};
|
||||||
|
enum ltVAULT {
|
||||||
|
lsfVaultPrivate = 0x00010000,
|
||||||
|
};
|
||||||
|
|
||||||
#endif // HOOKLSFLAGS_INCLUDED
|
#endif // HOOKLSFLAGS_INCLUDED
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#define sfUNLModifyDisabling ((16U << 16U) + 17U)
|
#define sfUNLModifyDisabling ((16U << 16U) + 17U)
|
||||||
#define sfHookResult ((16U << 16U) + 18U)
|
#define sfHookResult ((16U << 16U) + 18U)
|
||||||
#define sfWasLockingChainSend ((16U << 16U) + 19U)
|
#define sfWasLockingChainSend ((16U << 16U) + 19U)
|
||||||
|
#define sfWithdrawalPolicy ((16U << 16U) + 20U)
|
||||||
#define sfLedgerEntryType ((1U << 16U) + 1U)
|
#define sfLedgerEntryType ((1U << 16U) + 1U)
|
||||||
#define sfTransactionType ((1U << 16U) + 2U)
|
#define sfTransactionType ((1U << 16U) + 2U)
|
||||||
#define sfSignerWeight ((1U << 16U) + 3U)
|
#define sfSignerWeight ((1U << 16U) + 3U)
|
||||||
@@ -72,6 +73,7 @@
|
|||||||
#define sfLockCount ((2U << 16U) + 49U)
|
#define sfLockCount ((2U << 16U) + 49U)
|
||||||
#define sfFirstNFTokenSequence ((2U << 16U) + 50U)
|
#define sfFirstNFTokenSequence ((2U << 16U) + 50U)
|
||||||
#define sfOracleDocumentID ((2U << 16U) + 51U)
|
#define sfOracleDocumentID ((2U << 16U) + 51U)
|
||||||
|
#define sfPermissionValue ((2U << 16U) + 52U)
|
||||||
#define sfStartTime ((2U << 16U) + 93U)
|
#define sfStartTime ((2U << 16U) + 93U)
|
||||||
#define sfRepeatCount ((2U << 16U) + 94U)
|
#define sfRepeatCount ((2U << 16U) + 94U)
|
||||||
#define sfDelaySeconds ((2U << 16U) + 95U)
|
#define sfDelaySeconds ((2U << 16U) + 95U)
|
||||||
@@ -115,6 +117,7 @@
|
|||||||
#define sfTakerGetsCurrency ((17U << 16U) + 3U)
|
#define sfTakerGetsCurrency ((17U << 16U) + 3U)
|
||||||
#define sfTakerGetsIssuer ((17U << 16U) + 4U)
|
#define sfTakerGetsIssuer ((17U << 16U) + 4U)
|
||||||
#define sfMPTokenIssuanceID ((21U << 16U) + 1U)
|
#define sfMPTokenIssuanceID ((21U << 16U) + 1U)
|
||||||
|
#define sfShareMPTID ((21U << 16U) + 2U)
|
||||||
#define sfLedgerHash ((5U << 16U) + 1U)
|
#define sfLedgerHash ((5U << 16U) + 1U)
|
||||||
#define sfParentHash ((5U << 16U) + 2U)
|
#define sfParentHash ((5U << 16U) + 2U)
|
||||||
#define sfTransactionHash ((5U << 16U) + 3U)
|
#define sfTransactionHash ((5U << 16U) + 3U)
|
||||||
@@ -152,6 +155,8 @@
|
|||||||
#define sfEscrowID ((5U << 16U) + 35U)
|
#define sfEscrowID ((5U << 16U) + 35U)
|
||||||
#define sfURITokenID ((5U << 16U) + 36U)
|
#define sfURITokenID ((5U << 16U) + 36U)
|
||||||
#define sfDomainID ((5U << 16U) + 37U)
|
#define sfDomainID ((5U << 16U) + 37U)
|
||||||
|
#define sfVaultID ((5U << 16U) + 38U)
|
||||||
|
#define sfParentBatchID ((5U << 16U) + 39U)
|
||||||
#define sfHookOnOutgoing ((5U << 16U) + 93U)
|
#define sfHookOnOutgoing ((5U << 16U) + 93U)
|
||||||
#define sfHookOnIncoming ((5U << 16U) + 94U)
|
#define sfHookOnIncoming ((5U << 16U) + 94U)
|
||||||
#define sfCron ((5U << 16U) + 95U)
|
#define sfCron ((5U << 16U) + 95U)
|
||||||
@@ -160,6 +165,10 @@
|
|||||||
#define sfGovernanceMarks ((5U << 16U) + 98U)
|
#define sfGovernanceMarks ((5U << 16U) + 98U)
|
||||||
#define sfGovernanceFlags ((5U << 16U) + 99U)
|
#define sfGovernanceFlags ((5U << 16U) + 99U)
|
||||||
#define sfNumber ((9U << 16U) + 1U)
|
#define sfNumber ((9U << 16U) + 1U)
|
||||||
|
#define sfAssetsAvailable ((9U << 16U) + 2U)
|
||||||
|
#define sfAssetsMaximum ((9U << 16U) + 3U)
|
||||||
|
#define sfAssetsTotal ((9U << 16U) + 4U)
|
||||||
|
#define sfLossUnrealized ((9U << 16U) + 5U)
|
||||||
#define sfAmount ((6U << 16U) + 1U)
|
#define sfAmount ((6U << 16U) + 1U)
|
||||||
#define sfBalance ((6U << 16U) + 2U)
|
#define sfBalance ((6U << 16U) + 2U)
|
||||||
#define sfLimitAmount ((6U << 16U) + 3U)
|
#define sfLimitAmount ((6U << 16U) + 3U)
|
||||||
@@ -221,7 +230,6 @@
|
|||||||
#define sfProvider ((7U << 16U) + 30U)
|
#define sfProvider ((7U << 16U) + 30U)
|
||||||
#define sfMPTokenMetadata ((7U << 16U) + 31U)
|
#define sfMPTokenMetadata ((7U << 16U) + 31U)
|
||||||
#define sfCredentialType ((7U << 16U) + 32U)
|
#define sfCredentialType ((7U << 16U) + 32U)
|
||||||
#define sfHookName ((7U << 16U) + 97U)
|
|
||||||
#define sfRemarkValue ((7U << 16U) + 98U)
|
#define sfRemarkValue ((7U << 16U) + 98U)
|
||||||
#define sfRemarkName ((7U << 16U) + 99U)
|
#define sfRemarkName ((7U << 16U) + 99U)
|
||||||
#define sfAccount ((8U << 16U) + 1U)
|
#define sfAccount ((8U << 16U) + 1U)
|
||||||
@@ -234,6 +242,7 @@
|
|||||||
#define sfNFTokenMinter ((8U << 16U) + 9U)
|
#define sfNFTokenMinter ((8U << 16U) + 9U)
|
||||||
#define sfEmitCallback ((8U << 16U) + 10U)
|
#define sfEmitCallback ((8U << 16U) + 10U)
|
||||||
#define sfHolder ((8U << 16U) + 11U)
|
#define sfHolder ((8U << 16U) + 11U)
|
||||||
|
#define sfDelegate ((8U << 16U) + 12U)
|
||||||
#define sfHookAccount ((8U << 16U) + 16U)
|
#define sfHookAccount ((8U << 16U) + 16U)
|
||||||
#define sfOtherChainSource ((8U << 16U) + 18U)
|
#define sfOtherChainSource ((8U << 16U) + 18U)
|
||||||
#define sfOtherChainDestination ((8U << 16U) + 19U)
|
#define sfOtherChainDestination ((8U << 16U) + 19U)
|
||||||
@@ -272,6 +281,7 @@
|
|||||||
#define sfNFToken ((14U << 16U) + 12U)
|
#define sfNFToken ((14U << 16U) + 12U)
|
||||||
#define sfEmitDetails ((14U << 16U) + 13U)
|
#define sfEmitDetails ((14U << 16U) + 13U)
|
||||||
#define sfHook ((14U << 16U) + 14U)
|
#define sfHook ((14U << 16U) + 14U)
|
||||||
|
#define sfPermission ((14U << 16U) + 15U)
|
||||||
#define sfSigner ((14U << 16U) + 16U)
|
#define sfSigner ((14U << 16U) + 16U)
|
||||||
#define sfMajority ((14U << 16U) + 18U)
|
#define sfMajority ((14U << 16U) + 18U)
|
||||||
#define sfDisabledValidator ((14U << 16U) + 19U)
|
#define sfDisabledValidator ((14U << 16U) + 19U)
|
||||||
@@ -288,6 +298,9 @@
|
|||||||
#define sfXChainCreateAccountAttestationCollectionElement ((14U << 16U) + 31U)
|
#define sfXChainCreateAccountAttestationCollectionElement ((14U << 16U) + 31U)
|
||||||
#define sfPriceData ((14U << 16U) + 32U)
|
#define sfPriceData ((14U << 16U) + 32U)
|
||||||
#define sfCredential ((14U << 16U) + 33U)
|
#define sfCredential ((14U << 16U) + 33U)
|
||||||
|
#define sfRawTransaction ((14U << 16U) + 34U)
|
||||||
|
#define sfBatchSigner ((14U << 16U) + 35U)
|
||||||
|
#define sfBook ((14U << 16U) + 36U)
|
||||||
#define sfAmountEntry ((14U << 16U) + 91U)
|
#define sfAmountEntry ((14U << 16U) + 91U)
|
||||||
#define sfMintURIToken ((14U << 16U) + 92U)
|
#define sfMintURIToken ((14U << 16U) + 92U)
|
||||||
#define sfHookEmission ((14U << 16U) + 93U)
|
#define sfHookEmission ((14U << 16U) + 93U)
|
||||||
@@ -307,6 +320,7 @@
|
|||||||
#define sfNFTokens ((15U << 16U) + 10U)
|
#define sfNFTokens ((15U << 16U) + 10U)
|
||||||
#define sfHooks ((15U << 16U) + 11U)
|
#define sfHooks ((15U << 16U) + 11U)
|
||||||
#define sfVoteSlots ((15U << 16U) + 12U)
|
#define sfVoteSlots ((15U << 16U) + 12U)
|
||||||
|
#define sfAdditionalBooks ((15U << 16U) + 13U)
|
||||||
#define sfMajorities ((15U << 16U) + 16U)
|
#define sfMajorities ((15U << 16U) + 16U)
|
||||||
#define sfDisabledValidators ((15U << 16U) + 17U)
|
#define sfDisabledValidators ((15U << 16U) + 17U)
|
||||||
#define sfHookExecutions ((15U << 16U) + 18U)
|
#define sfHookExecutions ((15U << 16U) + 18U)
|
||||||
@@ -319,6 +333,9 @@
|
|||||||
#define sfAuthorizeCredentials ((15U << 16U) + 26U)
|
#define sfAuthorizeCredentials ((15U << 16U) + 26U)
|
||||||
#define sfUnauthorizeCredentials ((15U << 16U) + 27U)
|
#define sfUnauthorizeCredentials ((15U << 16U) + 27U)
|
||||||
#define sfAcceptedCredentials ((15U << 16U) + 28U)
|
#define sfAcceptedCredentials ((15U << 16U) + 28U)
|
||||||
|
#define sfPermissions ((15U << 16U) + 29U)
|
||||||
|
#define sfRawTransactions ((15U << 16U) + 30U)
|
||||||
|
#define sfBatchSigners ((15U << 16U) + 31U)
|
||||||
#define sfAmounts ((15U << 16U) + 92U)
|
#define sfAmounts ((15U << 16U) + 92U)
|
||||||
#define sfHookEmissions ((15U << 16U) + 93U)
|
#define sfHookEmissions ((15U << 16U) + 93U)
|
||||||
#define sfImportVLKeys ((15U << 16U) + 94U)
|
#define sfImportVLKeys ((15U << 16U) + 94U)
|
||||||
|
|||||||
@@ -61,6 +61,14 @@
|
|||||||
#define ttNFTOKEN_MODIFY 70
|
#define ttNFTOKEN_MODIFY 70
|
||||||
#define ttPERMISSIONED_DOMAIN_SET 71
|
#define ttPERMISSIONED_DOMAIN_SET 71
|
||||||
#define ttPERMISSIONED_DOMAIN_DELETE 72
|
#define ttPERMISSIONED_DOMAIN_DELETE 72
|
||||||
|
#define ttDELEGATE_SET 73
|
||||||
|
#define ttVAULT_CREATE 74
|
||||||
|
#define ttVAULT_SET 75
|
||||||
|
#define ttVAULT_DELETE 76
|
||||||
|
#define ttVAULT_DEPOSIT 77
|
||||||
|
#define ttVAULT_WITHDRAW 78
|
||||||
|
#define ttVAULT_CLAWBACK 79
|
||||||
|
#define ttBATCH 80
|
||||||
#define ttCRON 92
|
#define ttCRON 92
|
||||||
#define ttCRON_SET 93
|
#define ttCRON_SET 93
|
||||||
#define ttREMARKS_SET 94
|
#define ttREMARKS_SET 94
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
enum UniversalFlags : uint32_t {
|
enum UniversalFlags : uint32_t {
|
||||||
tfFullyCanonicalSig = 0x80000000,
|
tfFullyCanonicalSig = 0x80000000,
|
||||||
|
tfInnerBatchTxn = 0x40000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum AccountSetFlags : uint32_t {
|
enum AccountSetFlags : uint32_t {
|
||||||
@@ -40,6 +41,7 @@ enum OfferCreateFlags : uint32_t {
|
|||||||
tfImmediateOrCancel = 0x00020000,
|
tfImmediateOrCancel = 0x00020000,
|
||||||
tfFillOrKill = 0x00040000,
|
tfFillOrKill = 0x00040000,
|
||||||
tfSell = 0x00080000,
|
tfSell = 0x00080000,
|
||||||
|
tfHybrid = 0x00100000,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PaymentFlags : uint32_t {
|
enum PaymentFlags : uint32_t {
|
||||||
@@ -115,3 +117,10 @@ enum AMMClawbackFlags : uint32_t {
|
|||||||
enum BridgeModifyFlags : uint32_t {
|
enum BridgeModifyFlags : uint32_t {
|
||||||
tfClearAccountCreateAmount = 0x00010000,
|
tfClearAccountCreateAmount = 0x00010000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum BatchFlags : uint32_t {
|
||||||
|
tfAllOrNothing = 0x00010000,
|
||||||
|
tfOnlyOne = 0x00020000,
|
||||||
|
tfUntilFailure = 0x00040000,
|
||||||
|
tfIndependent = 0x00080000,
|
||||||
|
};
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <ostream>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -368,7 +367,7 @@ get(Section const& section,
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline std::string
|
inline std::string
|
||||||
get(Section const& section, std::string const& name, const char* defaultValue)
|
get(Section const& section, std::string const& name, char const* defaultValue)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,10 +22,10 @@
|
|||||||
|
|
||||||
#include <xrpl/basics/Slice.h>
|
#include <xrpl/basics/Slice.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,11 @@
|
|||||||
#define RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED
|
#define RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED
|
||||||
|
|
||||||
#include <xrpl/basics/contract.h>
|
#include <xrpl/basics/contract.h>
|
||||||
|
|
||||||
|
#include <lz4.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <lz4.h>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -53,7 +55,7 @@ lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf)
|
|||||||
auto compressed = bf(outCapacity);
|
auto compressed = bf(outCapacity);
|
||||||
|
|
||||||
auto compressedSize = LZ4_compress_default(
|
auto compressedSize = LZ4_compress_default(
|
||||||
reinterpret_cast<const char*>(in),
|
reinterpret_cast<char const*>(in),
|
||||||
reinterpret_cast<char*>(compressed),
|
reinterpret_cast<char*>(compressed),
|
||||||
inSize,
|
inSize,
|
||||||
outCapacity);
|
outCapacity);
|
||||||
@@ -87,7 +89,7 @@ lz4Decompress(
|
|||||||
Throw<std::runtime_error>("lz4Decompress: integer overflow (output)");
|
Throw<std::runtime_error>("lz4Decompress: integer overflow (output)");
|
||||||
|
|
||||||
if (LZ4_decompress_safe(
|
if (LZ4_decompress_safe(
|
||||||
reinterpret_cast<const char*>(in),
|
reinterpret_cast<char const*>(in),
|
||||||
reinterpret_cast<char*>(decompressed),
|
reinterpret_cast<char*>(decompressed),
|
||||||
inSize,
|
inSize,
|
||||||
decompressedSize) != decompressedSize)
|
decompressedSize) != decompressedSize)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#define RIPPLE_BASICS_COUNTEDOBJECT_H_INCLUDED
|
#define RIPPLE_BASICS_COUNTEDOBJECT_H_INCLUDED
|
||||||
|
|
||||||
#include <xrpl/beast/type_name.h>
|
#include <xrpl/beast/type_name.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|||||||
@@ -24,9 +24,7 @@
|
|||||||
|
|
||||||
#include <boost/outcome.hpp>
|
#include <boost/outcome.hpp>
|
||||||
|
|
||||||
#include <concepts>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
@@ -95,7 +93,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const E&
|
constexpr E const&
|
||||||
value() const&
|
value() const&
|
||||||
{
|
{
|
||||||
return val_;
|
return val_;
|
||||||
@@ -113,7 +111,7 @@ public:
|
|||||||
return std::move(val_);
|
return std::move(val_);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const E&&
|
constexpr E const&&
|
||||||
value() const&&
|
value() const&&
|
||||||
{
|
{
|
||||||
return std::move(val_);
|
return std::move(val_);
|
||||||
|
|||||||
515
include/xrpl/basics/IntrusivePointer.h
Normal file
515
include/xrpl/basics/IntrusivePointer.h
Normal file
@@ -0,0 +1,515 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2023 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_BASICS_INTRUSIVEPOINTER_H_INCLUDED
|
||||||
|
#define RIPPLE_BASICS_INTRUSIVEPOINTER_H_INCLUDED
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Tag to create an intrusive pointer from another intrusive pointer by using a
|
||||||
|
static cast. This is useful to create an intrusive pointer to a derived
|
||||||
|
class from an intrusive pointer to a base class.
|
||||||
|
*/
|
||||||
|
struct StaticCastTagSharedIntrusive
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Tag to create an intrusive pointer from another intrusive pointer by using a
|
||||||
|
dynamic cast. This is useful to create an intrusive pointer to a derived
|
||||||
|
class from an intrusive pointer to a base class. If the cast fails an empty
|
||||||
|
(null) intrusive pointer is created.
|
||||||
|
*/
|
||||||
|
struct DynamicCastTagSharedIntrusive
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/** When creating or adopting a raw pointer, controls whether the strong count
|
||||||
|
is incremented or not. Use this tag to increment the strong count.
|
||||||
|
*/
|
||||||
|
struct SharedIntrusiveAdoptIncrementStrongTag
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/** When creating or adopting a raw pointer, controls whether the strong count
|
||||||
|
is incremented or not. Use this tag to leave the strong count unchanged.
|
||||||
|
*/
|
||||||
|
struct SharedIntrusiveAdoptNoIncrementTag
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
concept CAdoptTag = std::is_same_v<T, SharedIntrusiveAdoptIncrementStrongTag> ||
|
||||||
|
std::is_same_v<T, SharedIntrusiveAdoptNoIncrementTag>;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** A shared intrusive pointer class that supports weak pointers.
|
||||||
|
|
||||||
|
This is meant to be used for SHAMapInnerNodes, but may be useful for other
|
||||||
|
cases. Since the reference counts are stored on the pointee, the pointee is
|
||||||
|
not destroyed until both the strong _and_ weak pointer counts go to zero.
|
||||||
|
When the strong pointer count goes to zero, the "partialDestructor" is
|
||||||
|
called. This can be used to destroy as much of the object as possible while
|
||||||
|
still retaining the reference counts. For example, for SHAMapInnerNodes the
|
||||||
|
children may be reset in that function. Note that std::shared_poiner WILL
|
||||||
|
run the destructor when the strong count reaches zero, but may not free the
|
||||||
|
memory used by the object until the weak count reaches zero. In rippled, we
|
||||||
|
typically allocate shared pointers with the `make_shared` function. When
|
||||||
|
that is used, the memory is not reclaimed until the weak count reaches zero.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
class SharedIntrusive
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SharedIntrusive() = default;
|
||||||
|
|
||||||
|
template <CAdoptTag TAdoptTag>
|
||||||
|
SharedIntrusive(T* p, TAdoptTag) noexcept;
|
||||||
|
|
||||||
|
SharedIntrusive(SharedIntrusive const& rhs);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
// TODO: convertible_to isn't quite right. That include a static castable.
|
||||||
|
// Find the right concept.
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedIntrusive(SharedIntrusive<TT> const& rhs);
|
||||||
|
|
||||||
|
SharedIntrusive(SharedIntrusive&& rhs);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedIntrusive(SharedIntrusive<TT>&& rhs);
|
||||||
|
|
||||||
|
SharedIntrusive&
|
||||||
|
operator=(SharedIntrusive const& rhs);
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator!=(std::nullptr_t) const;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(std::nullptr_t) const;
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedIntrusive&
|
||||||
|
operator=(SharedIntrusive<TT> const& rhs);
|
||||||
|
|
||||||
|
SharedIntrusive&
|
||||||
|
operator=(SharedIntrusive&& rhs);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedIntrusive&
|
||||||
|
operator=(SharedIntrusive<TT>&& rhs);
|
||||||
|
|
||||||
|
/** Adopt the raw pointer. The strong reference may or may not be
|
||||||
|
incremented, depending on the TAdoptTag
|
||||||
|
*/
|
||||||
|
template <CAdoptTag TAdoptTag = SharedIntrusiveAdoptIncrementStrongTag>
|
||||||
|
void
|
||||||
|
adopt(T* p);
|
||||||
|
|
||||||
|
~SharedIntrusive();
|
||||||
|
|
||||||
|
/** Create a new SharedIntrusive by statically casting the pointer
|
||||||
|
controlled by the rhs param.
|
||||||
|
*/
|
||||||
|
template <class TT>
|
||||||
|
SharedIntrusive(
|
||||||
|
StaticCastTagSharedIntrusive,
|
||||||
|
SharedIntrusive<TT> const& rhs);
|
||||||
|
|
||||||
|
/** Create a new SharedIntrusive by statically casting the pointer
|
||||||
|
controlled by the rhs param.
|
||||||
|
*/
|
||||||
|
template <class TT>
|
||||||
|
SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT>&& rhs);
|
||||||
|
|
||||||
|
/** Create a new SharedIntrusive by dynamically casting the pointer
|
||||||
|
controlled by the rhs param.
|
||||||
|
*/
|
||||||
|
template <class TT>
|
||||||
|
SharedIntrusive(
|
||||||
|
DynamicCastTagSharedIntrusive,
|
||||||
|
SharedIntrusive<TT> const& rhs);
|
||||||
|
|
||||||
|
/** Create a new SharedIntrusive by dynamically casting the pointer
|
||||||
|
controlled by the rhs param.
|
||||||
|
*/
|
||||||
|
template <class TT>
|
||||||
|
SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive<TT>&& rhs);
|
||||||
|
|
||||||
|
T&
|
||||||
|
operator*() const noexcept;
|
||||||
|
|
||||||
|
T*
|
||||||
|
operator->() const noexcept;
|
||||||
|
|
||||||
|
explicit
|
||||||
|
operator bool() const noexcept;
|
||||||
|
|
||||||
|
/** Set the pointer to null, decrement the strong count, and run the
|
||||||
|
appropriate release action.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
reset();
|
||||||
|
|
||||||
|
/** Get the raw pointer */
|
||||||
|
T*
|
||||||
|
get() const;
|
||||||
|
|
||||||
|
/** Return the strong count */
|
||||||
|
std::size_t
|
||||||
|
use_count() const;
|
||||||
|
|
||||||
|
template <class TT, class... Args>
|
||||||
|
friend SharedIntrusive<TT>
|
||||||
|
make_SharedIntrusive(Args&&... args);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
friend class SharedIntrusive;
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
friend class SharedWeakUnion;
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
friend class WeakIntrusive;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Return the raw pointer held by this object. */
|
||||||
|
T*
|
||||||
|
unsafeGetRawPtr() const;
|
||||||
|
|
||||||
|
/** Exchange the current raw pointer held by this object with the given
|
||||||
|
pointer. Decrement the strong count of the raw pointer previously held
|
||||||
|
by this object and run the appropriate release action.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
unsafeReleaseAndStore(T* next);
|
||||||
|
|
||||||
|
/** Set the raw pointer directly. This is wrapped in a function so the class
|
||||||
|
can support both atomic and non-atomic pointers in a future patch.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
unsafeSetRawPtr(T* p);
|
||||||
|
|
||||||
|
/** Exchange the raw pointer directly.
|
||||||
|
This sets the raw pointer to the given value and returns the previous
|
||||||
|
value. This is wrapped in a function so the class can support both
|
||||||
|
atomic and non-atomic pointers in a future patch.
|
||||||
|
*/
|
||||||
|
T*
|
||||||
|
unsafeExchange(T* p);
|
||||||
|
|
||||||
|
/** pointer to the type with an intrusive count */
|
||||||
|
T* ptr_{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** A weak intrusive pointer class for the SharedIntrusive pointer class.
|
||||||
|
|
||||||
|
Note that this weak pointer class asks differently from normal weak pointer
|
||||||
|
classes. When the strong pointer count goes to zero, the "partialDestructor"
|
||||||
|
is called. See the comment on SharedIntrusive for a fuller explanation.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
class WeakIntrusive
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WeakIntrusive() = default;
|
||||||
|
|
||||||
|
WeakIntrusive(WeakIntrusive const& rhs);
|
||||||
|
|
||||||
|
WeakIntrusive(WeakIntrusive&& rhs);
|
||||||
|
|
||||||
|
WeakIntrusive(SharedIntrusive<T> const& rhs);
|
||||||
|
|
||||||
|
// There is no move constructor from a strong intrusive ptr because
|
||||||
|
// moving would be move expensive than copying in this case (the strong
|
||||||
|
// ref would need to be decremented)
|
||||||
|
WeakIntrusive(SharedIntrusive<T> const&& rhs) = delete;
|
||||||
|
|
||||||
|
// Since there are no current use cases for copy assignment in
|
||||||
|
// WeakIntrusive, we delete this operator to simplify the implementation. If
|
||||||
|
// a need arises in the future, we can reintroduce it with proper
|
||||||
|
// consideration."
|
||||||
|
WeakIntrusive&
|
||||||
|
operator=(WeakIntrusive const&) = delete;
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
WeakIntrusive&
|
||||||
|
operator=(SharedIntrusive<TT> const& rhs);
|
||||||
|
|
||||||
|
/** Adopt the raw pointer and increment the weak count. */
|
||||||
|
void
|
||||||
|
adopt(T* ptr);
|
||||||
|
|
||||||
|
~WeakIntrusive();
|
||||||
|
|
||||||
|
/** Get a strong pointer from the weak pointer, if possible. This will
|
||||||
|
only return a seated pointer if the strong count on the raw pointer
|
||||||
|
is non-zero before locking.
|
||||||
|
*/
|
||||||
|
SharedIntrusive<T>
|
||||||
|
lock() const;
|
||||||
|
|
||||||
|
/** Return true if the strong count is zero. */
|
||||||
|
bool
|
||||||
|
expired() const;
|
||||||
|
|
||||||
|
/** Set the pointer to null and decrement the weak count.
|
||||||
|
|
||||||
|
Note: This may run the destructor if the strong count is zero.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* ptr_ = nullptr;
|
||||||
|
|
||||||
|
/** Decrement the weak count. This does _not_ set the raw pointer to
|
||||||
|
null.
|
||||||
|
|
||||||
|
Note: This may run the destructor if the strong count is zero.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
unsafeReleaseNoStore();
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** A combination of a strong and a weak intrusive pointer stored in the
|
||||||
|
space of a single pointer.
|
||||||
|
|
||||||
|
This class is similar to a `std::variant<SharedIntrusive,WeakIntrusive>`
|
||||||
|
with some optimizations. In particular, it uses a low-order bit to
|
||||||
|
determine if the raw pointer represents a strong pointer or a weak
|
||||||
|
pointer. It can also be quickly switched between its strong pointer and
|
||||||
|
weak pointer representations. This class is useful for storing intrusive
|
||||||
|
pointers in tagged caches.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class SharedWeakUnion
|
||||||
|
{
|
||||||
|
// Tagged pointer. Low bit determines if this is a strong or a weak
|
||||||
|
// pointer. The low bit must be masked to zero when converting back to a
|
||||||
|
// pointer. If the low bit is '1', this is a weak pointer.
|
||||||
|
static_assert(
|
||||||
|
alignof(T) >= 2,
|
||||||
|
"Bad alignment: Combo pointer requires low bit to be zero");
|
||||||
|
|
||||||
|
public:
|
||||||
|
SharedWeakUnion() = default;
|
||||||
|
|
||||||
|
SharedWeakUnion(SharedWeakUnion const& rhs);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakUnion(SharedIntrusive<TT> const& rhs);
|
||||||
|
|
||||||
|
SharedWeakUnion(SharedWeakUnion&& rhs);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakUnion(SharedIntrusive<TT>&& rhs);
|
||||||
|
|
||||||
|
SharedWeakUnion&
|
||||||
|
operator=(SharedWeakUnion const& rhs);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakUnion&
|
||||||
|
operator=(SharedIntrusive<TT> const& rhs);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakUnion&
|
||||||
|
operator=(SharedIntrusive<TT>&& rhs);
|
||||||
|
|
||||||
|
~SharedWeakUnion();
|
||||||
|
|
||||||
|
/** Return a strong pointer if this is already a strong pointer (i.e.
|
||||||
|
don't lock the weak pointer. Use the `lock` method if that's what's
|
||||||
|
needed)
|
||||||
|
*/
|
||||||
|
SharedIntrusive<T>
|
||||||
|
getStrong() const;
|
||||||
|
|
||||||
|
/** Return true if this is a strong pointer and the strong pointer is
|
||||||
|
seated.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
operator bool() const noexcept;
|
||||||
|
|
||||||
|
/** Set the pointer to null, decrement the appropriate ref count, and
|
||||||
|
run the appropriate release action.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
reset();
|
||||||
|
|
||||||
|
/** If this is a strong pointer, return the raw pointer. Otherwise
|
||||||
|
return null.
|
||||||
|
*/
|
||||||
|
T*
|
||||||
|
get() const;
|
||||||
|
|
||||||
|
/** If this is a strong pointer, return the strong count. Otherwise
|
||||||
|
* return 0
|
||||||
|
*/
|
||||||
|
std::size_t
|
||||||
|
use_count() const;
|
||||||
|
|
||||||
|
/** Return true if there is a non-zero strong count. */
|
||||||
|
bool
|
||||||
|
expired() const;
|
||||||
|
|
||||||
|
/** If this is a strong pointer, return the strong pointer. Otherwise
|
||||||
|
attempt to lock the weak pointer.
|
||||||
|
*/
|
||||||
|
SharedIntrusive<T>
|
||||||
|
lock() const;
|
||||||
|
|
||||||
|
/** Return true is this represents a strong pointer. */
|
||||||
|
bool
|
||||||
|
isStrong() const;
|
||||||
|
|
||||||
|
/** Return true is this represents a weak pointer. */
|
||||||
|
bool
|
||||||
|
isWeak() const;
|
||||||
|
|
||||||
|
/** If this is a weak pointer, attempt to convert it to a strong
|
||||||
|
pointer.
|
||||||
|
|
||||||
|
@return true if successfully converted to a strong pointer (or was
|
||||||
|
already a strong pointer). Otherwise false.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
convertToStrong();
|
||||||
|
|
||||||
|
/** If this is a strong pointer, attempt to convert it to a weak
|
||||||
|
pointer.
|
||||||
|
|
||||||
|
@return false if the pointer is null. Otherwise return true.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
convertToWeak();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Tagged pointer. Low bit determines if this is a strong or a weak
|
||||||
|
// pointer. The low bit must be masked to zero when converting back to a
|
||||||
|
// pointer. If the low bit is '1', this is a weak pointer.
|
||||||
|
std::uintptr_t tp_{0};
|
||||||
|
static constexpr std::uintptr_t tagMask = 1;
|
||||||
|
static constexpr std::uintptr_t ptrMask = ~tagMask;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Return the raw pointer held by this object.
|
||||||
|
*/
|
||||||
|
T*
|
||||||
|
unsafeGetRawPtr() const;
|
||||||
|
|
||||||
|
enum class RefStrength { strong, weak };
|
||||||
|
/** Set the raw pointer and tag bit directly.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
unsafeSetRawPtr(T* p, RefStrength rs);
|
||||||
|
|
||||||
|
/** Set the raw pointer and tag bit to all zeros (strong null pointer).
|
||||||
|
*/
|
||||||
|
void unsafeSetRawPtr(std::nullptr_t);
|
||||||
|
|
||||||
|
/** Decrement the appropriate ref count, and run the appropriate release
|
||||||
|
action. Note: this does _not_ set the raw pointer to null.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
unsafeReleaseNoStore();
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Create a shared intrusive pointer.
|
||||||
|
|
||||||
|
Note: unlike std::shared_ptr, where there is an advantage of allocating
|
||||||
|
the pointer and control block together, there is no benefit for intrusive
|
||||||
|
pointers.
|
||||||
|
*/
|
||||||
|
template <class TT, class... Args>
|
||||||
|
SharedIntrusive<TT>
|
||||||
|
make_SharedIntrusive(Args&&... args)
|
||||||
|
{
|
||||||
|
auto p = new TT(std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
noexcept(SharedIntrusive<TT>(
|
||||||
|
std::declval<TT*>(),
|
||||||
|
std::declval<SharedIntrusiveAdoptNoIncrementTag>())),
|
||||||
|
"SharedIntrusive constructor should not throw or this can leak "
|
||||||
|
"memory");
|
||||||
|
|
||||||
|
return SharedIntrusive<TT>(p, SharedIntrusiveAdoptNoIncrementTag{});
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace intr_ptr {
|
||||||
|
template <class T>
|
||||||
|
using SharedPtr = SharedIntrusive<T>;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
using WeakPtr = WeakIntrusive<T>;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
using SharedWeakUnionPtr = SharedWeakUnion<T>;
|
||||||
|
|
||||||
|
template <class T, class... A>
|
||||||
|
SharedPtr<T>
|
||||||
|
make_shared(A&&... args)
|
||||||
|
{
|
||||||
|
return make_SharedIntrusive<T>(std::forward<A>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class TT>
|
||||||
|
SharedPtr<T>
|
||||||
|
static_pointer_cast(TT const& v)
|
||||||
|
{
|
||||||
|
return SharedPtr<T>(StaticCastTagSharedIntrusive{}, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class TT>
|
||||||
|
SharedPtr<T>
|
||||||
|
dynamic_pointer_cast(TT const& v)
|
||||||
|
{
|
||||||
|
return SharedPtr<T>(DynamicCastTagSharedIntrusive{}, v);
|
||||||
|
}
|
||||||
|
} // namespace intr_ptr
|
||||||
|
} // namespace ripple
|
||||||
|
#endif
|
||||||
740
include/xrpl/basics/IntrusivePointer.ipp
Normal file
740
include/xrpl/basics/IntrusivePointer.ipp
Normal file
@@ -0,0 +1,740 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2023 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_BASICS_INTRUSIVEPOINTER_IPP_INCLUDED
|
||||||
|
#define RIPPLE_BASICS_INTRUSIVEPOINTER_IPP_INCLUDED
|
||||||
|
|
||||||
|
#include <xrpl/basics/IntrusivePointer.h>
|
||||||
|
#include <xrpl/basics/IntrusiveRefCounts.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <CAdoptTag TAdoptTag>
|
||||||
|
SharedIntrusive<T>::SharedIntrusive(T* p, TAdoptTag) noexcept : ptr_{p}
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<
|
||||||
|
TAdoptTag,
|
||||||
|
SharedIntrusiveAdoptIncrementStrongTag>)
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
p->addStrongRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive const& rhs)
|
||||||
|
: ptr_{[&] {
|
||||||
|
auto p = rhs.unsafeGetRawPtr();
|
||||||
|
if (p)
|
||||||
|
p->addStrongRef();
|
||||||
|
return p;
|
||||||
|
}()}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT> const& rhs)
|
||||||
|
: ptr_{[&] {
|
||||||
|
auto p = rhs.unsafeGetRawPtr();
|
||||||
|
if (p)
|
||||||
|
p->addStrongRef();
|
||||||
|
return p;
|
||||||
|
}()}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive&& rhs)
|
||||||
|
: ptr_{rhs.unsafeExchange(nullptr)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT>&& rhs)
|
||||||
|
: ptr_{rhs.unsafeExchange(nullptr)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
SharedIntrusive<T>&
|
||||||
|
SharedIntrusive<T>::operator=(SharedIntrusive const& rhs)
|
||||||
|
{
|
||||||
|
if (this == &rhs)
|
||||||
|
return *this;
|
||||||
|
auto p = rhs.unsafeGetRawPtr();
|
||||||
|
if (p)
|
||||||
|
p->addStrongRef();
|
||||||
|
unsafeReleaseAndStore(p);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
// clang-format off
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
// clang-format on
|
||||||
|
SharedIntrusive<T>&
|
||||||
|
SharedIntrusive<T>::operator=(SharedIntrusive<TT> const& rhs)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<T, TT>)
|
||||||
|
{
|
||||||
|
// This case should never be hit. The operator above will run instead.
|
||||||
|
// (The normal operator= is needed or it will be marked `deleted`)
|
||||||
|
if (this == &rhs)
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
auto p = rhs.unsafeGetRawPtr();
|
||||||
|
if (p)
|
||||||
|
p->addStrongRef();
|
||||||
|
unsafeReleaseAndStore(p);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedIntrusive<T>&
|
||||||
|
SharedIntrusive<T>::operator=(SharedIntrusive&& rhs)
|
||||||
|
{
|
||||||
|
if (this == &rhs)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
unsafeReleaseAndStore(rhs.unsafeExchange(nullptr));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
// clang-format off
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
// clang-format on
|
||||||
|
SharedIntrusive<T>&
|
||||||
|
SharedIntrusive<T>::operator=(SharedIntrusive<TT>&& rhs)
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
!std::is_same_v<T, TT>,
|
||||||
|
"This overload should not be instantiated for T == TT");
|
||||||
|
|
||||||
|
unsafeReleaseAndStore(rhs.unsafeExchange(nullptr));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedIntrusive<T>::operator!=(std::nullptr_t) const
|
||||||
|
{
|
||||||
|
return this->get() != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedIntrusive<T>::operator==(std::nullptr_t) const
|
||||||
|
{
|
||||||
|
return this->get() == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <CAdoptTag TAdoptTag>
|
||||||
|
void
|
||||||
|
SharedIntrusive<T>::adopt(T* p)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<
|
||||||
|
TAdoptTag,
|
||||||
|
SharedIntrusiveAdoptIncrementStrongTag>)
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
p->addStrongRef();
|
||||||
|
}
|
||||||
|
unsafeReleaseAndStore(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedIntrusive<T>::~SharedIntrusive()
|
||||||
|
{
|
||||||
|
unsafeReleaseAndStore(nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
SharedIntrusive<T>::SharedIntrusive(
|
||||||
|
StaticCastTagSharedIntrusive,
|
||||||
|
SharedIntrusive<TT> const& rhs)
|
||||||
|
: ptr_{[&] {
|
||||||
|
auto p = static_cast<T*>(rhs.unsafeGetRawPtr());
|
||||||
|
if (p)
|
||||||
|
p->addStrongRef();
|
||||||
|
return p;
|
||||||
|
}()}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
SharedIntrusive<T>::SharedIntrusive(
|
||||||
|
StaticCastTagSharedIntrusive,
|
||||||
|
SharedIntrusive<TT>&& rhs)
|
||||||
|
: ptr_{static_cast<T*>(rhs.unsafeExchange(nullptr))}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
SharedIntrusive<T>::SharedIntrusive(
|
||||||
|
DynamicCastTagSharedIntrusive,
|
||||||
|
SharedIntrusive<TT> const& rhs)
|
||||||
|
: ptr_{[&] {
|
||||||
|
auto p = dynamic_cast<T*>(rhs.unsafeGetRawPtr());
|
||||||
|
if (p)
|
||||||
|
p->addStrongRef();
|
||||||
|
return p;
|
||||||
|
}()}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
SharedIntrusive<T>::SharedIntrusive(
|
||||||
|
DynamicCastTagSharedIntrusive,
|
||||||
|
SharedIntrusive<TT>&& rhs)
|
||||||
|
{
|
||||||
|
// This can be simplified without the `exchange`, but the `exchange` is kept
|
||||||
|
// in anticipation of supporting atomic operations.
|
||||||
|
auto toSet = rhs.unsafeExchange(nullptr);
|
||||||
|
if (toSet)
|
||||||
|
{
|
||||||
|
ptr_ = dynamic_cast<T*>(toSet);
|
||||||
|
if (!ptr_)
|
||||||
|
// need to set the pointer back or will leak
|
||||||
|
rhs.unsafeExchange(toSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T&
|
||||||
|
SharedIntrusive<T>::operator*() const noexcept
|
||||||
|
{
|
||||||
|
return *unsafeGetRawPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T*
|
||||||
|
SharedIntrusive<T>::operator->() const noexcept
|
||||||
|
{
|
||||||
|
return unsafeGetRawPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedIntrusive<T>::operator bool() const noexcept
|
||||||
|
{
|
||||||
|
return bool(unsafeGetRawPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
SharedIntrusive<T>::reset()
|
||||||
|
{
|
||||||
|
unsafeReleaseAndStore(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T*
|
||||||
|
SharedIntrusive<T>::get() const
|
||||||
|
{
|
||||||
|
return unsafeGetRawPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::size_t
|
||||||
|
SharedIntrusive<T>::use_count() const
|
||||||
|
{
|
||||||
|
if (auto p = unsafeGetRawPtr())
|
||||||
|
return p->use_count();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T*
|
||||||
|
SharedIntrusive<T>::unsafeGetRawPtr() const
|
||||||
|
{
|
||||||
|
return ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
SharedIntrusive<T>::unsafeSetRawPtr(T* p)
|
||||||
|
{
|
||||||
|
ptr_ = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T*
|
||||||
|
SharedIntrusive<T>::unsafeExchange(T* p)
|
||||||
|
{
|
||||||
|
return std::exchange(ptr_, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
SharedIntrusive<T>::unsafeReleaseAndStore(T* next)
|
||||||
|
{
|
||||||
|
auto prev = unsafeExchange(next);
|
||||||
|
if (!prev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using enum ReleaseStrongRefAction;
|
||||||
|
auto action = prev->releaseStrongRef();
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case noop:
|
||||||
|
break;
|
||||||
|
case destroy:
|
||||||
|
delete prev;
|
||||||
|
break;
|
||||||
|
case partialDestroy:
|
||||||
|
prev->partialDestructor();
|
||||||
|
partialDestructorFinished(&prev);
|
||||||
|
// prev is null and may no longer be used
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
WeakIntrusive<T>::WeakIntrusive(WeakIntrusive const& rhs) : ptr_{rhs.ptr_}
|
||||||
|
{
|
||||||
|
if (ptr_)
|
||||||
|
ptr_->addWeakRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
WeakIntrusive<T>::WeakIntrusive(WeakIntrusive&& rhs) : ptr_{rhs.ptr_}
|
||||||
|
{
|
||||||
|
rhs.ptr_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
WeakIntrusive<T>::WeakIntrusive(SharedIntrusive<T> const& rhs)
|
||||||
|
: ptr_{rhs.unsafeGetRawPtr()}
|
||||||
|
{
|
||||||
|
if (ptr_)
|
||||||
|
ptr_->addWeakRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
// clang-format off
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
// clang-format on
|
||||||
|
WeakIntrusive<T>&
|
||||||
|
WeakIntrusive<T>::operator=(SharedIntrusive<TT> const& rhs)
|
||||||
|
{
|
||||||
|
unsafeReleaseNoStore();
|
||||||
|
auto p = rhs.unsafeGetRawPtr();
|
||||||
|
if (p)
|
||||||
|
p->addWeakRef();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
WeakIntrusive<T>::adopt(T* ptr)
|
||||||
|
{
|
||||||
|
unsafeReleaseNoStore();
|
||||||
|
if (ptr)
|
||||||
|
ptr->addWeakRef();
|
||||||
|
ptr_ = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
WeakIntrusive<T>::~WeakIntrusive()
|
||||||
|
{
|
||||||
|
unsafeReleaseNoStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedIntrusive<T>
|
||||||
|
WeakIntrusive<T>::lock() const
|
||||||
|
{
|
||||||
|
if (ptr_ && ptr_->checkoutStrongRefFromWeak())
|
||||||
|
{
|
||||||
|
return SharedIntrusive<T>{ptr_, SharedIntrusiveAdoptNoIncrementTag{}};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
WeakIntrusive<T>::expired() const
|
||||||
|
{
|
||||||
|
return (!ptr_ || ptr_->expired());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
WeakIntrusive<T>::reset()
|
||||||
|
{
|
||||||
|
unsafeReleaseNoStore();
|
||||||
|
ptr_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
WeakIntrusive<T>::unsafeReleaseNoStore()
|
||||||
|
{
|
||||||
|
if (!ptr_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using enum ReleaseWeakRefAction;
|
||||||
|
auto action = ptr_->releaseWeakRef();
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case noop:
|
||||||
|
break;
|
||||||
|
case destroy:
|
||||||
|
delete ptr_;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedWeakUnion<T>::SharedWeakUnion(SharedWeakUnion const& rhs) : tp_{rhs.tp_}
|
||||||
|
{
|
||||||
|
auto p = rhs.unsafeGetRawPtr();
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (rhs.isStrong())
|
||||||
|
p->addStrongRef();
|
||||||
|
else
|
||||||
|
p->addWeakRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakUnion<T>::SharedWeakUnion(SharedIntrusive<TT> const& rhs)
|
||||||
|
{
|
||||||
|
auto p = rhs.unsafeGetRawPtr();
|
||||||
|
if (p)
|
||||||
|
p->addStrongRef();
|
||||||
|
unsafeSetRawPtr(p, RefStrength::strong);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedWeakUnion<T>::SharedWeakUnion(SharedWeakUnion&& rhs) : tp_{rhs.tp_}
|
||||||
|
{
|
||||||
|
rhs.unsafeSetRawPtr(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakUnion<T>::SharedWeakUnion(SharedIntrusive<TT>&& rhs)
|
||||||
|
{
|
||||||
|
auto p = rhs.unsafeGetRawPtr();
|
||||||
|
if (p)
|
||||||
|
unsafeSetRawPtr(p, RefStrength::strong);
|
||||||
|
rhs.unsafeSetRawPtr(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedWeakUnion<T>&
|
||||||
|
SharedWeakUnion<T>::operator=(SharedWeakUnion const& rhs)
|
||||||
|
{
|
||||||
|
if (this == &rhs)
|
||||||
|
return *this;
|
||||||
|
unsafeReleaseNoStore();
|
||||||
|
|
||||||
|
if (auto p = rhs.unsafeGetRawPtr())
|
||||||
|
{
|
||||||
|
if (rhs.isStrong())
|
||||||
|
{
|
||||||
|
p->addStrongRef();
|
||||||
|
unsafeSetRawPtr(p, RefStrength::strong);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->addWeakRef();
|
||||||
|
unsafeSetRawPtr(p, RefStrength::weak);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsafeSetRawPtr(nullptr);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
// clang-format off
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
// clang-format on
|
||||||
|
SharedWeakUnion<T>&
|
||||||
|
SharedWeakUnion<T>::operator=(SharedIntrusive<TT> const& rhs)
|
||||||
|
{
|
||||||
|
unsafeReleaseNoStore();
|
||||||
|
auto p = rhs.unsafeGetRawPtr();
|
||||||
|
if (p)
|
||||||
|
p->addStrongRef();
|
||||||
|
unsafeSetRawPtr(p, RefStrength::strong);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
// clang-format off
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
// clang-format on
|
||||||
|
SharedWeakUnion<T>&
|
||||||
|
SharedWeakUnion<T>::operator=(SharedIntrusive<TT>&& rhs)
|
||||||
|
{
|
||||||
|
unsafeReleaseNoStore();
|
||||||
|
unsafeSetRawPtr(rhs.unsafeGetRawPtr(), RefStrength::strong);
|
||||||
|
rhs.unsafeSetRawPtr(nullptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedWeakUnion<T>::~SharedWeakUnion()
|
||||||
|
{
|
||||||
|
unsafeReleaseNoStore();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return a strong pointer if this is already a strong pointer (i.e. don't
|
||||||
|
// lock the weak pointer. Use the `lock` method if that's what's needed)
|
||||||
|
template <class T>
|
||||||
|
SharedIntrusive<T>
|
||||||
|
SharedWeakUnion<T>::getStrong() const
|
||||||
|
{
|
||||||
|
SharedIntrusive<T> result;
|
||||||
|
auto p = unsafeGetRawPtr();
|
||||||
|
if (p && isStrong())
|
||||||
|
{
|
||||||
|
result.template adopt<SharedIntrusiveAdoptIncrementStrongTag>(p);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedWeakUnion<T>::operator bool() const noexcept
|
||||||
|
{
|
||||||
|
return bool(get());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
SharedWeakUnion<T>::reset()
|
||||||
|
{
|
||||||
|
unsafeReleaseNoStore();
|
||||||
|
unsafeSetRawPtr(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T*
|
||||||
|
SharedWeakUnion<T>::get() const
|
||||||
|
{
|
||||||
|
return isStrong() ? unsafeGetRawPtr() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::size_t
|
||||||
|
SharedWeakUnion<T>::use_count() const
|
||||||
|
{
|
||||||
|
if (auto p = get())
|
||||||
|
return p->use_count();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedWeakUnion<T>::expired() const
|
||||||
|
{
|
||||||
|
auto p = unsafeGetRawPtr();
|
||||||
|
return (!p || p->expired());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedIntrusive<T>
|
||||||
|
SharedWeakUnion<T>::lock() const
|
||||||
|
{
|
||||||
|
SharedIntrusive<T> result;
|
||||||
|
auto p = unsafeGetRawPtr();
|
||||||
|
if (!p)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (isStrong())
|
||||||
|
{
|
||||||
|
result.template adopt<SharedIntrusiveAdoptIncrementStrongTag>(p);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->checkoutStrongRefFromWeak())
|
||||||
|
{
|
||||||
|
result.template adopt<SharedIntrusiveAdoptNoIncrementTag>(p);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedWeakUnion<T>::isStrong() const
|
||||||
|
{
|
||||||
|
return !(tp_ & tagMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedWeakUnion<T>::isWeak() const
|
||||||
|
{
|
||||||
|
return tp_ & tagMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedWeakUnion<T>::convertToStrong()
|
||||||
|
{
|
||||||
|
if (isStrong())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto p = unsafeGetRawPtr();
|
||||||
|
if (p && p->checkoutStrongRefFromWeak())
|
||||||
|
{
|
||||||
|
[[maybe_unused]] auto action = p->releaseWeakRef();
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(action == ReleaseWeakRefAction::noop),
|
||||||
|
"ripple::SharedWeakUnion::convertToStrong : "
|
||||||
|
"action is noop");
|
||||||
|
unsafeSetRawPtr(p, RefStrength::strong);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedWeakUnion<T>::convertToWeak()
|
||||||
|
{
|
||||||
|
if (isWeak())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto p = unsafeGetRawPtr();
|
||||||
|
if (!p)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
using enum ReleaseStrongRefAction;
|
||||||
|
auto action = p->addWeakReleaseStrongRef();
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case noop:
|
||||||
|
break;
|
||||||
|
case destroy:
|
||||||
|
// We just added a weak ref. How could we destroy?
|
||||||
|
UNREACHABLE(
|
||||||
|
"ripple::SharedWeakUnion::convertToWeak : destroying freshly "
|
||||||
|
"added ref");
|
||||||
|
delete p;
|
||||||
|
unsafeSetRawPtr(nullptr);
|
||||||
|
return true; // Should never happen
|
||||||
|
case partialDestroy:
|
||||||
|
// This is a weird case. We just converted the last strong
|
||||||
|
// pointer to a weak pointer.
|
||||||
|
p->partialDestructor();
|
||||||
|
partialDestructorFinished(&p);
|
||||||
|
// p is null and may no longer be used
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unsafeSetRawPtr(p, RefStrength::weak);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T*
|
||||||
|
SharedWeakUnion<T>::unsafeGetRawPtr() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T*>(tp_ & ptrMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
SharedWeakUnion<T>::unsafeSetRawPtr(T* p, RefStrength rs)
|
||||||
|
{
|
||||||
|
tp_ = reinterpret_cast<std::uintptr_t>(p);
|
||||||
|
if (tp_ && rs == RefStrength::weak)
|
||||||
|
tp_ |= tagMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
SharedWeakUnion<T>::unsafeSetRawPtr(std::nullptr_t)
|
||||||
|
{
|
||||||
|
tp_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
SharedWeakUnion<T>::unsafeReleaseNoStore()
|
||||||
|
{
|
||||||
|
auto p = unsafeGetRawPtr();
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (isStrong())
|
||||||
|
{
|
||||||
|
using enum ReleaseStrongRefAction;
|
||||||
|
auto strongAction = p->releaseStrongRef();
|
||||||
|
switch (strongAction)
|
||||||
|
{
|
||||||
|
case noop:
|
||||||
|
break;
|
||||||
|
case destroy:
|
||||||
|
delete p;
|
||||||
|
break;
|
||||||
|
case partialDestroy:
|
||||||
|
p->partialDestructor();
|
||||||
|
partialDestructorFinished(&p);
|
||||||
|
// p is null and may no longer be used
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using enum ReleaseWeakRefAction;
|
||||||
|
auto weakAction = p->releaseWeakRef();
|
||||||
|
switch (weakAction)
|
||||||
|
{
|
||||||
|
case noop:
|
||||||
|
break;
|
||||||
|
case destroy:
|
||||||
|
delete p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
#endif
|
||||||
502
include/xrpl/basics/IntrusiveRefCounts.h
Normal file
502
include/xrpl/basics/IntrusiveRefCounts.h
Normal file
@@ -0,0 +1,502 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2023 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_BASICS_INTRUSIVEREFCOUNTS_H_INCLUDED
|
||||||
|
#define RIPPLE_BASICS_INTRUSIVEREFCOUNTS_H_INCLUDED
|
||||||
|
|
||||||
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
/** Action to perform when releasing a strong pointer.
|
||||||
|
|
||||||
|
noop: Do nothing. For example, a `noop` action will occur when a count is
|
||||||
|
decremented to a non-zero value.
|
||||||
|
|
||||||
|
partialDestroy: Run the `partialDestructor`. This action will happen when a
|
||||||
|
strong count is decremented to zero and the weak count is non-zero.
|
||||||
|
|
||||||
|
destroy: Run the destructor. This action will occur when either the strong
|
||||||
|
count or weak count is decremented and the other count is also zero.
|
||||||
|
*/
|
||||||
|
enum class ReleaseStrongRefAction { noop, partialDestroy, destroy };
|
||||||
|
|
||||||
|
/** Action to perform when releasing a weak pointer.
|
||||||
|
|
||||||
|
noop: Do nothing. For example, a `noop` action will occur when a count is
|
||||||
|
decremented to a non-zero value.
|
||||||
|
|
||||||
|
destroy: Run the destructor. This action will occur when either the strong
|
||||||
|
count or weak count is decremented and the other count is also zero.
|
||||||
|
*/
|
||||||
|
enum class ReleaseWeakRefAction { noop, destroy };
|
||||||
|
|
||||||
|
/** Implement the strong count, weak count, and bit flags for an intrusive
|
||||||
|
pointer.
|
||||||
|
|
||||||
|
A class can satisfy the requirements of a ripple::IntrusivePointer by
|
||||||
|
inheriting from this class.
|
||||||
|
*/
|
||||||
|
struct IntrusiveRefCounts
|
||||||
|
{
|
||||||
|
virtual ~IntrusiveRefCounts() noexcept;
|
||||||
|
|
||||||
|
// This must be `noexcept` or the make_SharedIntrusive function could leak
|
||||||
|
// memory.
|
||||||
|
void
|
||||||
|
addStrongRef() const noexcept;
|
||||||
|
|
||||||
|
void
|
||||||
|
addWeakRef() const noexcept;
|
||||||
|
|
||||||
|
ReleaseStrongRefAction
|
||||||
|
releaseStrongRef() const;
|
||||||
|
|
||||||
|
// Same as:
|
||||||
|
// {
|
||||||
|
// addWeakRef();
|
||||||
|
// return releaseStrongRef;
|
||||||
|
// }
|
||||||
|
// done as one atomic operation
|
||||||
|
ReleaseStrongRefAction
|
||||||
|
addWeakReleaseStrongRef() const;
|
||||||
|
|
||||||
|
ReleaseWeakRefAction
|
||||||
|
releaseWeakRef() const;
|
||||||
|
|
||||||
|
// Returns true is able to checkout a strong ref. False otherwise
|
||||||
|
bool
|
||||||
|
checkoutStrongRefFromWeak() const noexcept;
|
||||||
|
|
||||||
|
bool
|
||||||
|
expired() const noexcept;
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
use_count() const noexcept;
|
||||||
|
|
||||||
|
// This function MUST be called after a partial destructor finishes running.
|
||||||
|
// Calling this function may cause other threads to delete the object
|
||||||
|
// pointed to by `o`, so `o` should never be used after calling this
|
||||||
|
// function. The parameter will be set to a `nullptr` after calling this
|
||||||
|
// function to emphasize that it should not be used.
|
||||||
|
// Note: This is intentionally NOT called at the end of `partialDestructor`.
|
||||||
|
// The reason for this is if new classes are written to support this smart
|
||||||
|
// pointer class, they need to write their own `partialDestructor` function
|
||||||
|
// and ensure `partialDestructorFinished` is called at the end. Putting this
|
||||||
|
// call inside the smart pointer class itself is expected to be less error
|
||||||
|
// prone.
|
||||||
|
// Note: The "two-star" programming is intentional. It emphasizes that `o`
|
||||||
|
// may be deleted and the unergonomic API is meant to signal the special
|
||||||
|
// nature of this function call to callers.
|
||||||
|
// Note: This is a template to support incompletely defined classes.
|
||||||
|
template <class T>
|
||||||
|
friend void
|
||||||
|
partialDestructorFinished(T** o);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// TODO: We may need to use a uint64_t for both counts. This will reduce the
|
||||||
|
// memory savings. We need to audit the code to make sure 16 bit counts are
|
||||||
|
// enough for strong pointers and 14 bit counts are enough for weak
|
||||||
|
// pointers. Use type aliases to make it easy to switch types.
|
||||||
|
using CountType = std::uint16_t;
|
||||||
|
static constexpr size_t StrongCountNumBits = sizeof(CountType) * 8;
|
||||||
|
static constexpr size_t WeakCountNumBits = StrongCountNumBits - 2;
|
||||||
|
using FieldType = std::uint32_t;
|
||||||
|
static constexpr size_t FieldTypeBits = sizeof(FieldType) * 8;
|
||||||
|
static constexpr FieldType one = 1;
|
||||||
|
|
||||||
|
/** `refCounts` consists of four fields that are treated atomically:
|
||||||
|
|
||||||
|
1. Strong count. This is a count of the number of shared pointers that
|
||||||
|
hold a reference to this object. When the strong counts goes to zero,
|
||||||
|
if the weak count is zero, the destructor is run. If the weak count is
|
||||||
|
non-zero when the strong count goes to zero then the partialDestructor
|
||||||
|
is run.
|
||||||
|
|
||||||
|
2. Weak count. This is a count of the number of weak pointer that hold
|
||||||
|
a reference to this object. When the weak count goes to zero and the
|
||||||
|
strong count is also zero, then the destructor is run.
|
||||||
|
|
||||||
|
3. Partial destroy started bit. This bit is set if the
|
||||||
|
`partialDestructor` function has been started (or is about to be
|
||||||
|
started). This is used to prevent the destructor from running
|
||||||
|
concurrently with the partial destructor. This can easily happen when
|
||||||
|
the last strong pointer release its reference in one thread and starts
|
||||||
|
the partialDestructor, while in another thread the last weak pointer
|
||||||
|
goes out of scope and starts the destructor while the partialDestructor
|
||||||
|
is still running. Both a start and finished bit is needed to handle a
|
||||||
|
corner-case where the last strong pointer goes out of scope, then then
|
||||||
|
last `weakPointer` goes out of scope, but this happens before the
|
||||||
|
`partialDestructor` bit is set. It would be possible to use a single
|
||||||
|
bit if it could also be set atomically when the strong count goes to
|
||||||
|
zero and the weak count is non-zero, but that would add complexity (and
|
||||||
|
likely slow down common cases as well).
|
||||||
|
|
||||||
|
4. Partial destroy finished bit. This bit is set when the
|
||||||
|
`partialDestructor` has finished running. See (3) above for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
mutable std::atomic<FieldType> refCounts{strongDelta};
|
||||||
|
|
||||||
|
/** Amount to change the strong count when adding or releasing a reference
|
||||||
|
|
||||||
|
Note: The strong count is stored in the low `StrongCountNumBits` bits
|
||||||
|
of refCounts
|
||||||
|
*/
|
||||||
|
static constexpr FieldType strongDelta = 1;
|
||||||
|
|
||||||
|
/** Amount to change the weak count when adding or releasing a reference
|
||||||
|
|
||||||
|
Note: The weak count is stored in the high `WeakCountNumBits` bits of
|
||||||
|
refCounts
|
||||||
|
*/
|
||||||
|
static constexpr FieldType weakDelta = (one << StrongCountNumBits);
|
||||||
|
|
||||||
|
/** Flag that is set when the partialDestroy function has started running
|
||||||
|
(or is about to start running).
|
||||||
|
|
||||||
|
See description of the `refCounts` field for a fuller description of
|
||||||
|
this field.
|
||||||
|
*/
|
||||||
|
static constexpr FieldType partialDestroyStartedMask =
|
||||||
|
(one << (FieldTypeBits - 1));
|
||||||
|
|
||||||
|
/** Flag that is set when the partialDestroy function has finished running
|
||||||
|
|
||||||
|
See description of the `refCounts` field for a fuller description of
|
||||||
|
this field.
|
||||||
|
*/
|
||||||
|
static constexpr FieldType partialDestroyFinishedMask =
|
||||||
|
(one << (FieldTypeBits - 2));
|
||||||
|
|
||||||
|
/** Mask that will zero out all the `count` bits and leave the tag bits
|
||||||
|
unchanged.
|
||||||
|
*/
|
||||||
|
static constexpr FieldType tagMask =
|
||||||
|
partialDestroyStartedMask | partialDestroyFinishedMask;
|
||||||
|
|
||||||
|
/** Mask that will zero out the `tag` bits and leave the count bits
|
||||||
|
unchanged.
|
||||||
|
*/
|
||||||
|
static constexpr FieldType valueMask = ~tagMask;
|
||||||
|
|
||||||
|
/** Mask that will zero out everything except the strong count.
|
||||||
|
*/
|
||||||
|
static constexpr FieldType strongMask =
|
||||||
|
((one << StrongCountNumBits) - 1) & valueMask;
|
||||||
|
|
||||||
|
/** Mask that will zero out everything except the weak count.
|
||||||
|
*/
|
||||||
|
static constexpr FieldType weakMask =
|
||||||
|
(((one << WeakCountNumBits) - 1) << StrongCountNumBits) & valueMask;
|
||||||
|
|
||||||
|
/** Unpack the count and tag fields from the packed atomic integer form. */
|
||||||
|
struct RefCountPair
|
||||||
|
{
|
||||||
|
CountType strong;
|
||||||
|
CountType weak;
|
||||||
|
/** The `partialDestroyStartedBit` is set to on when the partial
|
||||||
|
destroy function is started. It is not a boolean; it is a uint32
|
||||||
|
with all bits zero with the possible exception of the
|
||||||
|
`partialDestroyStartedMask` bit. This is done so it can be directly
|
||||||
|
masked into the `combinedValue`.
|
||||||
|
*/
|
||||||
|
FieldType partialDestroyStartedBit{0};
|
||||||
|
/** The `partialDestroyFinishedBit` is set to on when the partial
|
||||||
|
destroy function has finished.
|
||||||
|
*/
|
||||||
|
FieldType partialDestroyFinishedBit{0};
|
||||||
|
RefCountPair(FieldType v) noexcept;
|
||||||
|
RefCountPair(CountType s, CountType w) noexcept;
|
||||||
|
|
||||||
|
/** Convert back to the packed integer form. */
|
||||||
|
FieldType
|
||||||
|
combinedValue() const noexcept;
|
||||||
|
|
||||||
|
static constexpr CountType maxStrongValue =
|
||||||
|
static_cast<CountType>((one << StrongCountNumBits) - 1);
|
||||||
|
static constexpr CountType maxWeakValue =
|
||||||
|
static_cast<CountType>((one << WeakCountNumBits) - 1);
|
||||||
|
/** Put an extra margin to detect when running up against limits.
|
||||||
|
This is only used in debug code, and is useful if we reduce the
|
||||||
|
number of bits in the strong and weak counts (to 16 and 14 bits).
|
||||||
|
*/
|
||||||
|
static constexpr CountType checkStrongMaxValue = maxStrongValue - 32;
|
||||||
|
static constexpr CountType checkWeakMaxValue = maxWeakValue - 32;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void
|
||||||
|
IntrusiveRefCounts::addStrongRef() const noexcept
|
||||||
|
{
|
||||||
|
refCounts.fetch_add(strongDelta, std::memory_order_acq_rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
IntrusiveRefCounts::addWeakRef() const noexcept
|
||||||
|
{
|
||||||
|
refCounts.fetch_add(weakDelta, std::memory_order_acq_rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ReleaseStrongRefAction
|
||||||
|
IntrusiveRefCounts::releaseStrongRef() const
|
||||||
|
{
|
||||||
|
// Subtract `strongDelta` from refCounts. If this releases the last strong
|
||||||
|
// ref, set the `partialDestroyStarted` bit. It is important that the ref
|
||||||
|
// count and the `partialDestroyStartedBit` are changed atomically (hence
|
||||||
|
// the loop and `compare_exchange` op). If this didn't need to be done
|
||||||
|
// atomically, the loop could be replaced with a `fetch_sub` and a
|
||||||
|
// conditional `fetch_or`. This loop will almost always run once.
|
||||||
|
|
||||||
|
using enum ReleaseStrongRefAction;
|
||||||
|
auto prevIntVal = refCounts.load(std::memory_order_acquire);
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
RefCountPair const prevVal{prevIntVal};
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(prevVal.strong >= strongDelta),
|
||||||
|
"ripple::IntrusiveRefCounts::releaseStrongRef : previous ref "
|
||||||
|
"higher than new");
|
||||||
|
auto nextIntVal = prevIntVal - strongDelta;
|
||||||
|
ReleaseStrongRefAction action = noop;
|
||||||
|
if (prevVal.strong == 1)
|
||||||
|
{
|
||||||
|
if (prevVal.weak == 0)
|
||||||
|
{
|
||||||
|
action = destroy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nextIntVal |= partialDestroyStartedMask;
|
||||||
|
action = partialDestroy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refCounts.compare_exchange_weak(
|
||||||
|
prevIntVal, nextIntVal, std::memory_order_acq_rel))
|
||||||
|
{
|
||||||
|
// Can't be in partial destroy because only decrementing the strong
|
||||||
|
// count to zero can start a partial destroy, and that can't happen
|
||||||
|
// twice.
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(action == noop) || !(prevIntVal & partialDestroyStartedMask),
|
||||||
|
"ripple::IntrusiveRefCounts::releaseStrongRef : not in partial "
|
||||||
|
"destroy");
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ReleaseStrongRefAction
|
||||||
|
IntrusiveRefCounts::addWeakReleaseStrongRef() const
|
||||||
|
{
|
||||||
|
using enum ReleaseStrongRefAction;
|
||||||
|
|
||||||
|
static_assert(weakDelta > strongDelta);
|
||||||
|
auto constexpr delta = weakDelta - strongDelta;
|
||||||
|
auto prevIntVal = refCounts.load(std::memory_order_acquire);
|
||||||
|
// This loop will almost always run once. The loop is needed to atomically
|
||||||
|
// change the counts and flags (the count could be atomically changed, but
|
||||||
|
// the flags depend on the current value of the counts).
|
||||||
|
//
|
||||||
|
// Note: If this becomes a perf bottleneck, the `partialDestoryStartedMask`
|
||||||
|
// may be able to be set non-atomically. But it is easier to reason about
|
||||||
|
// the code if the flag is set atomically.
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
RefCountPair const prevVal{prevIntVal};
|
||||||
|
// Converted the last strong pointer to a weak pointer.
|
||||||
|
//
|
||||||
|
// Can't be in partial destroy because only decrementing the
|
||||||
|
// strong count to zero can start a partial destroy, and that
|
||||||
|
// can't happen twice.
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(!prevVal.partialDestroyStartedBit),
|
||||||
|
"ripple::IntrusiveRefCounts::addWeakReleaseStrongRef : not in "
|
||||||
|
"partial destroy");
|
||||||
|
|
||||||
|
auto nextIntVal = prevIntVal + delta;
|
||||||
|
ReleaseStrongRefAction action = noop;
|
||||||
|
if (prevVal.strong == 1)
|
||||||
|
{
|
||||||
|
if (prevVal.weak == 0)
|
||||||
|
{
|
||||||
|
action = noop;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nextIntVal |= partialDestroyStartedMask;
|
||||||
|
action = partialDestroy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (refCounts.compare_exchange_weak(
|
||||||
|
prevIntVal, nextIntVal, std::memory_order_acq_rel))
|
||||||
|
{
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(!(prevIntVal & partialDestroyStartedMask)),
|
||||||
|
"ripple::IntrusiveRefCounts::addWeakReleaseStrongRef : not "
|
||||||
|
"started partial destroy");
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ReleaseWeakRefAction
|
||||||
|
IntrusiveRefCounts::releaseWeakRef() const
|
||||||
|
{
|
||||||
|
auto prevIntVal = refCounts.fetch_sub(weakDelta, std::memory_order_acq_rel);
|
||||||
|
RefCountPair prev = prevIntVal;
|
||||||
|
if (prev.weak == 1 && prev.strong == 0)
|
||||||
|
{
|
||||||
|
if (!prev.partialDestroyStartedBit)
|
||||||
|
{
|
||||||
|
// This case should only be hit if the partialDestroyStartedBit is
|
||||||
|
// set non-atomically (and even then very rarely). The code is kept
|
||||||
|
// in case we need to set the flag non-atomically for perf reasons.
|
||||||
|
refCounts.wait(prevIntVal, std::memory_order_acquire);
|
||||||
|
prevIntVal = refCounts.load(std::memory_order_acquire);
|
||||||
|
prev = RefCountPair{prevIntVal};
|
||||||
|
}
|
||||||
|
if (!prev.partialDestroyFinishedBit)
|
||||||
|
{
|
||||||
|
// partial destroy MUST finish before running a full destroy (when
|
||||||
|
// using weak pointers)
|
||||||
|
refCounts.wait(prevIntVal - weakDelta, std::memory_order_acquire);
|
||||||
|
}
|
||||||
|
return ReleaseWeakRefAction::destroy;
|
||||||
|
}
|
||||||
|
return ReleaseWeakRefAction::noop;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
IntrusiveRefCounts::checkoutStrongRefFromWeak() const noexcept
|
||||||
|
{
|
||||||
|
auto curValue = RefCountPair{1, 1}.combinedValue();
|
||||||
|
auto desiredValue = RefCountPair{2, 1}.combinedValue();
|
||||||
|
|
||||||
|
while (!refCounts.compare_exchange_weak(
|
||||||
|
curValue, desiredValue, std::memory_order_acq_rel))
|
||||||
|
{
|
||||||
|
RefCountPair const prev{curValue};
|
||||||
|
if (!prev.strong)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
desiredValue = curValue + strongDelta;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
IntrusiveRefCounts::expired() const noexcept
|
||||||
|
{
|
||||||
|
RefCountPair const val = refCounts.load(std::memory_order_acquire);
|
||||||
|
return val.strong == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t
|
||||||
|
IntrusiveRefCounts::use_count() const noexcept
|
||||||
|
{
|
||||||
|
RefCountPair const val = refCounts.load(std::memory_order_acquire);
|
||||||
|
return val.strong;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
auto v = refCounts.load(std::memory_order_acquire);
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(!(v & valueMask)),
|
||||||
|
"ripple::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
|
||||||
|
auto t = v & tagMask;
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(!t || t == tagMask),
|
||||||
|
"ripple::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
inline IntrusiveRefCounts::RefCountPair::RefCountPair(
|
||||||
|
IntrusiveRefCounts::FieldType v) noexcept
|
||||||
|
: strong{static_cast<CountType>(v & strongMask)}
|
||||||
|
, weak{static_cast<CountType>((v & weakMask) >> StrongCountNumBits)}
|
||||||
|
, partialDestroyStartedBit{v & partialDestroyStartedMask}
|
||||||
|
, partialDestroyFinishedBit{v & partialDestroyFinishedMask}
|
||||||
|
{
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
|
||||||
|
"ripple::IntrusiveRefCounts::RefCountPair(FieldType) : inputs inside "
|
||||||
|
"range");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IntrusiveRefCounts::RefCountPair::RefCountPair(
|
||||||
|
IntrusiveRefCounts::CountType s,
|
||||||
|
IntrusiveRefCounts::CountType w) noexcept
|
||||||
|
: strong{s}, weak{w}
|
||||||
|
{
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
|
||||||
|
"ripple::IntrusiveRefCounts::RefCountPair(CountType, CountType) : "
|
||||||
|
"inputs inside range");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline IntrusiveRefCounts::FieldType
|
||||||
|
IntrusiveRefCounts::RefCountPair::combinedValue() const noexcept
|
||||||
|
{
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
|
||||||
|
"ripple::IntrusiveRefCounts::RefCountPair::combinedValue : inputs "
|
||||||
|
"inside range");
|
||||||
|
return (static_cast<IntrusiveRefCounts::FieldType>(weak)
|
||||||
|
<< IntrusiveRefCounts::StrongCountNumBits) |
|
||||||
|
static_cast<IntrusiveRefCounts::FieldType>(strong) |
|
||||||
|
partialDestroyStartedBit | partialDestroyFinishedBit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline void
|
||||||
|
partialDestructorFinished(T** o)
|
||||||
|
{
|
||||||
|
T& self = **o;
|
||||||
|
IntrusiveRefCounts::RefCountPair p =
|
||||||
|
self.refCounts.fetch_or(IntrusiveRefCounts::partialDestroyFinishedMask);
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(!p.partialDestroyFinishedBit && p.partialDestroyStartedBit &&
|
||||||
|
!p.strong),
|
||||||
|
"ripple::partialDestructorFinished : not a weak ref");
|
||||||
|
if (!p.weak)
|
||||||
|
{
|
||||||
|
// There was a weak count before the partial destructor ran (or we would
|
||||||
|
// have run the full destructor) and now there isn't a weak count. Some
|
||||||
|
// thread is waiting to run the destructor.
|
||||||
|
self.refCounts.notify_one();
|
||||||
|
}
|
||||||
|
// Set the pointer to null to emphasize that the object shouldn't be used
|
||||||
|
// after calling this function as it may be destroyed in another thread.
|
||||||
|
*o = nullptr;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
#endif
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
#define RIPPLE_BASICS_LOCALVALUE_H_INCLUDED
|
#define RIPPLE_BASICS_LOCALVALUE_H_INCLUDED
|
||||||
|
|
||||||
#include <boost/thread/tss.hpp>
|
#include <boost/thread/tss.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,10 @@
|
|||||||
|
|
||||||
#include <xrpl/basics/UnorderedContainers.h>
|
#include <xrpl/basics/UnorderedContainers.h>
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
|
|
||||||
#include <boost/beast/core/string.hpp>
|
#include <boost/beast/core/string.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|||||||
@@ -4,37 +4,34 @@ Utility functions and classes.
|
|||||||
|
|
||||||
ripple/basic should contain no dependencies on other modules.
|
ripple/basic should contain no dependencies on other modules.
|
||||||
|
|
||||||
|
# Choosing a rippled container.
|
||||||
|
|
||||||
Choosing a rippled container.
|
- `std::vector`
|
||||||
=============================
|
- For ordered containers with most insertions or erases at the end.
|
||||||
|
|
||||||
* `std::vector`
|
- `std::deque`
|
||||||
* For ordered containers with most insertions or erases at the end.
|
- For ordered containers with most insertions or erases at the start or end.
|
||||||
|
|
||||||
* `std::deque`
|
- `std::list`
|
||||||
* For ordered containers with most insertions or erases at the start or end.
|
- For ordered containers with inserts and erases to the middle.
|
||||||
|
- For containers with iterators stable over insert and erase.
|
||||||
* `std::list`
|
- Generally slower and bigger than `std::vector` or `std::deque` except for
|
||||||
* For ordered containers with inserts and erases to the middle.
|
|
||||||
* For containers with iterators stable over insert and erase.
|
|
||||||
* Generally slower and bigger than `std::vector` or `std::deque` except for
|
|
||||||
those cases.
|
those cases.
|
||||||
|
|
||||||
* `std::set`
|
- `std::set`
|
||||||
* For sorted containers.
|
- For sorted containers.
|
||||||
|
|
||||||
* `ripple::hash_set`
|
- `ripple::hash_set`
|
||||||
* Where inserts and contains need to be O(1).
|
- Where inserts and contains need to be O(1).
|
||||||
* For "small" sets, `std::set` might be faster and smaller.
|
- For "small" sets, `std::set` might be faster and smaller.
|
||||||
|
|
||||||
* `ripple::hardened_hash_set`
|
- `ripple::hardened_hash_set`
|
||||||
* For data sets where the key could be manipulated by an attacker
|
- For data sets where the key could be manipulated by an attacker
|
||||||
in an attempt to mount an algorithmic complexity attack: see
|
in an attempt to mount an algorithmic complexity attack: see
|
||||||
http://en.wikipedia.org/wiki/Algorithmic_complexity_attack
|
http://en.wikipedia.org/wiki/Algorithmic_complexity_attack
|
||||||
|
|
||||||
|
|
||||||
The following container is deprecated
|
The following container is deprecated
|
||||||
|
|
||||||
* `std::unordered_set`
|
- `std::unordered_set`
|
||||||
* Use `ripple::hash_set` instead, which uses a better hashing algorithm.
|
- Use `ripple::hash_set` instead, which uses a better hashing algorithm.
|
||||||
* Or use `ripple::hardened_hash_set` to prevent algorithmic complexity attacks.
|
- Or use `ripple::hardened_hash_set` to prevent algorithmic complexity attacks.
|
||||||
|
|||||||
@@ -20,11 +20,11 @@
|
|||||||
#ifndef RIPPLE_BASICS_RESOLVER_H_INCLUDED
|
#ifndef RIPPLE_BASICS_RESOLVER_H_INCLUDED
|
||||||
#define RIPPLE_BASICS_RESOLVER_H_INCLUDED
|
#define RIPPLE_BASICS_RESOLVER_H_INCLUDED
|
||||||
|
|
||||||
|
#include <xrpl/beast/net/IPEndpoint.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <xrpl/beast/net/IPEndpoint.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
class Resolver
|
class Resolver
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <xrpl/basics/Resolver.h>
|
#include <xrpl/basics/Resolver.h>
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
|
|
||||||
#include <boost/asio/io_service.hpp>
|
#include <boost/asio/io_service.hpp>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|||||||
135
include/xrpl/basics/SharedWeakCachePointer.h
Normal file
135
include/xrpl/basics/SharedWeakCachePointer.h
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2023 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_H_INCLUDED
|
||||||
|
#define RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_H_INCLUDED
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
/** A combination of a std::shared_ptr and a std::weak_pointer.
|
||||||
|
|
||||||
|
|
||||||
|
This class is a wrapper to a `std::variant<std::shared_ptr,std::weak_ptr>`
|
||||||
|
This class is useful for storing intrusive pointers in tagged caches using less
|
||||||
|
memory than storing both pointers directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class SharedWeakCachePointer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SharedWeakCachePointer() = default;
|
||||||
|
|
||||||
|
SharedWeakCachePointer(SharedWeakCachePointer const& rhs);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakCachePointer(std::shared_ptr<TT> const& rhs);
|
||||||
|
|
||||||
|
SharedWeakCachePointer(SharedWeakCachePointer&& rhs);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakCachePointer(std::shared_ptr<TT>&& rhs);
|
||||||
|
|
||||||
|
SharedWeakCachePointer&
|
||||||
|
operator=(SharedWeakCachePointer const& rhs);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakCachePointer&
|
||||||
|
operator=(std::shared_ptr<TT> const& rhs);
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakCachePointer&
|
||||||
|
operator=(std::shared_ptr<TT>&& rhs);
|
||||||
|
|
||||||
|
~SharedWeakCachePointer();
|
||||||
|
|
||||||
|
/** Return a strong pointer if this is already a strong pointer (i.e. don't
|
||||||
|
lock the weak pointer. Use the `lock` method if that's what's needed)
|
||||||
|
*/
|
||||||
|
std::shared_ptr<T> const&
|
||||||
|
getStrong() const;
|
||||||
|
|
||||||
|
/** Return true if this is a strong pointer and the strong pointer is
|
||||||
|
seated.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
operator bool() const noexcept;
|
||||||
|
|
||||||
|
/** Set the pointer to null, decrement the appropriate ref count, and run
|
||||||
|
the appropriate release action.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
reset();
|
||||||
|
|
||||||
|
/** If this is a strong pointer, return the raw pointer. Otherwise return
|
||||||
|
null.
|
||||||
|
*/
|
||||||
|
T*
|
||||||
|
get() const;
|
||||||
|
|
||||||
|
/** If this is a strong pointer, return the strong count. Otherwise return 0
|
||||||
|
*/
|
||||||
|
std::size_t
|
||||||
|
use_count() const;
|
||||||
|
|
||||||
|
/** Return true if there is a non-zero strong count. */
|
||||||
|
bool
|
||||||
|
expired() const;
|
||||||
|
|
||||||
|
/** If this is a strong pointer, return the strong pointer. Otherwise
|
||||||
|
attempt to lock the weak pointer.
|
||||||
|
*/
|
||||||
|
std::shared_ptr<T>
|
||||||
|
lock() const;
|
||||||
|
|
||||||
|
/** Return true is this represents a strong pointer. */
|
||||||
|
bool
|
||||||
|
isStrong() const;
|
||||||
|
|
||||||
|
/** Return true is this represents a weak pointer. */
|
||||||
|
bool
|
||||||
|
isWeak() const;
|
||||||
|
|
||||||
|
/** If this is a weak pointer, attempt to convert it to a strong pointer.
|
||||||
|
|
||||||
|
@return true if successfully converted to a strong pointer (or was
|
||||||
|
already a strong pointer). Otherwise false.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
convertToStrong();
|
||||||
|
|
||||||
|
/** If this is a strong pointer, attempt to convert it to a weak pointer.
|
||||||
|
|
||||||
|
@return false if the pointer is null. Otherwise return true.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
convertToWeak();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::variant<std::shared_ptr<T>, std::weak_ptr<T>> combo_;
|
||||||
|
};
|
||||||
|
} // namespace ripple
|
||||||
|
#endif
|
||||||
192
include/xrpl/basics/SharedWeakCachePointer.ipp
Normal file
192
include/xrpl/basics/SharedWeakCachePointer.ipp
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2023 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_IPP_INCLUDED
|
||||||
|
#define RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_IPP_INCLUDED
|
||||||
|
|
||||||
|
#include <xrpl/basics/SharedWeakCachePointer.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
template <class T>
|
||||||
|
SharedWeakCachePointer<T>::SharedWeakCachePointer(
|
||||||
|
SharedWeakCachePointer const& rhs) = default;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakCachePointer<T>::SharedWeakCachePointer(
|
||||||
|
std::shared_ptr<TT> const& rhs)
|
||||||
|
: combo_{rhs}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedWeakCachePointer<T>::SharedWeakCachePointer(
|
||||||
|
SharedWeakCachePointer&& rhs) = default;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakCachePointer<T>::SharedWeakCachePointer(std::shared_ptr<TT>&& rhs)
|
||||||
|
: combo_{std::move(rhs)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedWeakCachePointer<T>&
|
||||||
|
SharedWeakCachePointer<T>::operator=(SharedWeakCachePointer const& rhs) =
|
||||||
|
default;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakCachePointer<T>&
|
||||||
|
SharedWeakCachePointer<T>::operator=(std::shared_ptr<TT> const& rhs)
|
||||||
|
{
|
||||||
|
combo_ = rhs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
template <class TT>
|
||||||
|
requires std::convertible_to<TT*, T*>
|
||||||
|
SharedWeakCachePointer<T>&
|
||||||
|
SharedWeakCachePointer<T>::operator=(std::shared_ptr<TT>&& rhs)
|
||||||
|
{
|
||||||
|
combo_ = std::move(rhs);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedWeakCachePointer<T>::~SharedWeakCachePointer() = default;
|
||||||
|
|
||||||
|
// Return a strong pointer if this is already a strong pointer (i.e. don't
|
||||||
|
// lock the weak pointer. Use the `lock` method if that's what's needed)
|
||||||
|
template <class T>
|
||||||
|
std::shared_ptr<T> const&
|
||||||
|
SharedWeakCachePointer<T>::getStrong() const
|
||||||
|
{
|
||||||
|
static std::shared_ptr<T> const empty;
|
||||||
|
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
|
||||||
|
return *p;
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
SharedWeakCachePointer<T>::operator bool() const noexcept
|
||||||
|
{
|
||||||
|
return !!std::get_if<std::shared_ptr<T>>(&combo_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
SharedWeakCachePointer<T>::reset()
|
||||||
|
{
|
||||||
|
combo_ = std::shared_ptr<T>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T*
|
||||||
|
SharedWeakCachePointer<T>::get() const
|
||||||
|
{
|
||||||
|
return std::get_if<std::shared_ptr<T>>(&combo_).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::size_t
|
||||||
|
SharedWeakCachePointer<T>::use_count() const
|
||||||
|
{
|
||||||
|
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
|
||||||
|
return p->use_count();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedWeakCachePointer<T>::expired() const
|
||||||
|
{
|
||||||
|
if (auto p = std::get_if<std::weak_ptr<T>>(&combo_))
|
||||||
|
return p->expired();
|
||||||
|
return !std::get_if<std::shared_ptr<T>>(&combo_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::shared_ptr<T>
|
||||||
|
SharedWeakCachePointer<T>::lock() const
|
||||||
|
{
|
||||||
|
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
|
||||||
|
return *p;
|
||||||
|
|
||||||
|
if (auto p = std::get_if<std::weak_ptr<T>>(&combo_))
|
||||||
|
return p->lock();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedWeakCachePointer<T>::isStrong() const
|
||||||
|
{
|
||||||
|
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
|
||||||
|
return !!p->get();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedWeakCachePointer<T>::isWeak() const
|
||||||
|
{
|
||||||
|
return !isStrong();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedWeakCachePointer<T>::convertToStrong()
|
||||||
|
{
|
||||||
|
if (isStrong())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (auto p = std::get_if<std::weak_ptr<T>>(&combo_))
|
||||||
|
{
|
||||||
|
if (auto s = p->lock())
|
||||||
|
{
|
||||||
|
combo_ = std::move(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool
|
||||||
|
SharedWeakCachePointer<T>::convertToWeak()
|
||||||
|
{
|
||||||
|
if (isWeak())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
|
||||||
|
{
|
||||||
|
combo_ = std::weak_ptr<T>(*p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} // namespace ripple
|
||||||
|
#endif
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <xrpl/basics/contract.h>
|
#include <xrpl/basics/contract.h>
|
||||||
#include <xrpl/basics/strHex.h>
|
#include <xrpl/basics/strHex.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|||||||
@@ -20,11 +20,14 @@
|
|||||||
#ifndef RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
|
#ifndef RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
|
||||||
#define RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
|
#define RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
|
||||||
|
|
||||||
|
#include <xrpl/basics/IntrusivePointer.h>
|
||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
|
#include <xrpl/basics/SharedWeakCachePointer.ipp>
|
||||||
#include <xrpl/basics/UnorderedContainers.h>
|
#include <xrpl/basics/UnorderedContainers.h>
|
||||||
#include <xrpl/basics/hardened_hash.h>
|
#include <xrpl/basics/hardened_hash.h>
|
||||||
#include <xrpl/beast/clock/abstract_clock.h>
|
#include <xrpl/beast/clock/abstract_clock.h>
|
||||||
#include <xrpl/beast/insight/Insight.h>
|
#include <xrpl/beast/insight/Insight.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@@ -50,6 +53,8 @@ template <
|
|||||||
class Key,
|
class Key,
|
||||||
class T,
|
class T,
|
||||||
bool IsKeyCache = false,
|
bool IsKeyCache = false,
|
||||||
|
class SharedWeakUnionPointerType = SharedWeakCachePointer<T>,
|
||||||
|
class SharedPointerType = std::shared_ptr<T>,
|
||||||
class Hash = hardened_hash<>,
|
class Hash = hardened_hash<>,
|
||||||
class KeyEqual = std::equal_to<Key>,
|
class KeyEqual = std::equal_to<Key>,
|
||||||
class Mutex = std::recursive_mutex>
|
class Mutex = std::recursive_mutex>
|
||||||
@@ -60,6 +65,8 @@ public:
|
|||||||
using key_type = Key;
|
using key_type = Key;
|
||||||
using mapped_type = T;
|
using mapped_type = T;
|
||||||
using clock_type = beast::abstract_clock<std::chrono::steady_clock>;
|
using clock_type = beast::abstract_clock<std::chrono::steady_clock>;
|
||||||
|
using shared_weak_combo_pointer_type = SharedWeakUnionPointerType;
|
||||||
|
using shared_pointer_type = SharedPointerType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TaggedCache(
|
TaggedCache(
|
||||||
@@ -69,231 +76,48 @@ public:
|
|||||||
clock_type& clock,
|
clock_type& clock,
|
||||||
beast::Journal journal,
|
beast::Journal journal,
|
||||||
beast::insight::Collector::ptr const& collector =
|
beast::insight::Collector::ptr const& collector =
|
||||||
beast::insight::NullCollector::New())
|
beast::insight::NullCollector::New());
|
||||||
: m_journal(journal)
|
|
||||||
, m_clock(clock)
|
|
||||||
, m_stats(
|
|
||||||
name,
|
|
||||||
std::bind(&TaggedCache::collect_metrics, this),
|
|
||||||
collector)
|
|
||||||
, m_name(name)
|
|
||||||
, m_target_size(size)
|
|
||||||
, m_target_age(expiration)
|
|
||||||
, m_cache_count(0)
|
|
||||||
, m_hits(0)
|
|
||||||
, m_misses(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Return the clock associated with the cache. */
|
/** Return the clock associated with the cache. */
|
||||||
clock_type&
|
clock_type&
|
||||||
clock()
|
clock();
|
||||||
{
|
|
||||||
return m_clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the number of items in the container. */
|
/** Returns the number of items in the container. */
|
||||||
std::size_t
|
std::size_t
|
||||||
size() const
|
size() const;
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
return m_cache.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
setTargetSize(int s)
|
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
m_target_size = s;
|
|
||||||
|
|
||||||
if (s > 0)
|
|
||||||
{
|
|
||||||
for (auto& partition : m_cache.map())
|
|
||||||
{
|
|
||||||
partition.rehash(static_cast<std::size_t>(
|
|
||||||
(s + (s >> 2)) /
|
|
||||||
(partition.max_load_factor() * m_cache.partitions()) +
|
|
||||||
1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JLOG(m_journal.debug()) << m_name << " target size set to " << s;
|
|
||||||
}
|
|
||||||
|
|
||||||
clock_type::duration
|
|
||||||
getTargetAge() const
|
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
return m_target_age;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
setTargetAge(clock_type::duration s)
|
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
m_target_age = s;
|
|
||||||
JLOG(m_journal.debug())
|
|
||||||
<< m_name << " target age set to " << m_target_age.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
getCacheSize() const
|
getCacheSize() const;
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
return m_cache_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
getTrackSize() const
|
getTrackSize() const;
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
return m_cache.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
float
|
float
|
||||||
getHitRate()
|
getHitRate();
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
auto const total = static_cast<float>(m_hits + m_misses);
|
|
||||||
return m_hits * (100.0f / std::max(1.0f, total));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
clear()
|
clear();
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
m_cache.clear();
|
|
||||||
m_cache_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
reset()
|
reset();
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
m_cache.clear();
|
|
||||||
m_cache_count = 0;
|
|
||||||
m_hits = 0;
|
|
||||||
m_misses = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Refresh the last access time on a key if present.
|
/** Refresh the last access time on a key if present.
|
||||||
@return `true` If the key was found.
|
@return `true` If the key was found.
|
||||||
*/
|
*/
|
||||||
template <class KeyComparable>
|
template <class KeyComparable>
|
||||||
bool
|
bool
|
||||||
touch_if_exists(KeyComparable const& key)
|
touch_if_exists(KeyComparable const& key);
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
auto const iter(m_cache.find(key));
|
|
||||||
if (iter == m_cache.end())
|
|
||||||
{
|
|
||||||
++m_stats.misses;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
iter->second.touch(m_clock.now());
|
|
||||||
++m_stats.hits;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
using SweptPointersVector = std::pair<
|
using SweptPointersVector = std::vector<SharedWeakUnionPointerType>;
|
||||||
std::vector<std::shared_ptr<mapped_type>>,
|
|
||||||
std::vector<std::weak_ptr<mapped_type>>>;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
sweep()
|
sweep();
|
||||||
{
|
|
||||||
// Keep references to all the stuff we sweep
|
|
||||||
// For performance, each worker thread should exit before the swept data
|
|
||||||
// is destroyed but still within the main cache lock.
|
|
||||||
std::vector<SweptPointersVector> allStuffToSweep(m_cache.partitions());
|
|
||||||
|
|
||||||
clock_type::time_point const now(m_clock.now());
|
|
||||||
clock_type::time_point when_expire;
|
|
||||||
|
|
||||||
auto const start = std::chrono::steady_clock::now();
|
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
|
|
||||||
if (m_target_size == 0 ||
|
|
||||||
(static_cast<int>(m_cache.size()) <= m_target_size))
|
|
||||||
{
|
|
||||||
when_expire = now - m_target_age;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
when_expire =
|
|
||||||
now - m_target_age * m_target_size / m_cache.size();
|
|
||||||
|
|
||||||
clock_type::duration const minimumAge(std::chrono::seconds(1));
|
|
||||||
if (when_expire > (now - minimumAge))
|
|
||||||
when_expire = now - minimumAge;
|
|
||||||
|
|
||||||
JLOG(m_journal.trace())
|
|
||||||
<< m_name << " is growing fast " << m_cache.size() << " of "
|
|
||||||
<< m_target_size << " aging at "
|
|
||||||
<< (now - when_expire).count() << " of "
|
|
||||||
<< m_target_age.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::thread> workers;
|
|
||||||
workers.reserve(m_cache.partitions());
|
|
||||||
std::atomic<int> allRemovals = 0;
|
|
||||||
|
|
||||||
for (std::size_t p = 0; p < m_cache.partitions(); ++p)
|
|
||||||
{
|
|
||||||
workers.push_back(sweepHelper(
|
|
||||||
when_expire,
|
|
||||||
now,
|
|
||||||
m_cache.map()[p],
|
|
||||||
allStuffToSweep[p],
|
|
||||||
allRemovals,
|
|
||||||
lock));
|
|
||||||
}
|
|
||||||
for (std::thread& worker : workers)
|
|
||||||
worker.join();
|
|
||||||
|
|
||||||
m_cache_count -= allRemovals;
|
|
||||||
}
|
|
||||||
// At this point allStuffToSweep will go out of scope outside the lock
|
|
||||||
// and decrement the reference count on each strong pointer.
|
|
||||||
JLOG(m_journal.debug())
|
|
||||||
<< m_name << " TaggedCache sweep lock duration "
|
|
||||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
||||||
std::chrono::steady_clock::now() - start)
|
|
||||||
.count()
|
|
||||||
<< "ms";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
del(const key_type& key, bool valid)
|
del(key_type const& key, bool valid);
|
||||||
{
|
|
||||||
// Remove from cache, if !valid, remove from map too. Returns true if
|
|
||||||
// removed from cache
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
|
|
||||||
auto cit = m_cache.find(key);
|
|
||||||
|
|
||||||
if (cit == m_cache.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Entry& entry = cit->second;
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
if (entry.isCached())
|
|
||||||
{
|
|
||||||
--m_cache_count;
|
|
||||||
entry.ptr.reset();
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!valid || entry.isExpired())
|
|
||||||
m_cache.erase(cit);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public:
|
||||||
/** Replace aliased objects with originals.
|
/** Replace aliased objects with originals.
|
||||||
|
|
||||||
Due to concurrency it is possible for two separate objects with
|
Due to concurrency it is possible for two separate objects with
|
||||||
@@ -307,100 +131,23 @@ public:
|
|||||||
|
|
||||||
@return `true` If the key already existed.
|
@return `true` If the key already existed.
|
||||||
*/
|
*/
|
||||||
public:
|
template <class R>
|
||||||
bool
|
bool
|
||||||
canonicalize(
|
canonicalize(
|
||||||
const key_type& key,
|
key_type const& key,
|
||||||
std::shared_ptr<T>& data,
|
SharedPointerType& data,
|
||||||
std::function<bool(std::shared_ptr<T> const&)>&& replace)
|
R&& replaceCallback);
|
||||||
{
|
|
||||||
// Return canonical value, store if needed, refresh in cache
|
|
||||||
// Return values: true=we had the data already
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
|
|
||||||
auto cit = m_cache.find(key);
|
|
||||||
|
|
||||||
if (cit == m_cache.end())
|
|
||||||
{
|
|
||||||
m_cache.emplace(
|
|
||||||
std::piecewise_construct,
|
|
||||||
std::forward_as_tuple(key),
|
|
||||||
std::forward_as_tuple(m_clock.now(), data));
|
|
||||||
++m_cache_count;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Entry& entry = cit->second;
|
|
||||||
entry.touch(m_clock.now());
|
|
||||||
|
|
||||||
if (entry.isCached())
|
|
||||||
{
|
|
||||||
if (replace(entry.ptr))
|
|
||||||
{
|
|
||||||
entry.ptr = data;
|
|
||||||
entry.weak_ptr = data;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
data = entry.ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cachedData = entry.lock();
|
|
||||||
|
|
||||||
if (cachedData)
|
|
||||||
{
|
|
||||||
if (replace(entry.ptr))
|
|
||||||
{
|
|
||||||
entry.ptr = data;
|
|
||||||
entry.weak_ptr = data;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry.ptr = cachedData;
|
|
||||||
data = cachedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
++m_cache_count;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.ptr = data;
|
|
||||||
entry.weak_ptr = data;
|
|
||||||
++m_cache_count;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
canonicalize_replace_cache(
|
canonicalize_replace_cache(
|
||||||
const key_type& key,
|
key_type const& key,
|
||||||
std::shared_ptr<T> const& data)
|
SharedPointerType const& data);
|
||||||
{
|
|
||||||
return canonicalize(
|
|
||||||
key,
|
|
||||||
const_cast<std::shared_ptr<T>&>(data),
|
|
||||||
[](std::shared_ptr<T> const&) { return true; });
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
canonicalize_replace_client(const key_type& key, std::shared_ptr<T>& data)
|
canonicalize_replace_client(key_type const& key, SharedPointerType& data);
|
||||||
{
|
|
||||||
return canonicalize(
|
|
||||||
key, data, [](std::shared_ptr<T> const&) { return false; });
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<T>
|
SharedPointerType
|
||||||
fetch(const key_type& key)
|
fetch(key_type const& key);
|
||||||
{
|
|
||||||
std::lock_guard<mutex_type> l(m_mutex);
|
|
||||||
auto ret = initialFetch(key, l);
|
|
||||||
if (!ret)
|
|
||||||
++m_misses;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Insert the element into the container.
|
/** Insert the element into the container.
|
||||||
If the key already exists, nothing happens.
|
If the key already exists, nothing happens.
|
||||||
@@ -409,26 +156,11 @@ public:
|
|||||||
template <class ReturnType = bool>
|
template <class ReturnType = bool>
|
||||||
auto
|
auto
|
||||||
insert(key_type const& key, T const& value)
|
insert(key_type const& key, T const& value)
|
||||||
-> std::enable_if_t<!IsKeyCache, ReturnType>
|
-> std::enable_if_t<!IsKeyCache, ReturnType>;
|
||||||
{
|
|
||||||
auto p = std::make_shared<T>(std::cref(value));
|
|
||||||
return canonicalize_replace_client(key, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ReturnType = bool>
|
template <class ReturnType = bool>
|
||||||
auto
|
auto
|
||||||
insert(key_type const& key) -> std::enable_if_t<IsKeyCache, ReturnType>
|
insert(key_type const& key) -> std::enable_if_t<IsKeyCache, ReturnType>;
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
clock_type::time_point const now(m_clock.now());
|
|
||||||
auto [it, inserted] = m_cache.emplace(
|
|
||||||
std::piecewise_construct,
|
|
||||||
std::forward_as_tuple(key),
|
|
||||||
std::forward_as_tuple(now));
|
|
||||||
if (!inserted)
|
|
||||||
it->second.last_access = now;
|
|
||||||
return inserted;
|
|
||||||
}
|
|
||||||
|
|
||||||
// VFALCO NOTE It looks like this returns a copy of the data in
|
// VFALCO NOTE It looks like this returns a copy of the data in
|
||||||
// the output parameter 'data'. This could be expensive.
|
// the output parameter 'data'. This could be expensive.
|
||||||
@@ -436,50 +168,18 @@ public:
|
|||||||
// simply return an iterator.
|
// simply return an iterator.
|
||||||
//
|
//
|
||||||
bool
|
bool
|
||||||
retrieve(const key_type& key, T& data)
|
retrieve(key_type const& key, T& data);
|
||||||
{
|
|
||||||
// retrieve the value of the stored data
|
|
||||||
auto entry = fetch(key);
|
|
||||||
|
|
||||||
if (!entry)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
data = *entry;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_type&
|
mutex_type&
|
||||||
peekMutex()
|
peekMutex();
|
||||||
{
|
|
||||||
return m_mutex;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<key_type>
|
std::vector<key_type>
|
||||||
getKeys() const
|
getKeys() const;
|
||||||
{
|
|
||||||
std::vector<key_type> v;
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
v.reserve(m_cache.size());
|
|
||||||
for (auto const& _ : m_cache)
|
|
||||||
v.push_back(_.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CachedSLEs functions.
|
// CachedSLEs functions.
|
||||||
/** Returns the fraction of cache hits. */
|
/** Returns the fraction of cache hits. */
|
||||||
double
|
double
|
||||||
rate() const
|
rate() const;
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
auto const tot = m_hits + m_misses;
|
|
||||||
if (tot == 0)
|
|
||||||
return 0;
|
|
||||||
return double(m_hits) / tot;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Fetch an item from the cache.
|
/** Fetch an item from the cache.
|
||||||
If the digest was not found, Handler
|
If the digest was not found, Handler
|
||||||
@@ -487,73 +187,16 @@ public:
|
|||||||
std::shared_ptr<SLE const>(void)
|
std::shared_ptr<SLE const>(void)
|
||||||
*/
|
*/
|
||||||
template <class Handler>
|
template <class Handler>
|
||||||
std::shared_ptr<T>
|
SharedPointerType
|
||||||
fetch(key_type const& digest, Handler const& h)
|
fetch(key_type const& digest, Handler const& h);
|
||||||
{
|
|
||||||
{
|
|
||||||
std::lock_guard l(m_mutex);
|
|
||||||
if (auto ret = initialFetch(digest, l))
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sle = h();
|
|
||||||
if (!sle)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::lock_guard l(m_mutex);
|
|
||||||
++m_misses;
|
|
||||||
auto const [it, inserted] =
|
|
||||||
m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle)));
|
|
||||||
if (!inserted)
|
|
||||||
it->second.touch(m_clock.now());
|
|
||||||
return it->second.ptr;
|
|
||||||
}
|
|
||||||
// End CachedSLEs functions.
|
// End CachedSLEs functions.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<T>
|
SharedPointerType
|
||||||
initialFetch(key_type const& key, std::lock_guard<mutex_type> const& l)
|
initialFetch(key_type const& key, std::lock_guard<mutex_type> const& l);
|
||||||
{
|
|
||||||
auto cit = m_cache.find(key);
|
|
||||||
if (cit == m_cache.end())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
Entry& entry = cit->second;
|
|
||||||
if (entry.isCached())
|
|
||||||
{
|
|
||||||
++m_hits;
|
|
||||||
entry.touch(m_clock.now());
|
|
||||||
return entry.ptr;
|
|
||||||
}
|
|
||||||
entry.ptr = entry.lock();
|
|
||||||
if (entry.isCached())
|
|
||||||
{
|
|
||||||
// independent of cache size, so not counted as a hit
|
|
||||||
++m_cache_count;
|
|
||||||
entry.touch(m_clock.now());
|
|
||||||
return entry.ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_cache.erase(cit);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
collect_metrics()
|
collect_metrics();
|
||||||
{
|
|
||||||
m_stats.size.set(getCacheSize());
|
|
||||||
|
|
||||||
{
|
|
||||||
beast::insight::Gauge::value_type hit_rate(0);
|
|
||||||
{
|
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
auto const total(m_hits + m_misses);
|
|
||||||
if (total != 0)
|
|
||||||
hit_rate = (m_hits * 100) / total;
|
|
||||||
}
|
|
||||||
m_stats.hit_rate.set(hit_rate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Stats
|
struct Stats
|
||||||
@@ -599,36 +242,37 @@ private:
|
|||||||
class ValueEntry
|
class ValueEntry
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<mapped_type> ptr;
|
shared_weak_combo_pointer_type ptr;
|
||||||
std::weak_ptr<mapped_type> weak_ptr;
|
|
||||||
clock_type::time_point last_access;
|
clock_type::time_point last_access;
|
||||||
|
|
||||||
ValueEntry(
|
ValueEntry(
|
||||||
clock_type::time_point const& last_access_,
|
clock_type::time_point const& last_access_,
|
||||||
std::shared_ptr<mapped_type> const& ptr_)
|
shared_pointer_type const& ptr_)
|
||||||
: ptr(ptr_), weak_ptr(ptr_), last_access(last_access_)
|
: ptr(ptr_), last_access(last_access_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
isWeak() const
|
isWeak() const
|
||||||
{
|
{
|
||||||
return ptr == nullptr;
|
if (!ptr)
|
||||||
|
return true;
|
||||||
|
return ptr.isWeak();
|
||||||
}
|
}
|
||||||
bool
|
bool
|
||||||
isCached() const
|
isCached() const
|
||||||
{
|
{
|
||||||
return ptr != nullptr;
|
return ptr && ptr.isStrong();
|
||||||
}
|
}
|
||||||
bool
|
bool
|
||||||
isExpired() const
|
isExpired() const
|
||||||
{
|
{
|
||||||
return weak_ptr.expired();
|
return ptr.expired();
|
||||||
}
|
}
|
||||||
std::shared_ptr<mapped_type>
|
SharedPointerType
|
||||||
lock()
|
lock()
|
||||||
{
|
{
|
||||||
return weak_ptr.lock();
|
return ptr.lock();
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
touch(clock_type::time_point const& now)
|
touch(clock_type::time_point const& now)
|
||||||
@@ -657,72 +301,7 @@ private:
|
|||||||
typename KeyValueCacheType::map_type& partition,
|
typename KeyValueCacheType::map_type& partition,
|
||||||
SweptPointersVector& stuffToSweep,
|
SweptPointersVector& stuffToSweep,
|
||||||
std::atomic<int>& allRemovals,
|
std::atomic<int>& allRemovals,
|
||||||
std::lock_guard<std::recursive_mutex> const&)
|
std::lock_guard<std::recursive_mutex> const&);
|
||||||
{
|
|
||||||
return std::thread([&, this]() {
|
|
||||||
int cacheRemovals = 0;
|
|
||||||
int mapRemovals = 0;
|
|
||||||
|
|
||||||
// Keep references to all the stuff we sweep
|
|
||||||
// so that we can destroy them outside the lock.
|
|
||||||
stuffToSweep.first.reserve(partition.size());
|
|
||||||
stuffToSweep.second.reserve(partition.size());
|
|
||||||
{
|
|
||||||
auto cit = partition.begin();
|
|
||||||
while (cit != partition.end())
|
|
||||||
{
|
|
||||||
if (cit->second.isWeak())
|
|
||||||
{
|
|
||||||
// weak
|
|
||||||
if (cit->second.isExpired())
|
|
||||||
{
|
|
||||||
stuffToSweep.second.push_back(
|
|
||||||
std::move(cit->second.weak_ptr));
|
|
||||||
++mapRemovals;
|
|
||||||
cit = partition.erase(cit);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++cit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cit->second.last_access <= when_expire)
|
|
||||||
{
|
|
||||||
// strong, expired
|
|
||||||
++cacheRemovals;
|
|
||||||
if (cit->second.ptr.use_count() == 1)
|
|
||||||
{
|
|
||||||
stuffToSweep.first.push_back(
|
|
||||||
std::move(cit->second.ptr));
|
|
||||||
++mapRemovals;
|
|
||||||
cit = partition.erase(cit);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// remains weakly cached
|
|
||||||
cit->second.ptr.reset();
|
|
||||||
++cit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// strong, not expired
|
|
||||||
++cit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapRemovals || cacheRemovals)
|
|
||||||
{
|
|
||||||
JLOG(m_journal.debug())
|
|
||||||
<< "TaggedCache partition sweep " << m_name
|
|
||||||
<< ": cache = " << partition.size() << "-" << cacheRemovals
|
|
||||||
<< ", map-=" << mapRemovals;
|
|
||||||
}
|
|
||||||
|
|
||||||
allRemovals += cacheRemovals;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::thread
|
[[nodiscard]] std::thread
|
||||||
sweepHelper(
|
sweepHelper(
|
||||||
@@ -731,45 +310,7 @@ private:
|
|||||||
typename KeyOnlyCacheType::map_type& partition,
|
typename KeyOnlyCacheType::map_type& partition,
|
||||||
SweptPointersVector&,
|
SweptPointersVector&,
|
||||||
std::atomic<int>& allRemovals,
|
std::atomic<int>& allRemovals,
|
||||||
std::lock_guard<std::recursive_mutex> const&)
|
std::lock_guard<std::recursive_mutex> const&);
|
||||||
{
|
|
||||||
return std::thread([&, this]() {
|
|
||||||
int cacheRemovals = 0;
|
|
||||||
int mapRemovals = 0;
|
|
||||||
|
|
||||||
// Keep references to all the stuff we sweep
|
|
||||||
// so that we can destroy them outside the lock.
|
|
||||||
{
|
|
||||||
auto cit = partition.begin();
|
|
||||||
while (cit != partition.end())
|
|
||||||
{
|
|
||||||
if (cit->second.last_access > now)
|
|
||||||
{
|
|
||||||
cit->second.last_access = now;
|
|
||||||
++cit;
|
|
||||||
}
|
|
||||||
else if (cit->second.last_access <= when_expire)
|
|
||||||
{
|
|
||||||
cit = partition.erase(cit);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++cit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapRemovals || cacheRemovals)
|
|
||||||
{
|
|
||||||
JLOG(m_journal.debug())
|
|
||||||
<< "TaggedCache partition sweep " << m_name
|
|
||||||
<< ": cache = " << partition.size() << "-" << cacheRemovals
|
|
||||||
<< ", map-=" << mapRemovals;
|
|
||||||
}
|
|
||||||
|
|
||||||
allRemovals += cacheRemovals;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
beast::Journal m_journal;
|
beast::Journal m_journal;
|
||||||
clock_type& m_clock;
|
clock_type& m_clock;
|
||||||
@@ -781,10 +322,10 @@ private:
|
|||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
|
||||||
// Desired number of cache entries (0 = ignore)
|
// Desired number of cache entries (0 = ignore)
|
||||||
int m_target_size;
|
int const m_target_size;
|
||||||
|
|
||||||
// Desired maximum cache age
|
// Desired maximum cache age
|
||||||
clock_type::duration m_target_age;
|
clock_type::duration const m_target_age;
|
||||||
|
|
||||||
// Number of items cached
|
// Number of items cached
|
||||||
int m_cache_count;
|
int m_cache_count;
|
||||||
|
|||||||
1029
include/xrpl/basics/TaggedCache.ipp
Normal file
1029
include/xrpl/basics/TaggedCache.ipp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@
|
|||||||
#include <xrpl/beast/hash/hash_append.h>
|
#include <xrpl/beast/hash/hash_append.h>
|
||||||
#include <xrpl/beast/hash/uhash.h>
|
#include <xrpl/beast/hash/uhash.h>
|
||||||
#include <xrpl/beast/hash/xxhasher.h>
|
#include <xrpl/beast/hash/xxhasher.h>
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#ifndef RIPPLE_ALGORITHM_H_INCLUDED
|
#ifndef RIPPLE_ALGORITHM_H_INCLUDED
|
||||||
#define RIPPLE_ALGORITHM_H_INCLUDED
|
#define RIPPLE_ALGORITHM_H_INCLUDED
|
||||||
|
|
||||||
#include <iterator>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|||||||
@@ -33,12 +33,13 @@
|
|||||||
#include <xrpl/basics/strHex.h>
|
#include <xrpl/basics/strHex.h>
|
||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
|
||||||
#include <boost/endian/conversion.hpp>
|
#include <boost/endian/conversion.hpp>
|
||||||
#include <boost/functional/hash.hpp>
|
#include <boost/functional/hash.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -385,7 +386,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
base_uint&
|
base_uint&
|
||||||
operator^=(const base_uint& b)
|
operator^=(base_uint const& b)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < WIDTH; i++)
|
for (int i = 0; i < WIDTH; i++)
|
||||||
data_[i] ^= b.data_[i];
|
data_[i] ^= b.data_[i];
|
||||||
@@ -394,7 +395,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
base_uint&
|
base_uint&
|
||||||
operator&=(const base_uint& b)
|
operator&=(base_uint const& b)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < WIDTH; i++)
|
for (int i = 0; i < WIDTH; i++)
|
||||||
data_[i] &= b.data_[i];
|
data_[i] &= b.data_[i];
|
||||||
@@ -403,7 +404,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
base_uint&
|
base_uint&
|
||||||
operator|=(const base_uint& b)
|
operator|=(base_uint const& b)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < WIDTH; i++)
|
for (int i = 0; i < WIDTH; i++)
|
||||||
data_[i] |= b.data_[i];
|
data_[i] |= b.data_[i];
|
||||||
@@ -426,11 +427,11 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const base_uint
|
base_uint const
|
||||||
operator++(int)
|
operator++(int)
|
||||||
{
|
{
|
||||||
// postfix operator
|
// postfix operator
|
||||||
const base_uint ret = *this;
|
base_uint const ret = *this;
|
||||||
++(*this);
|
++(*this);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -452,11 +453,11 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const base_uint
|
base_uint const
|
||||||
operator--(int)
|
operator--(int)
|
||||||
{
|
{
|
||||||
// postfix operator
|
// postfix operator
|
||||||
const base_uint ret = *this;
|
base_uint const ret = *this;
|
||||||
--(*this);
|
--(*this);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -477,7 +478,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
base_uint&
|
base_uint&
|
||||||
operator+=(const base_uint& b)
|
operator+=(base_uint const& b)
|
||||||
{
|
{
|
||||||
std::uint64_t carry = 0;
|
std::uint64_t carry = 0;
|
||||||
|
|
||||||
@@ -522,7 +523,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool
|
[[nodiscard]] constexpr bool
|
||||||
parseHex(const char* str)
|
parseHex(char const* str)
|
||||||
{
|
{
|
||||||
return parseHex(std::string_view{str});
|
return parseHex(std::string_view{str});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,17 +20,16 @@
|
|||||||
#ifndef RIPPLE_BASICS_CHRONO_H_INCLUDED
|
#ifndef RIPPLE_BASICS_CHRONO_H_INCLUDED
|
||||||
#define RIPPLE_BASICS_CHRONO_H_INCLUDED
|
#define RIPPLE_BASICS_CHRONO_H_INCLUDED
|
||||||
|
|
||||||
#include <date/date.h>
|
|
||||||
|
|
||||||
#include <xrpl/beast/clock/abstract_clock.h>
|
#include <xrpl/beast/clock/abstract_clock.h>
|
||||||
#include <xrpl/beast/clock/basic_seconds_clock.h>
|
#include <xrpl/beast/clock/basic_seconds_clock.h>
|
||||||
#include <xrpl/beast/clock/manual_clock.h>
|
#include <xrpl/beast/clock/manual_clock.h>
|
||||||
|
|
||||||
|
#include <date/date.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <ratio>
|
#include <ratio>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ struct less
|
|||||||
using result_type = bool;
|
using result_type = bool;
|
||||||
|
|
||||||
constexpr bool
|
constexpr bool
|
||||||
operator()(const T& left, const T& right) const
|
operator()(T const& left, T const& right) const
|
||||||
{
|
{
|
||||||
return std::less<T>()(left, right);
|
return std::less<T>()(left, right);
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ struct equal_to
|
|||||||
using result_type = bool;
|
using result_type = bool;
|
||||||
|
|
||||||
constexpr bool
|
constexpr bool
|
||||||
operator()(const T& left, const T& right) const
|
operator()(T const& left, T const& right) const
|
||||||
{
|
{
|
||||||
return std::equal_to<T>()(left, right);
|
return std::equal_to<T>()(left, right);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,9 @@
|
|||||||
#define RIPPLE_BASICS_CONTRACT_H_INCLUDED
|
#define RIPPLE_BASICS_CONTRACT_H_INCLUDED
|
||||||
|
|
||||||
#include <xrpl/beast/type_name.h>
|
#include <xrpl/beast/type_name.h>
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <typeinfo>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|||||||
@@ -24,12 +24,8 @@
|
|||||||
#include <xrpl/beast/hash/xxhasher.h>
|
#include <xrpl/beast/hash/xxhasher.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <functional>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <type_traits>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#define RIPPLE_BASICS_MAKE_SSLCONTEXT_H_INCLUDED
|
#define RIPPLE_BASICS_MAKE_SSLCONTEXT_H_INCLUDED
|
||||||
|
|
||||||
#include <boost/asio/ssl/context.hpp>
|
#include <boost/asio/ssl/context.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
auto constexpr muldiv_max = std::numeric_limits<std::uint64_t>::max();
|
auto constexpr muldiv_max = std::numeric_limits<std::uint64_t>::max();
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <xrpl/beast/hash/uhash.h>
|
#include <xrpl/beast/hash/uhash.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -51,7 +52,7 @@ template <
|
|||||||
typename Value,
|
typename Value,
|
||||||
typename Hash,
|
typename Hash,
|
||||||
typename Pred = std::equal_to<Key>,
|
typename Pred = std::equal_to<Key>,
|
||||||
typename Alloc = std::allocator<std::pair<const Key, Value>>>
|
typename Alloc = std::allocator<std::pair<Key const, Value>>>
|
||||||
class partitioned_unordered_map
|
class partitioned_unordered_map
|
||||||
{
|
{
|
||||||
std::size_t partitions_;
|
std::size_t partitions_;
|
||||||
|
|||||||
@@ -22,9 +22,9 @@
|
|||||||
|
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/beast/xor_shift_engine.h>
|
#include <xrpl/beast/xor_shift_engine.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#define RIPPLE_BASICS_SPINLOCK_H_INCLUDED
|
#define RIPPLE_BASICS_SPINLOCK_H_INCLUDED
|
||||||
|
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|||||||
@@ -21,11 +21,11 @@
|
|||||||
#define BEAST_UTILITY_TAGGED_INTEGER_H_INCLUDED
|
#define BEAST_UTILITY_TAGGED_INTEGER_H_INCLUDED
|
||||||
|
|
||||||
#include <xrpl/beast/hash/hash_append.h>
|
#include <xrpl/beast/hash/hash_append.h>
|
||||||
|
|
||||||
#include <boost/operators.hpp>
|
#include <boost/operators.hpp>
|
||||||
#include <functional>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
@@ -74,13 +74,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
operator<(const tagged_integer& rhs) const noexcept
|
operator<(tagged_integer const& rhs) const noexcept
|
||||||
{
|
{
|
||||||
return m_value < rhs.m_value;
|
return m_value < rhs.m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
operator==(const tagged_integer& rhs) const noexcept
|
operator==(tagged_integer const& rhs) const noexcept
|
||||||
{
|
{
|
||||||
return m_value == rhs.m_value;
|
return m_value == rhs.m_value;
|
||||||
}
|
}
|
||||||
@@ -142,14 +142,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
tagged_integer&
|
tagged_integer&
|
||||||
operator<<=(const tagged_integer& rhs) noexcept
|
operator<<=(tagged_integer const& rhs) noexcept
|
||||||
{
|
{
|
||||||
m_value <<= rhs.m_value;
|
m_value <<= rhs.m_value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
tagged_integer&
|
tagged_integer&
|
||||||
operator>>=(const tagged_integer& rhs) noexcept
|
operator>>=(tagged_integer const& rhs) noexcept
|
||||||
{
|
{
|
||||||
m_value >>= rhs.m_value;
|
m_value >>= rhs.m_value;
|
||||||
return *this;
|
return *this;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#define BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED
|
#define BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED
|
||||||
|
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
|
||||||
#include <boost/asio/basic_waitable_timer.hpp>
|
#include <boost/asio/basic_waitable_timer.hpp>
|
||||||
#include <boost/asio/io_service.hpp>
|
#include <boost/asio/io_service.hpp>
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,6 @@
|
|||||||
#ifndef BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED
|
#ifndef BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED
|
||||||
#define BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED
|
#define BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
/** Abstract interface to a clock.
|
/** Abstract interface to a clock.
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
#include <xrpl/beast/clock/abstract_clock.h>
|
#include <xrpl/beast/clock/abstract_clock.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
/** Manual clock implementation.
|
/** Manual clock implementation.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user